diff --git a/config/alfresco/dao/dao-context.xml b/config/alfresco/dao/dao-context.xml index f5c51d85cf..efdd5a501f 100644 --- a/config/alfresco/dao/dao-context.xml +++ b/config/alfresco/dao/dao-context.xml @@ -23,6 +23,12 @@ + + + + + + diff --git a/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-3.3-RepoTables.sql b/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-3.3-RepoTables.sql index c3de4f3526..977992bcee 100644 --- a/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-3.3-RepoTables.sql +++ b/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-3.3-RepoTables.sql @@ -22,3 +22,23 @@ CREATE TABLE alf_applied_patch report TEXT, PRIMARY KEY (id) ) ENGINE=InnoDB; + +CREATE TABLE alf_namespace +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + uri VARCHAR(100) NOT NULL, + UNIQUE (uri), + PRIMARY KEY (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_qname +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + ns_id BIGINT NOT NULL, + local_name VARCHAR(200) NOT NULL, + CONSTRAINT FOREIGN KEY fk_alf_qname_ns (ns_id) REFERENCES alf_namespace (id), + UNIQUE (ns_id, local_name), + PRIMARY KEY (id) +) ENGINE=InnoDB; diff --git a/config/alfresco/ehcache-default.xml b/config/alfresco/ehcache-default.xml index 926ebafbd9..c4ae897a36 100644 --- a/config/alfresco/ehcache-default.xml +++ b/config/alfresco/ehcache-default.xml @@ -35,13 +35,6 @@ eternal="true" overflowToDisk="false" /> - - - - - - - org/alfresco/repo/domain/hibernate/Locale.hbm.xml - org/alfresco/repo/domain/hibernate/QName.hbm.xml org/alfresco/repo/domain/hibernate/Node.hbm.xml org/alfresco/repo/domain/hibernate/Transaction.hbm.xml org/alfresco/repo/domain/hibernate/VersionCount.hbm.xml @@ -167,8 +166,6 @@ - ${cache.strategy} - ${cache.strategy} ${cache.strategy} ${cache.strategy} ${cache.strategy} @@ -209,19 +206,6 @@ - - - - - - - - - - - - - diff --git a/config/alfresco/ibatis/alfresco-SqlMapConfig.xml b/config/alfresco/ibatis/alfresco-SqlMapConfig.xml index 3cd9df29be..16f7a4e0e4 100644 --- a/config/alfresco/ibatis/alfresco-SqlMapConfig.xml +++ b/config/alfresco/ibatis/alfresco-SqlMapConfig.xml @@ -11,6 +11,8 @@ + + diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/qname-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/qname-common-SqlMap.xml new file mode 100644 index 0000000000..501c9dfd07 --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/qname-common-SqlMap.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + insert into alf_namespace (version, uri) + values (#version#, #uri#) + + + + insert into alf_namespace (id, version, uri) + values (#id#, #version#, #uri#) + + + + insert into alf_qname (version, ns_id, local_name) + values (#version#, #namespaceId#, #localName#) + + + + insert into alf_qname (id, version, ns_id, local_name) + values (#id#, #version#, #namespaceId#, #localName#) + + + + + + + + + + + + update + alf_namespace + set + uri = #uri# + where + id = #id# + + + + + + + + update + alf_qname + set + ns_id = #namespaceId#, + local_name = #localName# + where + id = #id# + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/qname-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/qname-insert-SqlMap.xml new file mode 100644 index 0000000000..223131fe67 --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/qname-insert-SqlMap.xml @@ -0,0 +1,23 @@ + + + + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + \ No newline at end of file diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index 78cb8993a1..41d3e6d886 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -1982,9 +1982,6 @@ - - - diff --git a/source/java/org/alfresco/repo/admin/patch/impl/AbstractPermissionChangePatch.java b/source/java/org/alfresco/repo/admin/patch/impl/AbstractPermissionChangePatch.java index c1aece6ac5..33c91c24af 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/AbstractPermissionChangePatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/AbstractPermissionChangePatch.java @@ -26,8 +26,8 @@ package org.alfresco.repo.admin.patch.impl; import org.alfresco.repo.admin.patch.AbstractPatch; import org.alfresco.repo.domain.DbPermission; -import org.alfresco.repo.domain.QNameDAO; import org.alfresco.repo.domain.hibernate.DbPermissionImpl; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.service.namespace.QName; import org.hibernate.Query; import org.hibernate.Session; diff --git a/source/java/org/alfresco/repo/admin/patch/impl/CalendarModelUriPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/CalendarModelUriPatch.java index 7eb9242645..a727e13620 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/CalendarModelUriPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/CalendarModelUriPatch.java @@ -25,9 +25,8 @@ package org.alfresco.repo.admin.patch.impl; -import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.repo.admin.patch.AbstractPatch; -import org.alfresco.repo.domain.QNameDAO; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.importer.ImporterBootstrap; import org.alfresco.repo.search.Indexer; import org.alfresco.repo.search.IndexerAndSearcher; @@ -37,6 +36,7 @@ import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.ResultSetRow; import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchService; +import org.springframework.extensions.surf.util.I18NUtil; /** * Patch usr:user and cm:person objects so that the user name properties are in the diff --git a/source/java/org/alfresco/repo/admin/patch/impl/FixNameCrcValuesPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/FixNameCrcValuesPatch.java index 3ee18287f9..1646f101c5 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/FixNameCrcValuesPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/FixNameCrcValuesPatch.java @@ -35,15 +35,14 @@ import java.util.Date; import java.util.List; import java.util.zip.CRC32; -import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.model.ContentModel; import org.alfresco.repo.admin.patch.AbstractPatch; import org.alfresco.repo.batch.BatchProcessor; import org.alfresco.repo.batch.BatchProcessor.Worker; import org.alfresco.repo.domain.ChildAssoc; import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.QNameDAO; import org.alfresco.repo.domain.hibernate.ChildAssocImpl; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.service.cmr.admin.PatchException; import org.alfresco.service.cmr.rule.RuleService; @@ -57,6 +56,7 @@ import org.hibernate.type.LongType; import org.hibernate.type.StringType; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.extensions.surf.util.I18NUtil; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; diff --git a/source/java/org/alfresco/repo/admin/patch/impl/ResetWCMToGroupBasedPermissionsPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/ResetWCMToGroupBasedPermissionsPatch.java index 2a9b7aa771..f254eb6451 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/ResetWCMToGroupBasedPermissionsPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/ResetWCMToGroupBasedPermissionsPatch.java @@ -43,7 +43,7 @@ import org.alfresco.repo.domain.DbAccessControlListChangeSet; import org.alfresco.repo.domain.DbAuthority; import org.alfresco.repo.domain.DbPermission; import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.QNameDAO; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.domain.hibernate.DbAccessControlEntryImpl; import org.alfresco.repo.domain.hibernate.DbAccessControlListChangeSetImpl; import org.alfresco.repo.domain.hibernate.DbAccessControlListImpl; diff --git a/source/java/org/alfresco/repo/avm/AVMRepository.java b/source/java/org/alfresco/repo/avm/AVMRepository.java index e3b30f2d5a..23654a02d2 100644 --- a/source/java/org/alfresco/repo/avm/AVMRepository.java +++ b/source/java/org/alfresco/repo/avm/AVMRepository.java @@ -39,8 +39,8 @@ import org.alfresco.repo.avm.util.AVMUtil; import org.alfresco.repo.content.ContentStore; import org.alfresco.repo.domain.DbAccessControlList; import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.QNameDAO; import org.alfresco.repo.domain.avm.AVMStoreEntity; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.security.permissions.ACLCopyMode; import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; @@ -62,10 +62,10 @@ import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.PermissionContext; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; -import org.alfresco.util.FileNameValidator; -import org.springframework.extensions.surf.util.Pair; +import org.alfresco.util.FileNameValidator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.Pair; /** * This or AVMStore are the implementors of the operations specified by AVMService. diff --git a/source/java/org/alfresco/repo/avm/ibatis/AVMStorePropertyDAOIbatis.java b/source/java/org/alfresco/repo/avm/ibatis/AVMStorePropertyDAOIbatis.java index 77e25b183a..78722402e3 100644 --- a/source/java/org/alfresco/repo/avm/ibatis/AVMStorePropertyDAOIbatis.java +++ b/source/java/org/alfresco/repo/avm/ibatis/AVMStorePropertyDAOIbatis.java @@ -34,7 +34,7 @@ import org.alfresco.repo.avm.AVMStoreProperty; import org.alfresco.repo.avm.AVMStorePropertyDAO; import org.alfresco.repo.avm.AVMStorePropertyImpl; import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.QNameDAO; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.domain.avm.AVMStorePropertyEntity; import org.alfresco.service.namespace.QName; import org.springframework.extensions.surf.util.Pair; diff --git a/source/java/org/alfresco/repo/domain/ChildAssoc.java b/source/java/org/alfresco/repo/domain/ChildAssoc.java index 36604a0d1e..15f79ef697 100644 --- a/source/java/org/alfresco/repo/domain/ChildAssoc.java +++ b/source/java/org/alfresco/repo/domain/ChildAssoc.java @@ -24,6 +24,7 @@ */ package org.alfresco.repo.domain; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.namespace.QName; diff --git a/source/java/org/alfresco/repo/domain/DbPermission.java b/source/java/org/alfresco/repo/domain/DbPermission.java index 076b447fb0..7678608115 100644 --- a/source/java/org/alfresco/repo/domain/DbPermission.java +++ b/source/java/org/alfresco/repo/domain/DbPermission.java @@ -26,6 +26,7 @@ package org.alfresco.repo.domain; import java.io.Serializable; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.service.namespace.QName; /** diff --git a/source/java/org/alfresco/repo/domain/DomainTestSuite.java b/source/java/org/alfresco/repo/domain/DomainTestSuite.java index 0ab5cf248c..eeabacc751 100644 --- a/source/java/org/alfresco/repo/domain/DomainTestSuite.java +++ b/source/java/org/alfresco/repo/domain/DomainTestSuite.java @@ -30,11 +30,11 @@ import junit.framework.TestSuite; import org.alfresco.repo.domain.audit.AuditDAOTest; import org.alfresco.repo.domain.contentdata.ContentDataDAOTest; import org.alfresco.repo.domain.encoding.EncodingDAOTest; -import org.alfresco.repo.domain.hibernate.HibernateSessionHelperTest; import org.alfresco.repo.domain.locks.LockDAOTest; import org.alfresco.repo.domain.mimetype.MimetypeDAOTest; import org.alfresco.repo.domain.patch.AppliedPatchDAOTest; import org.alfresco.repo.domain.propval.PropertyValueDAOTest; +import org.alfresco.repo.domain.qname.QNameDAOTest; /** * Suite for domain-related tests. @@ -49,7 +49,6 @@ public class DomainTestSuite extends TestSuite suite.addTestSuite(ContentDataDAOTest.class); suite.addTestSuite(EncodingDAOTest.class); - suite.addTestSuite(HibernateSessionHelperTest.class); suite.addTestSuite(LockDAOTest.class); suite.addTestSuite(MimetypeDAOTest.class); suite.addTestSuite(LocaleDAOTest.class); diff --git a/source/java/org/alfresco/repo/domain/LocaleDAOTest.java b/source/java/org/alfresco/repo/domain/LocaleDAOTest.java index 8ccb464fb6..7ed26b066e 100644 --- a/source/java/org/alfresco/repo/domain/LocaleDAOTest.java +++ b/source/java/org/alfresco/repo/domain/LocaleDAOTest.java @@ -52,7 +52,7 @@ import org.springframework.context.ApplicationContext; */ public class LocaleDAOTest extends TestCase { - private static Log logger = LogFactory.getLog(QNameDAOTest.class); + private static Log logger = LogFactory.getLog(LocaleDAOTest.class); private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); diff --git a/source/java/org/alfresco/repo/domain/NamespaceEntity.java b/source/java/org/alfresco/repo/domain/NamespaceEntity.java deleted file mode 100644 index 041a4a3d97..0000000000 --- a/source/java/org/alfresco/repo/domain/NamespaceEntity.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.domain; - -/** - * Represents a persistable Namespace entity. - * - * @author Derek Hulley - * @since 2.2 - */ -public interface NamespaceEntity -{ - Long getId(); - - String getUri(); - - void setUri(String namespaceUrl); -} diff --git a/source/java/org/alfresco/repo/domain/Node.java b/source/java/org/alfresco/repo/domain/Node.java index e1279a524a..3e4031f06e 100644 --- a/source/java/org/alfresco/repo/domain/Node.java +++ b/source/java/org/alfresco/repo/domain/Node.java @@ -27,6 +27,7 @@ package org.alfresco.repo.domain; import java.util.Map; import java.util.Set; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; diff --git a/source/java/org/alfresco/repo/domain/NodeAssoc.java b/source/java/org/alfresco/repo/domain/NodeAssoc.java index cfaf6c1663..11fe75ae16 100644 --- a/source/java/org/alfresco/repo/domain/NodeAssoc.java +++ b/source/java/org/alfresco/repo/domain/NodeAssoc.java @@ -24,6 +24,7 @@ */ package org.alfresco.repo.domain; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.namespace.QName; diff --git a/source/java/org/alfresco/repo/domain/QNameDAOTest.java b/source/java/org/alfresco/repo/domain/QNameDAOTest.java deleted file mode 100644 index 784c9e9e89..0000000000 --- a/source/java/org/alfresco/repo/domain/QNameDAOTest.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.domain; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import junit.framework.TestCase; - -import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.ServiceRegistry; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.ApplicationContextHelper; -import org.alfresco.util.GUID; -import org.springframework.extensions.surf.util.Pair; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.context.ApplicationContext; - -/** - * @see QNameDAO - * - * - * @author Derek Hulley - * @since 2.2 - */ -public class QNameDAOTest extends TestCase -{ - private static Log logger = LogFactory.getLog(QNameDAOTest.class); - - private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); - - private RetryingTransactionHelper retryingTransactionHelper; - private QNameDAO dao; - - @Override - public void setUp() throws Exception - { - ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); - retryingTransactionHelper = serviceRegistry.getTransactionService().getRetryingTransactionHelper(); - dao = (QNameDAO) ctx.getBean("qnameDAO"); - } - - @Override - public void tearDown() throws Exception - { - - } - - public void testNewNamespace() throws Exception - { - final String namespaceUri = GUID.generate(); - RetryingTransactionCallback> callback = new RetryingTransactionCallback>() - { - public Pair execute() throws Throwable - { - Pair namespacePair = dao.getNamespace(namespaceUri); - assertNull("Namespace should not exist yet", namespacePair); - // Now make it - namespacePair = dao.newNamespace(namespaceUri); - assertNotNull("Namespace should now exist", dao.getNamespace(namespaceUri)); - // Done - return namespacePair; - } - }; - retryingTransactionHelper.doInTransaction(callback); - } - - public void testRenameNamespace() throws Exception - { - final String namespaceUriBefore = GUID.generate(); - final QName qnameBefore = QName.createQName(namespaceUriBefore, "before"); - final String namespaceUriAfter = GUID.generate(); - final QName qnameAfter = QName.createQName(namespaceUriAfter, "before"); - RetryingTransactionCallback callback = new RetryingTransactionCallback() - { - public Object execute() throws Throwable - { - dao.getOrCreateNamespace(namespaceUriBefore); - // Get a QName that has the URI - Long qnameIdBefore = dao.getOrCreateQName(qnameBefore).getFirst(); - // Now modify the namespace - dao.updateNamespace(namespaceUriBefore, namespaceUriAfter); - // The old qname must be gone - assertNull("QName must be gone as the URI was renamed", dao.getQName(qnameBefore)); - // The new QName must be present and with the same ID - Pair qnamePairAfter = dao.getQName(qnameAfter); - assertNotNull("Expected QName with new URI to exist.", qnamePairAfter); - assertEquals("QName changed ID unexpectedly.", qnameIdBefore, qnamePairAfter.getFirst()); - // Done - return null; - } - }; - retryingTransactionHelper.doInTransaction(callback); - } - - public void testNewQName() throws Exception - { - final String namespaceUri = GUID.generate(); - final String localName = GUID.generate(); - final QName qname = QName.createQName(namespaceUri, localName); - RetryingTransactionCallback> callback = new RetryingTransactionCallback>() - { - public Pair execute() throws Throwable - { - Pair qnamePair = dao.getQName(qname); - assertNull("QName should not exist yet", qnamePair); - // Now make it - qnamePair = dao.newQName(qname); - assertNotNull("QName should now exist", dao.getQName(qname)); - // Done - return qnamePair; - } - }; - retryingTransactionHelper.doInTransaction(callback); - } - - public void testGetQNameManyTimes() throws Exception - { - final String namespaceUri = GUID.generate(); - final String localName = GUID.generate(); - final QName qname = QName.createQName(namespaceUri, localName); - RetryingTransactionCallback> callback = new RetryingTransactionCallback>() - { - public Pair execute() throws Throwable - { - Pair qnamePair = dao.getQName(qname); - assertNull("QName should not exist yet", qnamePair); - // Now make it - qnamePair = dao.newQName(qname); - assertNotNull("QName should now exist", dao.getQName(qname)); - // Done - return qnamePair; - } - }; - retryingTransactionHelper.doInTransaction(callback); - callback = new RetryingTransactionCallback>() - { - public Pair execute() throws Throwable - { - for (int i = 0; i < 1000; i++) - { - dao.getQName(qname); - } - return null; - } - }; - retryingTransactionHelper.doInTransaction(callback); - } - - /** - * Sinces the unique indexes are case-sensitive, we have to ensure that the DAO handles this accordingly. - */ - public void testNamespaceCaseInsensitivity() throws Throwable - { - final String guidNs = GUID.generate(); - final String namespaceUriLower = "aaa-" + guidNs; - final String namespaceUriUpper = "AAA-" + guidNs; - final QName namespaceUriLowerQName = QName.createQName(namespaceUriLower, "blah"); - final QName namespaceUriUpperQName = QName.createQName(namespaceUriUpper, "blah"); - final String localName = GUID.generate(); - final String localNameLower = "aaa-" + localName; - final String localNameUpper = "AAA-" + localName; - final QName localNameLowerQName = QName.createQName("blah", localNameLower); - final QName localNameUpperQName = QName.createQName("blah", localNameUpper); - RetryingTransactionCallback callback = new RetryingTransactionCallback() - { - public Object execute() throws Throwable - { - // Create QNames with lowercase values - dao.getOrCreateQName(namespaceUriLowerQName); - dao.getOrCreateQName(localNameLowerQName); - // Done - return null; - } - }; - retryingTransactionHelper.doInTransaction(callback); - RetryingTransactionCallback callback2 = new RetryingTransactionCallback() - { - public Object execute() throws Throwable - { - // Check namespace case-insensitivity - Pair namespaceUriLowerQNamePair = dao.getQName(namespaceUriLowerQName); - assertNotNull(namespaceUriLowerQNamePair); - Pair namespaceUriUpperQNamePair = dao.getOrCreateQName(namespaceUriUpperQName); - assertNotNull(namespaceUriUpperQNamePair); - assertEquals( - "Didn't resolve case-insensitively on namespace", - namespaceUriLowerQNamePair.getFirst(), namespaceUriUpperQNamePair.getFirst()); - // Check localname case-insensitivity - Pair localNameLowerQNamePair = dao.getQName(localNameLowerQName); - assertNotNull(localNameLowerQNamePair); - Pair localNameUpperQNamePair = dao.getOrCreateQName(localNameUpperQName); - assertNotNull(localNameUpperQNamePair); - assertEquals( - "Didn't resolve case-insensitively on local-name", - localNameLowerQNamePair.getFirst(), localNameUpperQNamePair.getFirst()); - // Done - return null; - } - }; - retryingTransactionHelper.doInTransaction(callback2); - } - - /** - * Forces a bunch of threads to attempt QName creation at exactly the same time - * for their first attempt. The subsequent retries should all succeed by - * finding the QNameEntity. - */ - public void testConcurrentQName() throws Throwable - { - final Random random = new Random(); - final String namespaceUri = GUID.generate(); - int threadCount = 50; - final CountDownLatch readyLatch = new CountDownLatch(threadCount); - final CountDownLatch startLatch = new CountDownLatch(1); - final CountDownLatch doneLatch = new CountDownLatch(threadCount); - final List errors = Collections.synchronizedList(new ArrayList(0)); - final RetryingTransactionCallback> callback = new RetryingTransactionCallback>() - { - public Pair execute() throws Throwable - { - String threadName = Thread.currentThread().getName(); - // We use a common namespace and assign one of a limited set of random numbers - // as the localname. The transaction waits a bit before going for the commit - // so as to ensure a good few others are trying the same thing. - String localName = "" + random.nextInt(10); - QName qname = QName.createQName(namespaceUri, localName); - Pair qnamePair = dao.getQName(qname); - if (qnamePair == null) - { - // Notify that we are ready - logger.debug("Thread " + threadName + " is READY"); - readyLatch.countDown(); - // Wait for start signal - startLatch.await(); - logger.debug("Thread " + threadName + " is GO"); - // Go - try - { - // This could fail with concurrency, but that's what we're testing - logger.debug("Thread " + threadName + " is CREATING " + qname); - qnamePair = dao.newQName(qname); - } - catch (Throwable e) - { - logger.debug("Failed to create QNameEntity. Might retry.", e); - throw e; - } - } - else - { - // In the case where the threads have to wait for database connections, - // it is quite possible that the entity was created as the ready latch - // is released after five seconds - } - assertNotNull("QName should now exist", qnamePair); - // Notify the counter that this thread is done - logger.debug("Thread " + threadName + " is DONE"); - doneLatch.countDown(); - // Done - return qnamePair; - } - }; - Runnable runnable = new Runnable() - { - public void run() - { - try - { - retryingTransactionHelper.doInTransaction(callback); - } - catch (Throwable e) - { - logger.error("Error escaped from retry", e); - errors.add(e); - } - } - }; - // Fire a bunch of threads off - for (int i = 0; i < threadCount; i++) - { - Thread thread = new Thread(runnable, getName() + "-" + i); - thread.setDaemon(true); // Just in case there are complications - thread.start(); - } - // Wait for threads to be ready - readyLatch.await(5, TimeUnit.SECONDS); - // Let the threads go - startLatch.countDown(); - // Wait for them all to be done (within limit of 10 seconds per thread) - if (doneLatch.await(threadCount * 10, TimeUnit.SECONDS)) - { - logger.warn("Still waiting for threads to finish after " + threadCount + " seconds."); - } - // Check if there are errors - if (errors.size() > 0) - { - throw errors.get(0); - } - } -} diff --git a/source/java/org/alfresco/repo/domain/QNameEntity.java b/source/java/org/alfresco/repo/domain/QNameEntity.java deleted file mode 100644 index e7ce61ce4c..0000000000 --- a/source/java/org/alfresco/repo/domain/QNameEntity.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.domain; - -import org.alfresco.service.namespace.QName; - -/** - * Represents a persistable QName entity. - * - * @author Derek Hulley - * @since 2.2 - */ -public interface QNameEntity -{ - Long getId(); - - NamespaceEntity getNamespace(); - - void setNamespace(NamespaceEntity namespace); - - String getLocalName(); - - void setLocalName(String localName); - - QName getQName(); -} diff --git a/source/java/org/alfresco/repo/domain/avm/AbstractAVMNodeDAOImpl.java b/source/java/org/alfresco/repo/domain/avm/AbstractAVMNodeDAOImpl.java index 87bd62d6f5..11ed03c3db 100644 --- a/source/java/org/alfresco/repo/domain/avm/AbstractAVMNodeDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/avm/AbstractAVMNodeDAOImpl.java @@ -25,22 +25,22 @@ package org.alfresco.repo.domain.avm; import java.io.Serializable; -import java.util.HashMap; -import java.util.HashSet; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.Map; +import java.util.Set; import org.alfresco.repo.cache.NullCache; import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.cache.lookup.EntityLookupCache; import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAO; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.QNameDAO; -import org.alfresco.service.namespace.QName; +import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.domain.qname.QNameDAO; +import org.alfresco.service.namespace.QName; +import org.springframework.dao.ConcurrencyFailureException; import org.springframework.extensions.surf.util.Pair; import org.springframework.extensions.surf.util.ParameterCheck; -import org.springframework.dao.ConcurrencyFailureException; /** * Abstract implementation for AVMNode DAO. diff --git a/source/java/org/alfresco/repo/domain/avm/AbstractAVMStoreDAOImpl.java b/source/java/org/alfresco/repo/domain/avm/AbstractAVMStoreDAOImpl.java index e899bfe86e..b9f1f4a416 100644 --- a/source/java/org/alfresco/repo/domain/avm/AbstractAVMStoreDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/avm/AbstractAVMStoreDAOImpl.java @@ -34,11 +34,11 @@ import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.cache.lookup.EntityLookupCache; import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAO; import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.QNameDAO; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.service.namespace.QName; +import org.springframework.dao.ConcurrencyFailureException; import org.springframework.extensions.surf.util.Pair; import org.springframework.extensions.surf.util.ParameterCheck; -import org.springframework.dao.ConcurrencyFailureException; /** * Abstract implementation for AVMStore DAO. diff --git a/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java index 2120c92128..d21941d4a7 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java @@ -44,10 +44,10 @@ import org.alfresco.repo.domain.DbAccessControlListMember; import org.alfresco.repo.domain.DbAuthority; import org.alfresco.repo.domain.DbPermission; import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.QNameDAO; import org.alfresco.repo.domain.avm.AVMNodeDAO; import org.alfresco.repo.domain.avm.AVMNodeEntity; import org.alfresco.repo.domain.patch.PatchDAO; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.security.permissions.ACEType; import org.alfresco.repo.security.permissions.ACLCopyMode; import org.alfresco.repo.security.permissions.ACLType; @@ -66,7 +66,6 @@ import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.namespace.QName; import org.alfresco.util.GUID; -import org.springframework.extensions.surf.util.Pair; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.CacheMode; @@ -75,6 +74,7 @@ import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.Restrictions; +import org.springframework.extensions.surf.util.Pair; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; diff --git a/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java b/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java index 3b7e04a97c..fc68bb446c 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java @@ -33,7 +33,7 @@ import java.util.zip.CRC32; import org.alfresco.repo.domain.ChildAssoc; import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.QNameDAO; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.namespace.QName; import org.alfresco.util.EqualsHelper; diff --git a/source/java/org/alfresco/repo/domain/hibernate/DbPermissionImpl.java b/source/java/org/alfresco/repo/domain/hibernate/DbPermissionImpl.java index 05c804706f..f66e9796e6 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/DbPermissionImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/DbPermissionImpl.java @@ -31,7 +31,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import org.alfresco.repo.domain.DbPermission; import org.alfresco.repo.domain.DbPermissionKey; -import org.alfresco.repo.domain.QNameDAO; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.service.namespace.QName; import org.alfresco.util.EqualsHelper; import org.hibernate.Session; diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateQNameDAOImpl.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateQNameDAOImpl.java deleted file mode 100644 index 4c76fdd472..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/HibernateQNameDAOImpl.java +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.repo.cache.SimpleCache; -import org.alfresco.repo.domain.NamespaceEntity; -import org.alfresco.repo.domain.QNameDAO; -import org.alfresco.repo.domain.QNameEntity; -import org.alfresco.service.namespace.QName; -import org.springframework.extensions.surf.util.Pair; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.Query; -import org.hibernate.Session; -import org.springframework.orm.hibernate3.HibernateCallback; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; - -/** - * Hibernate-specific implementation of the QName and Namespace DAO interface. - * - * @author Derek Hulley - * @since 2.1 - */ -public class HibernateQNameDAOImpl extends HibernateDaoSupport implements QNameDAO -{ - private static Log logger = LogFactory.getLog(HibernateQNameDAOImpl.class); - - private static final String QUERY_GET_NS_BY_URI = "qname.GetNamespaceByUri"; - private static final String QUERY_GET_QNAME_BY_URI_AND_LOCALNAME = "qname.GetQNameByUriAndLocalName"; - - private static final Long CACHE_NULL_LONG = Long.MIN_VALUE; - private SimpleCache namespaceEntityCache; - private SimpleCache qnameEntityCache; - - /** - * Set the cache that maintains the ID-Namespace mappings and vice-versa. - * - * @param namespaceEntityCache the cache - */ - public void setNamespaceEntityCache(SimpleCache namespaceEntityCache) - { - this.namespaceEntityCache = namespaceEntityCache; - } - - /** - * Set the cache that maintains the ID-QName mappings and vice-versa. - * - * @param qnameEntityCache the cache - */ - public void setQnameEntityCache(SimpleCache qnameEntityCache) - { - this.qnameEntityCache = qnameEntityCache; - } - - public Pair getNamespace(Long id) - { - // Check the cache - String uri = (String) namespaceEntityCache.get(id); - if (uri != null) - { - return new Pair(id, uri); - } - // Get it from the DB - NamespaceEntity namespaceEntity = (NamespaceEntity) getSession().get(NamespaceEntityImpl.class, id); - if (namespaceEntity == null) - { - throw new AlfrescoRuntimeException("The NamespaceEntity ID " + id + " doesn't exist."); - } - uri = namespaceEntity.getUri(); - // Cache it - namespaceEntityCache.put(uri, id); - namespaceEntityCache.put(id, uri); - // Done - return new Pair(id, uri); - } - - public Pair getNamespace(final String namespaceUri) - { - // Check the cache - Long id = (Long) namespaceEntityCache.get(namespaceUri); - if (id != null) - { - if (id.equals(CACHE_NULL_LONG)) - { - return null; - } - else - { - return new Pair(id, namespaceUri); - } - } - // Get it from the DB - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - String oracleSafeUri = (namespaceUri.length() == 0) ? NamespaceEntityImpl.EMPTY_URI_SUBSTITUTE : namespaceUri; - - Query query = session - .getNamedQuery(HibernateQNameDAOImpl.QUERY_GET_NS_BY_URI) - .setString("namespaceUri", oracleSafeUri); - return query.uniqueResult(); - } - }; - NamespaceEntity result = (NamespaceEntity) getHibernateTemplate().execute(callback); - if (result == null) - { - // Cache it - namespaceEntityCache.put(namespaceUri, CACHE_NULL_LONG); - // Done - return null; - } - else - { - id = result.getId(); - // Cache it - namespaceEntityCache.put(id, namespaceUri); - namespaceEntityCache.put(namespaceUri, id); - // Done - return new Pair(id, namespaceUri); - } - } - - public Pair getOrCreateNamespace(String namespaceUri) - { - Pair result = getNamespace(namespaceUri); - if (result == null) - { - result = newNamespace(namespaceUri); - } - return result; - } - - public Pair newNamespace(String namespaceUri) - { - if (logger.isDebugEnabled()) - { - logger.debug("Persisting Namespace: " + namespaceUri); - } - NamespaceEntity namespace = new NamespaceEntityImpl(); - namespace.setUri(namespaceUri); - // Persist - Session session = getSession(); - Long id = (Long) session.save(namespace); - DirtySessionMethodInterceptor.flushSession(session, true); - // Force a flush because Hibernate doesn't always get the flush order right - // for DBs that use sequences for the PK: ETHREEOH-1962 - DirtySessionMethodInterceptor.flushSession(getSession(), true); - // Cache it - namespaceEntityCache.put(id, namespaceUri); - namespaceEntityCache.put(namespaceUri, id); - // Done - return new Pair(id, namespaceUri); - } - - public void updateNamespace(String oldNamespaceUri, String newNamespaceUri) - { - // First check for clashes - if (getNamespace(newNamespaceUri) != null) - { - throw new AlfrescoRuntimeException("Namespace URI '" + newNamespaceUri + "' already exists."); - } - // Get the old one - Pair oldNamespacePair = getNamespace(oldNamespaceUri); - if (oldNamespacePair == null) - { - // Nothing to rename - return; - } - NamespaceEntity oldNamespaceEntity = (NamespaceEntity) getSession().load(NamespaceEntityImpl.class, oldNamespacePair.getFirst()); - oldNamespaceEntity.setUri(newNamespaceUri); - // Flush to force early failure - getSession().flush(); - // Trash the cache - qnameEntityCache.clear(); - // Done - } - - public Pair getQName(Long id) - { - // Check the cache - QName qname = (QName) qnameEntityCache.get(id); - if (qname != null) - { - return new Pair(id, qname); - } - QNameEntity qnameEntity = (QNameEntity) getSession().get(QNameEntityImpl.class, id); - if (qnameEntity == null) - { - throw new AlfrescoRuntimeException("The QNameEntity ID " + id + " doesn't exist."); - } - qname = qnameEntity.getQName(); - // Cache it - qnameEntityCache.put(id, qname); - qnameEntityCache.put(qname, id); - // Done - return new Pair(id, qname); - } - - public Pair getQName(final QName qname) - { - // Check the cache - Long id = (Long) qnameEntityCache.get(qname); - if (id != null) - { - if (id.equals(CACHE_NULL_LONG)) - { - return null; - } - else - { - return new Pair(id, qname); - } - } - QNameEntity result; - // It's not in the cache, so query - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - String namespaceUri = qname.getNamespaceURI(); - String oracleSafeUri = (namespaceUri.length() == 0) ? NamespaceEntityImpl.EMPTY_URI_SUBSTITUTE : namespaceUri; - - Query query = session - .getNamedQuery(HibernateQNameDAOImpl.QUERY_GET_QNAME_BY_URI_AND_LOCALNAME) - .setString("namespaceUri", oracleSafeUri) - .setString("localName", qname.getLocalName()); - return query.uniqueResult(); - } - }; - result = (QNameEntity) getHibernateTemplate().execute(callback); - if (result == null) - { - // Cache it - qnameEntityCache.put(qname, CACHE_NULL_LONG); - // Done - return null; - } - else - { - id = result.getId(); - // Cache it - qnameEntityCache.put(id, qname); - qnameEntityCache.put(qname, id); - // Done - return new Pair(id, qname); - } - } - - public Pair getOrCreateQName(QName qname) - { - Pair result = getQName(qname); - if (result == null) - { - result = newQName(qname); - } - return result; - } - - public Pair newQName(QName qname) - { - if (logger.isDebugEnabled()) - { - logger.debug("Persisting QName: " + qname); - } - final String namespaceUri = qname.getNamespaceURI(); - final String localName = qname.getLocalName(); - // Get the namespace - Pair namespacePair = getOrCreateNamespace(namespaceUri); - NamespaceEntity namespace = (NamespaceEntity) getSession().load(NamespaceEntityImpl.class, namespacePair.getFirst()); - // Create the QNameEntity - QNameEntity qnameEntity = new QNameEntityImpl(); - qnameEntity.setNamespace(namespace); - qnameEntity.setLocalName(localName); - // Persist - Long id = (Long) getSession().save(qnameEntity); - // Force a flush because Hibernate doesn't always get the flush order right - // for DBs that use sequences for the PK: ETHREEOH-1962 - DirtySessionMethodInterceptor.flushSession(getSession(), true); - // Update the cache - qnameEntityCache.put(qname, id); - qnameEntityCache.put(id, qname); - // Done - return new Pair(id, qname); - } - - public Set convertIdsToQNames(Set ids) - { - Set qnames = new HashSet(ids.size() * 2 + 1); - for (Long id : ids) - { - QName qname = getQName(id).getSecond(); // getQName(id) is never null - qnames.add(qname); - } - return qnames; - } - - public Map convertIdMapToQNameMap(Map idMap) - { - Map qnameMap = new HashMap(idMap.size() + 3); - for (Map.Entry entry : idMap.entrySet()) - { - QName qname = getQName(entry.getKey()).getSecond(); // getQName(id) is never null - qnameMap.put(qname, entry.getValue()); - } - return qnameMap; - } - - /** - * @return Returns a set of IDs mapping to the QNames provided. If create is false - * then there will not be corresponding entries for the QNames that don't exist. - * So there is no guarantee that the returned set will be ordered the same or even - * contain the same number of elements as the original unless create is true. - */ - public Set convertQNamesToIds(Set qnames, boolean create) - { - Set qnameIds = new HashSet(qnames.size(), 1.0F); - for (QName qname : qnames) - { - Long qnameEntityId = null; - if (create) - { - qnameEntityId = getOrCreateQName(qname).getFirst(); // getOrCreateQName(qname) is never null - } - else - { - Pair qnamePair = getQName(qname); - if (qnamePair == null) - { - // No such qname and we are not creating one - continue; - } - else - { - qnameEntityId = qnamePair.getFirst(); - } - } - if (qnameEntityId != null) - { - qnameIds.add(qnameEntityId); - } - } - // Done - return qnameIds; - } -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperResource.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperResource.java index ebe81f4c37..dd789eb64a 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperResource.java +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperResource.java @@ -213,11 +213,6 @@ public class HibernateSessionHelperResource implements HibernateSessionHelperRes { if (!check.contains(key)) { - if(key.getEntityName().equals(QNameEntityImpl.class.getName())) - { - //System.out.println("Skipping: " + key.getEntityName()); - continue; - } Object val = session.get(key.getEntityName(), key.getIdentifier()); if (val != null) { diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperTest.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperTest.java index 8ddf43fcc7..b556800ee3 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperTest.java +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateSessionHelperTest.java @@ -11,7 +11,7 @@ import junit.framework.TestCase; import org.alfresco.model.ContentModel; import org.alfresco.repo.domain.AuditableProperties; import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.QNameDAO; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.domain.Server; import org.alfresco.repo.domain.Store; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; @@ -143,7 +143,7 @@ public class HibernateSessionHelperTest extends TestCase // persist so that it is present in the hibernate cache getSession().save(store); - assertEquals(2, getSession().getStatistics().getEntityCount()); + assertEquals(1, getSession().getStatistics().getEntityCount()); Server server = (Server) getSession().get(ServerImpl.class, new Long(1)); if (server == null) @@ -158,9 +158,9 @@ public class HibernateSessionHelperTest extends TestCase transaction.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); getSession().save(transaction); - assertEquals(4, getSession().getStatistics().getEntityCount()); - HibernateSessionHelper helper = (HibernateSessionHelper)ctx.getBean("hibernateSessionHelper"); + + assertEquals(3, getSession().getStatistics().getEntityCount()); assertFalse(SessionSizeResourceManager.isDisableInTransaction()); helper.mark(); assertTrue(SessionSizeResourceManager.isDisableInTransaction()); @@ -168,35 +168,35 @@ public class HibernateSessionHelperTest extends TestCase Node n1 = createNode(transaction, store, "1", baseQNameId); - assertEquals(5, getSession().getStatistics().getEntityCount()); + assertEquals(4, getSession().getStatistics().getEntityCount()); helper.mark(); assertTrue(SessionSizeResourceManager.isDisableInTransaction()); assertEquals(2, helper.getMarks().size()); Node n2 = createNode(transaction, store, "2", baseQNameId); - assertEquals(6, getSession().getStatistics().getEntityCount()); + assertEquals(5, getSession().getStatistics().getEntityCount()); helper.mark(); assertTrue(SessionSizeResourceManager.isDisableInTransaction()); assertEquals(3, helper.getMarks().size()); Node n3 = createNode(transaction, store, "3", baseQNameId); - assertEquals(7, getSession().getStatistics().getEntityCount()); + assertEquals(6, getSession().getStatistics().getEntityCount()); helper.mark(); assertTrue(SessionSizeResourceManager.isDisableInTransaction()); assertEquals(4, helper.getMarks().size()); Node n4 = createNode(transaction, store, "4", baseQNameId); - assertEquals(8, getSession().getStatistics().getEntityCount()); + assertEquals(7, getSession().getStatistics().getEntityCount()); helper.mark(); assertTrue(SessionSizeResourceManager.isDisableInTransaction()); assertEquals(5, helper.getMarks().size()); Node n5 = createNode(transaction, store, "5", baseQNameId); - assertEquals(9, getSession().getStatistics().getEntityCount()); + assertEquals(8, getSession().getStatistics().getEntityCount()); helper.reset(); assertEquals(8, getSession().getStatistics().getEntityCount()); @@ -371,7 +371,7 @@ public class HibernateSessionHelperTest extends TestCase // persist so that it is present in the hibernate cache getSession().save(store); - assertEquals(2, getSession().getStatistics().getEntityCount()); + assertEquals(1, getSession().getStatistics().getEntityCount()); Server server = (Server) getSession().get(ServerImpl.class, new Long(1)); if (server == null) @@ -386,7 +386,7 @@ public class HibernateSessionHelperTest extends TestCase transaction.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); getSession().save(transaction); - assertEquals(4, getSession().getStatistics().getEntityCount()); + assertEquals(3, getSession().getStatistics().getEntityCount()); HibernateSessionHelper helper = (HibernateSessionHelper)ctx.getBean("hibernateSessionHelper"); assertNull(helper.getCurrentMark()); @@ -398,7 +398,7 @@ public class HibernateSessionHelperTest extends TestCase Node n1 = createNode(transaction, store, "1", baseQNameId); - assertEquals(5, getSession().getStatistics().getEntityCount()); + assertEquals(4, getSession().getStatistics().getEntityCount()); helper.mark("Two"); assertEquals("Two", helper.getCurrentMark()); assertTrue(SessionSizeResourceManager.isDisableInTransaction()); @@ -406,7 +406,7 @@ public class HibernateSessionHelperTest extends TestCase Node n2 = createNode(transaction, store, "2", baseQNameId); - assertEquals(6, getSession().getStatistics().getEntityCount()); + assertEquals(5, getSession().getStatistics().getEntityCount()); helper.mark("Three"); assertEquals("Three", helper.getCurrentMark()); assertTrue(SessionSizeResourceManager.isDisableInTransaction()); @@ -414,7 +414,7 @@ public class HibernateSessionHelperTest extends TestCase Node n3 = createNode(transaction, store, "3", baseQNameId); - assertEquals(7, getSession().getStatistics().getEntityCount()); + assertEquals(6, getSession().getStatistics().getEntityCount()); helper.mark("Four"); assertEquals("Four", helper.getCurrentMark()); assertTrue(SessionSizeResourceManager.isDisableInTransaction()); @@ -422,7 +422,7 @@ public class HibernateSessionHelperTest extends TestCase Node n4 = createNode(transaction, store, "4", baseQNameId); - assertEquals(8, getSession().getStatistics().getEntityCount()); + assertEquals(7, getSession().getStatistics().getEntityCount()); helper.mark("Five"); assertEquals("Five", helper.getCurrentMark()); assertTrue(SessionSizeResourceManager.isDisableInTransaction()); diff --git a/source/java/org/alfresco/repo/domain/hibernate/NodeAssocImpl.java b/source/java/org/alfresco/repo/domain/hibernate/NodeAssocImpl.java index e08835ee26..62b2423340 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/NodeAssocImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/NodeAssocImpl.java @@ -31,7 +31,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import org.alfresco.repo.domain.Node; import org.alfresco.repo.domain.NodeAssoc; -import org.alfresco.repo.domain.QNameDAO; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.namespace.QName; import org.alfresco.util.EqualsHelper; diff --git a/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java b/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java index ded2d244b9..8e95980eb8 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java @@ -38,9 +38,9 @@ import org.alfresco.repo.domain.DbAccessControlList; import org.alfresco.repo.domain.Node; import org.alfresco.repo.domain.NodePropertyValue; import org.alfresco.repo.domain.PropertyMapKey; -import org.alfresco.repo.domain.QNameDAO; import org.alfresco.repo.domain.Store; import org.alfresco.repo.domain.Transaction; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; import org.alfresco.util.EqualsHelper; diff --git a/source/java/org/alfresco/repo/domain/hibernate/QName.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/QName.hbm.xml deleted file mode 100644 index 3de05dec33..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/QName.hbm.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - select - namespace - from - org.alfresco.repo.domain.hibernate.NamespaceEntityImpl as namespace - where - namespace.safeUri = :namespaceUri - - - - select - qname - from - org.alfresco.repo.domain.hibernate.QNameEntityImpl as qname - join qname.namespace as namespace - where - namespace.safeUri = :namespaceUri and - qname.localName = :localName - - - diff --git a/source/java/org/alfresco/repo/domain/hibernate/QNameEntityImpl.java b/source/java/org/alfresco/repo/domain/hibernate/QNameEntityImpl.java deleted file mode 100644 index b3747ed41d..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/QNameEntityImpl.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; - -import org.alfresco.repo.domain.NamespaceEntity; -import org.alfresco.repo.domain.QNameEntity; -import org.alfresco.service.namespace.QName; - -/** - * Hibernate-specific implementation of the domain entity QnameEntity. - * - * @author Derek Hulley - */ -public class QNameEntityImpl implements QNameEntity, Serializable -{ - private static final long serialVersionUID = -4211902156023915846L; - - private Long id; - private Long version; - private NamespaceEntity namespace; - private String localName; - - private transient ReadLock refReadLock; - private transient WriteLock refWriteLock; - private transient QName qname; - - public QNameEntityImpl() - { - ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - refReadLock = lock.readLock(); - refWriteLock = lock.writeLock(); - } - - /** - * Lazily constructs a QName instance referencing this entity - */ - public QName getQName() - { - // first check if it is available - refReadLock.lock(); - try - { - if (qname != null) - { - return qname; - } - } - finally - { - refReadLock.unlock(); - } - // get write lock - refWriteLock.lock(); - try - { - // double check - if (qname == null ) - { - String namespaceUri = namespace.getUri(); - if (namespaceUri.equals(NamespaceEntityImpl.EMPTY_URI_SUBSTITUTE)) - { - namespaceUri = ""; - } - qname = QName.createQName(namespaceUri, localName); - } - return qname; - } - finally - { - refWriteLock.unlock(); - } - } - - /** - * @see #getStoreRef()() - */ - public String toString() - { - return getQName().toString(); - } - - /** - * @see #getKey() - */ - public boolean equals(Object obj) - { - if (obj == null) - { - return false; - } - else if (obj == this) - { - return true; - } - else if (!(obj instanceof QNameEntity)) - { - return false; - } - QNameEntity that = (QNameEntity) obj; - return (this.getQName().equals(that.getQName())); - } - - /** - * @see #getKey() - */ - public int hashCode() - { - return getQName().hashCode(); - } - - public Long getId() - { - return id; - } - - /** - * For Hibernate use. - */ - @SuppressWarnings("unused") - private void setId(Long id) - { - this.id = id; - } - - public Long getVersion() - { - return version; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setVersion(Long version) - { - this.version = version; - } - - public NamespaceEntity getNamespace() - { - return namespace; - } - - public void setNamespace(NamespaceEntity namespace) - { - refWriteLock.lock(); - try - { - this.namespace = namespace; - this.qname = null; - } - finally - { - refWriteLock.unlock(); - } - } - - public String getLocalName() - { - return localName; - } - - public void setLocalName(String localName) - { - refWriteLock.lock(); - try - { - this.localName = localName; - this.qname = null; - } - finally - { - refWriteLock.unlock(); - } - } -} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/hibernate/QNameUserType.java b/source/java/org/alfresco/repo/domain/hibernate/QNameUserType.java deleted file mode 100644 index d2aa50536a..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/QNameUserType.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; - -import org.alfresco.service.namespace.QName; -import org.alfresco.util.EqualsHelper; -import org.hibernate.HibernateException; -import org.hibernate.usertype.UserType; - -/** - * Custom type to hide the persistence of {@link org.alfresco.service.namespace.QName qname} - * instances. - * - * @author Derek Hulley - */ -public class QNameUserType implements UserType -{ - private static int[] SQL_TYPES = new int[] {Types.VARCHAR}; - - public Class returnedClass() - { - return QName.class; - } - - /** - * @see #SQL_TYPES - */ - public int[] sqlTypes() - { - return SQL_TYPES; - } - - public boolean isMutable() - { - return false; - } - - public boolean equals(Object x, Object y) throws HibernateException - { - return EqualsHelper.nullSafeEquals(x, y); - } - - public int hashCode(Object x) throws HibernateException - { - return x.hashCode(); - } - - public Object deepCopy(Object value) throws HibernateException - { - // the qname is immutable - return value; - } - - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException - { - String qnameStr = rs.getString(names[0]); - if (qnameStr == null) - { - return null; - } - else - { - QName qname = QName.createQName(qnameStr); - return qname; - } - } - - public void nullSafeSet(PreparedStatement stmt, Object value, int index) throws HibernateException, SQLException - { - // convert the qname to a string - stmt.setString(index, value.toString()); - } - - public Object replace(Object original, Object target, Object owner) throws HibernateException - { - // qname is immutable - return original; - } - - public Object assemble(Serializable cached, Object owner) throws HibernateException - { - // qname is serializable - return cached; - } - - public Serializable disassemble(Object value) throws HibernateException - { - // qname is serializable - return (QName) value; - } -} diff --git a/source/java/org/alfresco/repo/domain/locks/AbstractLockDAOImpl.java b/source/java/org/alfresco/repo/domain/locks/AbstractLockDAOImpl.java index fd8551026c..9b8eb8f7c8 100644 --- a/source/java/org/alfresco/repo/domain/locks/AbstractLockDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/locks/AbstractLockDAOImpl.java @@ -30,7 +30,7 @@ import java.util.List; import java.util.Map; import java.util.StringTokenizer; -import org.alfresco.repo.domain.QNameDAO; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.lock.LockAcquisitionException; import org.alfresco.service.namespace.QName; import org.alfresco.util.EqualsHelper; diff --git a/source/java/org/alfresco/repo/domain/qname/AbstractQNameDAOImpl.java b/source/java/org/alfresco/repo/domain/qname/AbstractQNameDAOImpl.java new file mode 100644 index 0000000000..a178cc15c5 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/qname/AbstractQNameDAOImpl.java @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.qname; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.cache.lookup.EntityLookupCache; +import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAOAdaptor; +import org.alfresco.service.namespace.QName; +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.extensions.surf.util.Pair; +import org.springframework.extensions.surf.util.ParameterCheck; + +/** + * Abstract implementation of the QName and Namespace DAO interface. + * + * @author Derek Hulley + * @since 3.3 + */ +public abstract class AbstractQNameDAOImpl implements QNameDAO +{ + private static final String CACHE_REGION_NAMESPACE = "Namespace"; + private static final String CACHE_REGION_QNAME = "QName"; + + /** + * Cache for the Namespace values:
+ * KEY: ID
+ * VALUE: Namespace
+ * VALUE KEY: Namespace
+ */ + private EntityLookupCache namespaceCache; + /** + * Cache for the QName values:
+ * KEY: ID
+ * VALUE: QName
+ * VALUE KEY: QName
+ */ + private EntityLookupCache qnameCache; + + /** + * Default constructor. + *

+ * This sets up the DAO accessors to bypass any caching to handle the case where the caches are not + * supplied in the setters. + */ + protected AbstractQNameDAOImpl() + { + this.namespaceCache = new EntityLookupCache(new NamespaceCallbackDAO()); + this.qnameCache = new EntityLookupCache(new QNameCallbackDAO()); + } + + /** + * Set the cache that maintains the ID-Namespace mappings and vice-versa. + * + * @param namespaceCache the cache + */ + public void setNamespaceCache(SimpleCache namespaceCache) + { + this.namespaceCache = new EntityLookupCache( + namespaceCache, + CACHE_REGION_NAMESPACE, + new NamespaceCallbackDAO()); + } + + /** + * Set the cache that maintains the ID-Namespace mappings and vice-versa. + * + * @param qnameCache the cache + */ + public void setQnameCache(SimpleCache qnameCache) + { + this.qnameCache = new EntityLookupCache( + qnameCache, + CACHE_REGION_QNAME, + new QNameCallbackDAO()); + } + + //================================ + // 'alf_namespace' accessors + //================================ + + public Pair getNamespace(Long id) + { + if (id == null) + { + throw new IllegalArgumentException("Cannot look up entity by null ID."); + } + Pair entityPair = namespaceCache.getByKey(id); + if (entityPair == null) + { + throw new DataIntegrityViolationException("No namespace exists for ID " + id); + } + return entityPair; + } + + public Pair getNamespace(String namespaceUri) + { + if (namespaceUri == null) + { + throw new IllegalArgumentException("Namespace URI cannot be null"); + } + Pair entityPair = namespaceCache.getByValue(namespaceUri); + return entityPair; + } + + public Pair getOrCreateNamespace(String namespaceUri) + { + if (namespaceUri == null) + { + throw new IllegalArgumentException("Namespace URI cannot be null"); + } + Pair entityPair = namespaceCache.getOrCreateByValue(namespaceUri); + return entityPair; + } + + public void updateNamespace(String oldNamespaceUri, String newNamespaceUri) + { + ParameterCheck.mandatory("newNamespaceUri", newNamespaceUri); + + Pair oldEntityPair = getNamespace(oldNamespaceUri); // incl. null check + if (oldEntityPair == null) + { + throw new DataIntegrityViolationException( + "Cannot update namespace as it doesn't exist: " + oldNamespaceUri); + } + // Find the value + int updated = namespaceCache.updateValue(oldEntityPair.getFirst(), newNamespaceUri); + if (updated != 1) + { + throw new ConcurrencyFailureException( + "Incorrect update count: \n" + + " Namespace: " + oldNamespaceUri + "\n" + + " Rows Updated: " + updated); + } + // All the QNames need to be dumped + qnameCache.clear(); + // Done + } + + /** + * Callback for alf_namespace DAO. + */ + private class NamespaceCallbackDAO extends EntityLookupCallbackDAOAdaptor + { + public Pair findByKey(Long id) + { + NamespaceEntity entity = findNamespaceEntityById(id); + if (entity == null) + { + return null; + } + else + { + return new Pair(id, entity.getUriSafe()); + } + } + + @Override + public Pair findByValue(String uri) + { + NamespaceEntity entity = findNamespaceEntityByUri(uri); + if (entity == null) + { + return null; + } + else + { + return new Pair(entity.getId(), uri); + } + } + + public Pair createValue(String uri) + { + NamespaceEntity entity = createNamespaceEntity(uri); + return new Pair(entity.getId(), uri); + } + + @Override + public int updateValue(Long id, String uri) + { + NamespaceEntity entity = findNamespaceEntityById(id); + if (entity == null) + { + // Client can decide if this is a problem + return 0; + } + return updateNamespaceEntity(entity, uri); + } + } + + protected abstract NamespaceEntity findNamespaceEntityById(Long id); + protected abstract NamespaceEntity findNamespaceEntityByUri(String uri); + protected abstract NamespaceEntity createNamespaceEntity(String uri); + protected abstract int updateNamespaceEntity(NamespaceEntity entity, String uri); + + //================================ + // 'alf_qname' accessors + //================================ + + public Pair getQName(Long id) + { + if (id == null) + { + throw new IllegalArgumentException("Cannot look up entity by null ID."); + } + Pair entityPair = qnameCache.getByKey(id); + if (entityPair == null) + { + throw new DataIntegrityViolationException("No qname exists for ID " + id); + } + return entityPair; + } + + public Pair getQName(final QName qname) + { + if (qname == null) + { + throw new IllegalArgumentException("QName cannot be null"); + } + Pair entityPair = qnameCache.getByValue(qname); + return entityPair; + } + + public Pair getOrCreateQName(QName qname) + { + if (qname == null) + { + throw new IllegalArgumentException("QName cannot be null"); + } + Pair entityPair = qnameCache.getOrCreateByValue(qname); + return entityPair; + } + + public Pair updateQName(QName qnameOld, QName qnameNew) + { + if (qnameOld == null|| qnameNew == null) + { + throw new IllegalArgumentException("QName cannot be null"); + } + if (qnameOld.equals(qnameNew)) + { + throw new IllegalArgumentException("Cannot update QNames: they are the same"); + } + // See if the old QName exists + Pair qnameOldPair = qnameCache.getByValue(qnameOld); + if (qnameOldPair == null) + { + throw new IllegalArgumentException("Cannot rename QName. QName " + qnameOld + " does not exist"); + } + // See if the new QName exists + if (qnameCache.getByValue(qnameNew) != null) + { + throw new IllegalArgumentException("Cannot rename QName. QName " + qnameNew + " already exists"); + } + // Update + Long qnameId = qnameOldPair.getFirst(); + int updated = qnameCache.updateValue(qnameId, qnameNew); + if (updated != 1) + { + throw new ConcurrencyFailureException("Failed to update QName entity " + qnameId); + } + return new Pair(qnameId, qnameNew); + } + + /** + * Callback for alf_qname DAO. + */ + private class QNameCallbackDAO extends EntityLookupCallbackDAOAdaptor + { + public Pair findByKey(Long id) + { + QNameEntity entity = findQNameEntityById(id); + if (entity == null) + { + return null; + } + else + { + Long namespaceId = entity.getNamespaceId(); + String uri = getNamespace(namespaceId).getSecond(); + String localName = entity.getLocalNameSafe(); + QName qname = QName.createQName(uri, localName); + return new Pair(id, qname); + } + } + + @Override + public Pair findByValue(QName qname) + { + String uri = qname.getNamespaceURI(); + String localName = qname.getLocalName(); + Pair namespaceEntity = getNamespace(uri); + if (namespaceEntity == null) + { + // There is no match on NS, so there is no QName like this + return null; + } + Long nsId = namespaceEntity.getFirst(); + QNameEntity entity = findQNameEntityByNamespaceAndLocalName(nsId, localName); + if (entity == null) + { + return null; + } + else + { + return new Pair(entity.getId(), qname); + } + } + + public Pair createValue(QName qname) + { + String uri = qname.getNamespaceURI(); + String localName = qname.getLocalName(); + // Create namespace + Pair namespaceEntity = getOrCreateNamespace(uri); + Long nsId = namespaceEntity.getFirst(); + // Create QName + QNameEntity entity = createQNameEntity(nsId, localName); + return new Pair(entity.getId(), qname); + } + + @Override + public int updateValue(Long id, QName qname) + { + String uri = qname.getNamespaceURI(); + String localName = qname.getLocalName(); + + QNameEntity entity = findQNameEntityById(id); + if (entity == null) + { + // No chance of updating + return 0; + } + + // Create namespace + Pair namespaceEntity = getOrCreateNamespace(uri); + Long nsId = namespaceEntity.getFirst(); + // Create QName + return updateQNameEntity(entity, nsId, localName); + } + } + + protected abstract QNameEntity findQNameEntityById(Long id); + protected abstract QNameEntity findQNameEntityByNamespaceAndLocalName(Long nsId, String localName); + protected abstract QNameEntity createQNameEntity(Long nsId, String localName); + protected abstract int updateQNameEntity(QNameEntity entity, Long nsId, String localName); + + + //================================ + // Utility method implementations + //================================ + + public Set convertIdsToQNames(Set ids) + { + Set qnames = new HashSet(ids.size() * 2 + 1); + for (Long id : ids) + { + QName qname = getQName(id).getSecond(); // getQName(id) is never null + qnames.add(qname); + } + return qnames; + } + + public Map convertIdMapToQNameMap(Map idMap) + { + Map qnameMap = new HashMap(idMap.size() + 3); + for (Map.Entry entry : idMap.entrySet()) + { + QName qname = getQName(entry.getKey()).getSecond(); // getQName(id) is never null + qnameMap.put(qname, entry.getValue()); + } + return qnameMap; + } + + /** + * @return Returns a set of IDs mapping to the QNames provided. If create is false + * then there will not be corresponding entries for the QNames that don't exist. + * So there is no guarantee that the returned set will be ordered the same or even + * contain the same number of elements as the original unless create is true. + */ + public Set convertQNamesToIds(Set qnames, boolean create) + { + Set qnameIds = new HashSet(qnames.size(), 1.0F); + for (QName qname : qnames) + { + Long qnameEntityId = null; + if (create) + { + qnameEntityId = getOrCreateQName(qname).getFirst(); // getOrCreateQName(qname) is never null + } + else + { + Pair qnamePair = getQName(qname); + if (qnamePair == null) + { + // No such qname and we are not creating one + continue; + } + else + { + qnameEntityId = qnamePair.getFirst(); + } + } + if (qnameEntityId != null) + { + qnameIds.add(qnameEntityId); + } + } + // Done + return qnameIds; + } +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/NamespaceEntityImpl.java b/source/java/org/alfresco/repo/domain/qname/NamespaceEntity.java similarity index 50% rename from source/java/org/alfresco/repo/domain/hibernate/NamespaceEntityImpl.java rename to source/java/org/alfresco/repo/domain/qname/NamespaceEntity.java index 0bb463296a..ba3450541b 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/NamespaceEntityImpl.java +++ b/source/java/org/alfresco/repo/domain/qname/NamespaceEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2010 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,79 +22,57 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.domain.hibernate; +package org.alfresco.repo.domain.qname; -import java.io.Serializable; - -import org.alfresco.repo.domain.NamespaceEntity; -import org.alfresco.repo.domain.QNameEntity; +import org.alfresco.util.EqualsHelper; /** - * Hibernate-specific implementation of the domain entity QnameEntity. + * Entity for alf_namespace persistence. * * @author Derek Hulley + * @since 3.3 */ -public class NamespaceEntityImpl implements NamespaceEntity, Serializable +public class NamespaceEntity { - private static final long serialVersionUID = -6781559184013949845L; - public static final String EMPTY_URI_SUBSTITUTE = ".empty"; + public static final Long CONST_LONG_ZERO = new Long(0L); private Long id; private Long version; - private String safeUri; - - public NamespaceEntityImpl() + private String uri; + + public NamespaceEntity() { } - /** - * @see #getStoreRef()() - */ + @Override public String toString() { - return getUri(); + StringBuilder sb = new StringBuilder(512); + sb.append("NamespaceEntity") + .append("[ id=").append(id) + .append(", uri=").append(uri) + .append("]"); + return sb.toString(); } - - /** - * @see #getKey() - */ - public boolean equals(Object obj) + + public void incrementVersion() { - if (obj == null) + if (version >= Short.MAX_VALUE) { - return false; + this.version = 0L; } - else if (obj == this) + else { - return true; + this.version++; } - else if (!(obj instanceof QNameEntity)) - { - return false; - } - NamespaceEntity that = (NamespaceEntity) obj; - return (this.getUri().equals(that.getUri())); - } - - /** - * @see #getKey() - */ - public int hashCode() - { - return safeUri.hashCode(); } public Long getId() { return id; } - - /** - * For Hibernate use. - */ - @SuppressWarnings("unused") - private void setId(Long id) + public void setId(Long id) { this.id = id; } @@ -103,34 +81,39 @@ public class NamespaceEntityImpl implements NamespaceEntity, Serializable { return version; } - - /** For Hibernate use */ - @SuppressWarnings("unused") - private void setVersion(Long version) + public void setVersion(Long version) { this.version = version; } - - /** For Hibernate use */ - @SuppressWarnings("unused") - private String getSafeUri() - { - return safeUri; - } - - /** For Hibernate use */ - private void setSafeUri(String safeUri) - { - this.safeUri = safeUri; - } - + public String getUri() { - return safeUri.equals(EMPTY_URI_SUBSTITUTE) ? "" : safeUri; + return uri; } - public void setUri(String uri) { - setSafeUri(uri.length() == 0 ? EMPTY_URI_SUBSTITUTE : uri); + this.uri = uri; } -} \ No newline at end of file + + /** + * Convenience getter to interpret the {@link #EMPTY_URI_SUBSTITUTE} + */ + public String getUriSafe() + { + if (EqualsHelper.nullSafeEquals(uri, NamespaceEntity.EMPTY_URI_SUBSTITUTE)) + { + return ""; + } + else + { + return uri; + } + } + /** + * Convenience setter to interpret the {@link #EMPTY_URI_SUBSTITUTE} + */ + public void setUriSafe(String uri) + { + this.uri = (uri.length() == 0) ? NamespaceEntity.EMPTY_URI_SUBSTITUTE : uri; + } +} diff --git a/source/java/org/alfresco/repo/domain/QNameDAO.java b/source/java/org/alfresco/repo/domain/qname/QNameDAO.java similarity index 71% rename from source/java/org/alfresco/repo/domain/QNameDAO.java rename to source/java/org/alfresco/repo/domain/qname/QNameDAO.java index 66c5d9d0d7..49c91e7fec 100644 --- a/source/java/org/alfresco/repo/domain/QNameDAO.java +++ b/source/java/org/alfresco/repo/domain/qname/QNameDAO.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Alfresco Software Limited. + * Copyright (C) 2005-2010 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,7 +22,7 @@ * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.domain; +package org.alfresco.repo.domain.qname; import java.util.Map; import java.util.Set; @@ -35,7 +35,7 @@ import org.springframework.extensions.surf.util.Pair; * Data abstraction layer for QName and Namespace entities. * * @author Derek Hulley - * @since 2.1 + * @since 3.3 */ public interface QNameDAO { @@ -62,12 +62,6 @@ public interface QNameDAO */ Pair getOrCreateNamespace(String namespaceUri); - /** - * @param namespaceUri the namespace URI to create - * @return the new namespace pair (id, uri) - */ - Pair newNamespace(String namespaceUri); - /** * Modifies an existing namespace URI. If the new URI already exists, then no * new entity is created. @@ -102,14 +96,39 @@ public interface QNameDAO Pair getOrCreateQName(QName qname); /** - * @param qname the QName to create - * @return the new QName pair (id, qname) + * Modify an existing QName. The ID of the new QName will be the same as the old one + * i.e. the old QName will cease to exist and will become the new QName. This allows + * QName modification without affecting tables that reference the old QName. + * + * @param qnameOld the old QName, which must exist + * @param qnameNew the new QName, which must not exist + * @return the QName pair (id, qname) with the ID unchanged from old to new */ - Pair newQName(QName qname); + Pair updateQName(QName qnameOld, QName qnameNew); + /** + * Bulk-convert QName IDs into QNames + * + * @param ids the IDs + * @return the QNames for the IDs given, in the same order + */ Set convertIdsToQNames(Set ids); + /** + * Convenience method to convert map keys from QName IDs to QNames + * + * @param idMap a map of objects keyed by QName ID + * @return a map of the same objects keyed by the equivalent QNames + */ Map convertIdMapToQNameMap(Map idMap); + /** + * Bulk-convert QNames into QName IDs. This is primarily used for generating + * SQL IN clause lists for other DAO queries. + * + * @param qnames the QNames to convert + * @param create true to create any missing QName entities + * @return returns the QName IDs (order not guaranteed) + */ Set convertQNamesToIds(Set qnames, boolean create); } diff --git a/source/java/org/alfresco/repo/domain/qname/QNameDAOTest.java b/source/java/org/alfresco/repo/domain/qname/QNameDAOTest.java new file mode 100644 index 0000000000..ea4bf37696 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/qname/QNameDAOTest.java @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.qname; + +import junit.framework.TestCase; + +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.GUID; +import org.springframework.extensions.surf.util.Pair; +import org.springframework.context.ApplicationContext; + +/** + * @see QNameDAO + * + * @author Derek Hulley + * @since 3.3 + */ +public class QNameDAOTest extends TestCase +{ + private ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + + private TransactionService transactionService; + private RetryingTransactionHelper txnHelper; + private QNameDAO qnameDAO; + + @Override + public void setUp() throws Exception + { + ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); + transactionService = serviceRegistry.getTransactionService(); + txnHelper = transactionService.getRetryingTransactionHelper(); + + qnameDAO = (QNameDAO) ctx.getBean("qnameDAO"); + } + + private Pair getNamespace(final String uri, final boolean autoCreate, boolean expectSuccess) + { + RetryingTransactionCallback> callback = new RetryingTransactionCallback>() + { + public Pair execute() throws Throwable + { + Pair namespacePair = null; + if (autoCreate) + { + namespacePair = qnameDAO.getOrCreateNamespace(uri); + } + else + { + namespacePair = qnameDAO.getNamespace(uri); + } + return namespacePair; + } + }; + try + { + return txnHelper.doInTransaction(callback, !autoCreate, false); + } + catch (Throwable e) + { + if (expectSuccess) + { + // oops + throw new RuntimeException("Expected to get namespace '" + uri + "'.", e); + } + else + { + return null; + } + } + } + + private Pair getQName(final QName qname, final boolean autoCreate, boolean expectSuccess) + { + RetryingTransactionCallback> callback = new RetryingTransactionCallback>() + { + public Pair execute() throws Throwable + { + Pair qnamePair = null; + if (autoCreate) + { + qnamePair = qnameDAO.getOrCreateQName(qname); + } + else + { + qnamePair = qnameDAO.getQName(qname); + } + return qnamePair; + } + }; + try + { + return txnHelper.doInTransaction(callback, !autoCreate, false); + } + catch (Throwable e) + { + if (expectSuccess) + { + // oops + throw new RuntimeException("Expected to get qname '" + qname + "'.", e); + } + else + { + return null; + } + } + } + + public void testCreateNamespace() throws Exception + { + // Create a namespace + String uri = GUID.generate(); + Pair namespacePair = getNamespace(uri, true, true); + // Check that it can be retrieved + Pair namespacePairCheck = getNamespace(namespacePair.getSecond(), false, true); + assertEquals("Namespace ID changed", namespacePair.getFirst(), namespacePairCheck.getFirst()); + // Check the duplicate checking + getNamespace(uri, true, false); + } + + public void testCreateNamespaceEmpty() throws Exception + { + // Create a namespace + String uri = ""; + Pair namespacePair = getNamespace(uri, true, true); + // Check that it can be retrieved + Pair namespacePairCheck = getNamespace(namespacePair.getSecond(), false, true); + assertEquals("Namespace ID changed", namespacePair.getFirst(), namespacePairCheck.getFirst()); + } + + public void testUpdateNamespace() throws Exception + { + // Create a namespace + final String uri = GUID.generate(); + Pair namespacePair = getNamespace(uri, true, true); + // Use namespace in a QName + QName qnameOld = QName.createQName(uri, GUID.generate()); + Pair qnameOldPair = getQName(qnameOld, true, true); + // Now update it + final String uri2 = GUID.generate(); + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + qnameDAO.updateNamespace(uri, uri2); + return null; + } + }; + transactionService.getRetryingTransactionHelper().doInTransaction(callback); + + // Make sure that the old QName is gone (checks caching) + getQName(qnameOld, false, false); + + // The new QName should be there + QName qnameNew = QName.createQName(uri2, qnameOld.getLocalName()); + getQName(qnameNew, false, true); + + // Should be able to create the original namespace again + Pair namespacePairAgain = getNamespace(uri, true, true); + assertNotSame("Should have a new namespace ID", namespacePair.getFirst(), namespacePairAgain.getFirst()); + } + + public void testCreateQName() throws Exception + { + // Create a qname + QName qname = QName.createQName(getName(), GUID.generate()); + Pair qnamePair = getQName(qname, true, true); + // Check that it can be retrieved + Pair qnamePairCheck = getQName(qnamePair.getSecond(), false, true); + assertEquals("QName ID changed", qnamePair.getFirst(), qnamePairCheck.getFirst()); + // Check the duplicate checking + getQName(qname, true, false); + } + + public void testUpdateQName() throws Exception + { + // Create a qname + final QName qnameOld = QName.createQName(GUID.generate(), GUID.generate()); + Pair qnamePairOld = getQName(qnameOld, true, true); + // Now update it + final QName qnameNew = QName.createQName(GUID.generate(), GUID.generate()); + RetryingTransactionCallback> callback = new RetryingTransactionCallback>() + { + public Pair execute() throws Throwable + { + return qnameDAO.updateQName(qnameOld, qnameNew); + } + }; + Pair qnamePairNew = transactionService.getRetryingTransactionHelper().doInTransaction(callback); + // The ID must be the same + assertEquals("New QName is incorrect", qnameNew, qnamePairNew.getSecond()); + assertEquals("ID did not remain the same", qnamePairOld.getFirst(), qnamePairNew.getFirst()); + // The old QName should not be there + getQName(qnameOld, false, false); + // The new QName should be there + getQName(qnameNew, false, true); + } +} diff --git a/source/java/org/alfresco/repo/domain/qname/QNameEntity.java b/source/java/org/alfresco/repo/domain/qname/QNameEntity.java new file mode 100644 index 0000000000..8771ac4a85 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/qname/QNameEntity.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.qname; + +import org.alfresco.util.EqualsHelper; + +/** + * Entity for alf_qname persistence. + * + * @author Derek Hulley + * @since 3.3 + */ +public class QNameEntity +{ + public static final String EMPTY_LOCALNAME_SUBSTITUTE = ".empty"; + public static final Long CONST_LONG_ZERO = new Long(0L); + + private Long id; + private Long version; + private Long namespaceId; + private String localName; + + public QNameEntity() + { + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("QNameEntity") + .append("[ id=").append(id) + .append(", nsId=").append(namespaceId) + .append(", localName=").append(localName) + .append("]"); + return sb.toString(); + } + + public void incrementVersion() + { + if (version >= Short.MAX_VALUE) + { + this.version = 0L; + } + else + { + this.version++; + } + } + + public Long getId() + { + return id; + } + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + public void setVersion(Long version) + { + this.version = version; + } + + public Long getNamespaceId() + { + return namespaceId; + } + public void setNamespaceId(Long namespaceId) + { + this.namespaceId = namespaceId; + } + + public String getLocalName() + { + return localName; + } + public void setLocalName(String localName) + { + this.localName = localName; + } + + /** + * Convenience getter to interpret the {@link #EMPTY_LOCALNAME_SUBSTITUTE} + */ + public String getLocalNameSafe() + { + if (EqualsHelper.nullSafeEquals(localName, QNameEntity.EMPTY_LOCALNAME_SUBSTITUTE)) + { + return ""; + } + else + { + return localName; + } + } + /** + * Convenience setter to interpret the {@link #EMPTY_LOCALNAME_SUBSTITUTE} + */ + public void setLocalNameSafe(String localName) + { + this.localName = (localName.length() == 0) ? QNameEntity.EMPTY_LOCALNAME_SUBSTITUTE : localName; + } +} diff --git a/source/java/org/alfresco/repo/domain/qname/ibatis/QNameDAOImpl.java b/source/java/org/alfresco/repo/domain/qname/ibatis/QNameDAOImpl.java new file mode 100644 index 0000000000..0e23bc8b48 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/qname/ibatis/QNameDAOImpl.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.qname.ibatis; + +import org.alfresco.repo.domain.qname.AbstractQNameDAOImpl; +import org.alfresco.repo.domain.qname.NamespaceEntity; +import org.alfresco.repo.domain.qname.QNameEntity; +import org.springframework.orm.ibatis.SqlMapClientTemplate; + +/** + * iBatis-specific extension of the QName and Namespace abstract DAO + * + * @author Derek Hulley + * @since 3.3 + */ +public class QNameDAOImpl extends AbstractQNameDAOImpl +{ + private static final String SELECT_NS_BY_ID = "alfresco.qname.select_NamespaceById"; + private static final String SELECT_NS_BY_URI = "alfresco.qname.select_NamespaceByUri"; + private static final String INSERT_NS = "alfresco.qname.insert_Namespace"; + private static final String UPDATE_NS = "alfresco.qname.update_Namespace"; + private static final String SELECT_QNAME_BY_ID = "alfresco.qname.select_QNameById"; + private static final String SELECT_QNAME_BY_NS_AND_LOCALNAME = "alfresco.qname.select_QNameByNsAndLocalName"; + private static final String INSERT_QNAME = "alfresco.qname.insert_QName"; + private static final String UPDATE_QNAME = "alfresco.qname.update_QName"; + + private SqlMapClientTemplate template; + + public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) + { + this.template = sqlMapClientTemplate; + } + + @Override + protected NamespaceEntity findNamespaceEntityById(Long id) + { + NamespaceEntity entity = new NamespaceEntity(); + entity.setId(id); + entity = (NamespaceEntity) template.queryForObject(SELECT_NS_BY_ID, entity); + return entity; + } + + @Override + protected NamespaceEntity findNamespaceEntityByUri(String uri) + { + NamespaceEntity entity = new NamespaceEntity(); + entity.setUriSafe(uri); + entity = (NamespaceEntity) template.queryForObject(SELECT_NS_BY_URI, entity); + return entity; + } + + @Override + protected NamespaceEntity createNamespaceEntity(String uri) + { + NamespaceEntity entity = new NamespaceEntity(); + entity.setVersion(NamespaceEntity.CONST_LONG_ZERO); + entity.setUriSafe(uri); + template.insert(INSERT_NS, entity); + return entity; + } + + @Override + protected int updateNamespaceEntity(NamespaceEntity entity, String uri) + { + entity.setUriSafe(uri); + entity.incrementVersion(); + return template.update(UPDATE_NS, entity); + } + + @Override + protected QNameEntity findQNameEntityById(Long id) + { + QNameEntity entity = new QNameEntity(); + entity.setId(id); + entity = (QNameEntity) template.queryForObject(SELECT_QNAME_BY_ID, entity); + return entity; + } + + @Override + protected QNameEntity findQNameEntityByNamespaceAndLocalName(Long nsId, String localName) + { + QNameEntity entity = new QNameEntity(); + entity.setNamespaceId(nsId); + entity.setLocalNameSafe(localName); + entity = (QNameEntity) template.queryForObject(SELECT_QNAME_BY_NS_AND_LOCALNAME, entity); + return entity; + } + + @Override + protected QNameEntity createQNameEntity(Long nsId, String localName) + { + QNameEntity entity = new QNameEntity(); + entity.setVersion(QNameEntity.CONST_LONG_ZERO); + entity.setNamespaceId(nsId); + entity.setLocalNameSafe(localName); + template.insert(INSERT_QNAME, entity); + return entity; + } + + @Override + protected int updateQNameEntity(QNameEntity entity, Long nsId, String localName) + { + entity.setNamespaceId(nsId); + entity.setLocalNameSafe(localName); + entity.incrementVersion(); + return template.update(UPDATE_QNAME, entity); + } +} diff --git a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java index 8fff95bdc2..c62ccdfc96 100644 --- a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java @@ -59,7 +59,7 @@ import org.alfresco.repo.domain.NodeAssoc; import org.alfresco.repo.domain.NodePropertyValue; import org.alfresco.repo.domain.PropertyMapKey; import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.QNameDAO; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.domain.Server; import org.alfresco.repo.domain.Store; import org.alfresco.repo.domain.Transaction; diff --git a/source/java/org/alfresco/service/namespace/QName.java b/source/java/org/alfresco/service/namespace/QName.java index ffe91d28ea..6ea494fd46 100644 --- a/source/java/org/alfresco/service/namespace/QName.java +++ b/source/java/org/alfresco/service/namespace/QName.java @@ -27,7 +27,7 @@ package org.alfresco.service.namespace; import java.io.Serializable; import java.util.Collection; -import org.alfresco.repo.domain.hibernate.NamespaceEntityImpl; +import org.alfresco.repo.domain.qname.NamespaceEntity; /** * QName represents the qualified name of a Repository item. Each @@ -231,7 +231,7 @@ public final class QName implements QNamePattern, Serializable, Cloneable, Compa */ private QName(String namespace, String name, String prefix) { - this.namespaceURI = ((namespace == null) || (namespace.equals(NamespaceEntityImpl.EMPTY_URI_SUBSTITUTE))) ? NamespaceService.DEFAULT_URI : namespace; + this.namespaceURI = ((namespace == null) || (namespace.equals(NamespaceEntity.EMPTY_URI_SUBSTITUTE))) ? NamespaceService.DEFAULT_URI : namespace; this.prefix = prefix; this.localName = name; this.hashCode = 0;