mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V3.2 to HEAD
17163: org.alfresco.repo.domain.hibernate.AclDaoComponentImpl.updateAuthority() needs to flush/dirty the session in order to work 17160: Fix HeartBeat - Lazy initialization in scheduled job needed its own transaction 17146: Fix failing unit tests - HibernateNodeDaoServiceImpl.moveNodeToStore() must invalidate parentAssocsCache now that it contains NodeRefs 17145: Fixes to patches for new CRC schema changes - Sequenced patch.fixNameCrcValues-2 before all other patches - Fixed typos in schema upgrade script and added CRCs for the repository descriptor nodes, so that the descriptor service and patch service can boot up - HeartBeat initializes lazily so that it doesn't try to load information before the patch service has bootstrapped - Made FixNameCrcValuesPatch industrial strength by using BatchProcessor to handle multi threading, progress reporting and transaction delineation 17097: Removal of spurious logs directory accidentally introduced in 17096 17096: Performance tuning for improved throughput during high volume import from LDAP directory - Lucene indexer will now no longer index and then reindex the same node in the same transaction - lucene.indexer.mergerTargetOverlaysBlockingFactor reduced to 1 (improves indexing performance and no excessive throttling observed during 10 hour test) - HomeFolderManager fixed so that it pays attention to the eager home folder creation flag - HibernateNodeDaoServiceImpl.parentAssocsCache 'upgraded' to hold information about root nodes and node refs so that recursive methods such as prependPaths can run entirely out of the cache - Boolean argument added to getChildAssocs() so that preloading of all child nodes is optional - qname_crc column added to alf_child_assoc to allow efficient lookup and indexing of child associations by QName. CRC of (qname_namespace, qname_localname). - idx_alf_cass_qnln on qname_localname replaced with idx_alf_cass_qncrc (qname_crc, type_qname_id, parent_node_id) - All node service lookup queries involving qname_localname modified to include qname_crc in WHERE clause - schema patch provided - existing org.alfresco.repo.admin.patch.impl.FixNameCrcValuesPatch extended to also fill in qname_crc column and forced to run on newer schemas - Optimized ChainingUserRegistrySynchronizer so that it doesn't have to look up the entire set of authorities during an 'empty' incremental sync - ChainingUserRegistrySynchronizer no longer starts an outer transaction around all its smaller transactions (used to die due to timeout) - rule service disabled for LDAP batch processing threads - org.alfresco.cache.parentAssocsCache and org.alfresco.cache.storeAndNodeIdCache size increased to 80,000 - Fixed case sensitivity issue with person caching in PersonServiceImpl - Cache the people container in PersonServiceImpl for faster person lookups - PersonDAO removed and replaced with now more efficient node service child assoc lookup methods git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@17168 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -81,6 +81,7 @@
|
|||||||
<value>classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-PropertyValueTables.sql</value>
|
<value>classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-PropertyValueTables.sql</value>
|
||||||
<value>classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-AuditTables.sql</value>
|
<value>classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-AuditTables.sql</value>
|
||||||
<value>classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-AvmTables.sql</value>
|
<value>classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-AvmTables.sql</value>
|
||||||
|
<value>classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-Indexes.sql</value>
|
||||||
</list>
|
</list>
|
||||||
</property>
|
</property>
|
||||||
<property name="validateUpdateScriptPatches">
|
<property name="validateUpdateScriptPatches">
|
||||||
@@ -103,6 +104,7 @@
|
|||||||
<ref bean="patch.db-V3.2-ContentTables" />
|
<ref bean="patch.db-V3.2-ContentTables" />
|
||||||
<ref bean="patch.db-V3.2-PropertyValueTables" />
|
<ref bean="patch.db-V3.2-PropertyValueTables" />
|
||||||
<ref bean="patch.db-V3.2-AuditTables" />
|
<ref bean="patch.db-V3.2-AuditTables" />
|
||||||
|
<ref bean="patch.db-V3.2-Child-Assoc-QName-CRC" />
|
||||||
</list>
|
</list>
|
||||||
</property>
|
</property>
|
||||||
<property name="postUpdateScriptPatches">
|
<property name="postUpdateScriptPatches">
|
||||||
|
@@ -311,7 +311,7 @@
|
|||||||
<value>org.alfresco.parentAssocsTransactionalCache</value>
|
<value>org.alfresco.parentAssocsTransactionalCache</value>
|
||||||
</property>
|
</property>
|
||||||
<property name="maxCacheSize">
|
<property name="maxCacheSize">
|
||||||
<value>10000</value>
|
<value>80000</value>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
@@ -0,0 +1,11 @@
|
|||||||
|
--
|
||||||
|
-- Title: Additional Indexes
|
||||||
|
-- Database: Generic
|
||||||
|
-- Since: V3.2 schema 2023
|
||||||
|
-- Author: davew
|
||||||
|
--
|
||||||
|
-- Please contact support@alfresco.com if you need assistance with the upgrade.
|
||||||
|
--
|
||||||
|
-- Additional indexes
|
||||||
|
|
||||||
|
CREATE INDEX idx_alf_cass_qncrc on alf_child_assoc (qname_crc, type_qname_id, parent_node_id);
|
@@ -0,0 +1,44 @@
|
|||||||
|
--
|
||||||
|
-- Title: Upgrade to V3.2 - Add qname_crc column to alf_child_assoc
|
||||||
|
-- Database: MySQL
|
||||||
|
-- Since: V3.2 schema 2023
|
||||||
|
-- Author: davew
|
||||||
|
--
|
||||||
|
-- Add qname_crc column to alf_child_assoc and change indexes
|
||||||
|
--
|
||||||
|
-- Please contact support@alfresco.com if you need assistance with the upgrade.
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE alf_child_assoc
|
||||||
|
ADD COLUMN qname_crc BIGINT NOT NULL DEFAULT 0 AFTER qname_localname
|
||||||
|
;
|
||||||
|
|
||||||
|
-- Enable additional patches to run by CRC-ing the descriptor nodes
|
||||||
|
UPDATE alf_child_assoc
|
||||||
|
SET qname_crc = 147310537
|
||||||
|
WHERE qname_ns_id = (SELECT id FROM alf_namespace WHERE uri = 'http://www.alfresco.org/model/system/1.0')
|
||||||
|
AND qname_localname = 'descriptor';
|
||||||
|
|
||||||
|
UPDATE alf_child_assoc
|
||||||
|
SET qname_crc = 369154895
|
||||||
|
WHERE qname_ns_id = (SELECT id FROM alf_namespace WHERE uri = 'http://www.alfresco.org/model/system/1.0')
|
||||||
|
AND qname_localname = 'descriptor-current';
|
||||||
|
|
||||||
|
ALTER TABLE alf_child_assoc
|
||||||
|
DROP INDEX idx_alf_cass_qnln,
|
||||||
|
ALTER COLUMN qname_crc DROP DEFAULT
|
||||||
|
;
|
||||||
|
|
||||||
|
CREATE INDEX idx_alf_cass_qncrc ON alf_child_assoc (qname_crc, type_qname_id, parent_node_id);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Record script finish
|
||||||
|
--
|
||||||
|
DELETE FROM alf_applied_patch WHERE id = 'patch.db-V3.2-Child-Assoc-QName-CRC';
|
||||||
|
INSERT INTO alf_applied_patch
|
||||||
|
(id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
'patch.db-V3.2-Child-Assoc-QName-CRC', 'Manually executed script upgrade V3.2 to Add qname_crc column to alf_child_assoc and change indexes',
|
||||||
|
0, 3005, -1, 3006, null, 'UNKOWN', 1, 1, 'Script completed'
|
||||||
|
);
|
@@ -277,13 +277,13 @@
|
|||||||
/>
|
/>
|
||||||
<cache
|
<cache
|
||||||
name="org.alfresco.cache.storeAndNodeIdCache"
|
name="org.alfresco.cache.storeAndNodeIdCache"
|
||||||
maxElementsInMemory="50000"
|
maxElementsInMemory="80000"
|
||||||
eternal="true"
|
eternal="true"
|
||||||
overflowToDisk="false"
|
overflowToDisk="false"
|
||||||
/>
|
/>
|
||||||
<cache
|
<cache
|
||||||
name="org.alfresco.cache.parentAssocsCache"
|
name="org.alfresco.cache.parentAssocsCache"
|
||||||
maxElementsInMemory="50000"
|
maxElementsInMemory="80000"
|
||||||
eternal="true"
|
eternal="true"
|
||||||
overflowToDisk="false"
|
overflowToDisk="false"
|
||||||
/>
|
/>
|
||||||
|
@@ -537,7 +537,7 @@
|
|||||||
|
|
||||||
<cache
|
<cache
|
||||||
name="org.alfresco.cache.storeAndNodeIdCache"
|
name="org.alfresco.cache.storeAndNodeIdCache"
|
||||||
maxElementsInMemory="50000"
|
maxElementsInMemory="80000"
|
||||||
eternal="true"
|
eternal="true"
|
||||||
overflowToDisk="false">
|
overflowToDisk="false">
|
||||||
|
|
||||||
@@ -642,7 +642,7 @@
|
|||||||
|
|
||||||
<cache
|
<cache
|
||||||
name="org.alfresco.cache.parentAssocsCache"
|
name="org.alfresco.cache.parentAssocsCache"
|
||||||
maxElementsInMemory="50000"
|
maxElementsInMemory="80000"
|
||||||
eternal="true"
|
eternal="true"
|
||||||
overflowToDisk="false">
|
overflowToDisk="false">
|
||||||
|
|
||||||
|
@@ -278,10 +278,10 @@ patch.authorityDefaultZonesPatch.result=Unzoned groups and people added to the d
|
|||||||
patch.authorityDefaultZonesPatch.users= Adding users to zones ...
|
patch.authorityDefaultZonesPatch.users= Adding users to zones ...
|
||||||
patch.authorityDefaultZonesPatch.groups= Adding groups to zones ...
|
patch.authorityDefaultZonesPatch.groups= Adding groups to zones ...
|
||||||
|
|
||||||
patch.fixNameCrcValues.description=Fixes name CRC32 values to match UTF-8 encoding.
|
patch.fixNameCrcValues.description=Fixes name and qname CRC32 values to match UTF-8 encoding.
|
||||||
patch.fixNameCrcValues.result=Fixed {0} name CRC32 values for UTF-8 encoding. See file {1} for details.
|
patch.fixNameCrcValues.result=Fixed CRC32 values for UTF-8 encoding for {0} node child associations. See file {1} for details.
|
||||||
patch.fixNameCrcValues.fixed=Updated CRC32 value for node ID {0}, name ''{1}'': {2} -> {3}.
|
patch.fixNameCrcValues.fixed=Updated CRC32 values for node ID {0}, name ''{1}'': {2} -> {3}, qname ''{4}'': {5} -> {6}.
|
||||||
patch.fixNameCrcValues.unableToChange=Failed to update the CRC32 value for node ID {0}: \n Node name: {1} \n CRC old: {2} \n CRC new: {3} \n Error: {4}
|
patch.fixNameCrcValues.unableToChange=Failed to update the CRC32 value for node ID {0}: \n Node name: {1} \n name CRC old: {2} \n name CRC new: {3} \n qname CRC old: {4} \n qname CRC new: {5} \n Error: {6}
|
||||||
|
|
||||||
patch.personUsagePatch.description=Add person 'cm:sizeCurrent' property (if missing).
|
patch.personUsagePatch.description=Add person 'cm:sizeCurrent' property (if missing).
|
||||||
patch.personUsagePatch.result1=Added 'cm:sizeCurrent' property to {0} people that were missing this property.
|
patch.personUsagePatch.result1=Added 'cm:sizeCurrent' property to {0} people that were missing this property.
|
||||||
|
@@ -121,6 +121,11 @@
|
|||||||
<property name="messageSource">
|
<property name="messageSource">
|
||||||
<ref bean="bootstrapSpacesMessageSource" />
|
<ref bean="bootstrapSpacesMessageSource" />
|
||||||
</property>
|
</property>
|
||||||
|
<property name="dependsOn" >
|
||||||
|
<list>
|
||||||
|
<ref bean="patch.fixNameCrcValues-2" />
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
<bean id="patch.savedSearchesPermission" class="org.alfresco.repo.admin.patch.impl.SavedSearchPermissionPatch" parent="basePatch" >
|
<bean id="patch.savedSearchesPermission" class="org.alfresco.repo.admin.patch.impl.SavedSearchPermissionPatch" parent="basePatch" >
|
||||||
<property name="id"><value>patch.savedSearchesPermission</value></property>
|
<property name="id"><value>patch.savedSearchesPermission</value></property>
|
||||||
@@ -1790,6 +1795,11 @@
|
|||||||
<prop key="location">alfresco/bootstrap/alfrescoAuthorityStore.xml</prop>
|
<prop key="location">alfresco/bootstrap/alfrescoAuthorityStore.xml</prop>
|
||||||
</props>
|
</props>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="dependsOn" >
|
||||||
|
<list>
|
||||||
|
<ref bean="patch.fixNameCrcValues-2" />
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="patch.authorityMigration" class="org.alfresco.repo.admin.patch.impl.AuthorityMigrationPatch" parent="basePatch" >
|
<bean id="patch.authorityMigration" class="org.alfresco.repo.admin.patch.impl.AuthorityMigrationPatch" parent="basePatch" >
|
||||||
@@ -1836,30 +1846,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean id="patch.fixNameCrcValues" class="org.alfresco.repo.admin.patch.impl.FixNameCrcValuesPatch" parent="basePatch" >
|
|
||||||
<property name="id"><value>patch.fixNameCrcValues</value></property>
|
|
||||||
<property name="description"><value>patch.fixNameCrcValues.description</value></property>
|
|
||||||
<property name="fixesFromSchema"><value>0</value></property>
|
|
||||||
<property name="fixesToSchema"><value>2014</value></property>
|
|
||||||
<property name="targetSchema"><value>2015</value></property>
|
|
||||||
<property name="dependsOn" >
|
|
||||||
<list>
|
|
||||||
<ref bean="patch.uniqueChildName" />
|
|
||||||
<ref bean="patch.InvalidNameEnding" />
|
|
||||||
</list>
|
|
||||||
</property>
|
|
||||||
<!-- helper beans -->
|
|
||||||
<property name="sessionFactory">
|
|
||||||
<ref bean="sessionFactory" />
|
|
||||||
</property>
|
|
||||||
<property name="nodeDaoService">
|
|
||||||
<ref bean="nodeDaoService" />
|
|
||||||
</property>
|
|
||||||
<property name="qnameDAO">
|
|
||||||
<ref bean="qnameDAO" />
|
|
||||||
</property>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="patch.db-V3.2-ContentTables" class="org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch" parent="basePatch">
|
<bean id="patch.db-V3.2-ContentTables" class="org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch" parent="basePatch">
|
||||||
<property name="id"><value>patch.db-V3.2-ContentTables</value></property>
|
<property name="id"><value>patch.db-V3.2-ContentTables</value></property>
|
||||||
<property name="description"><value>patch.schemaUpgradeScript.description</value></property>
|
<property name="description"><value>patch.schemaUpgradeScript.description</value></property>
|
||||||
@@ -1968,4 +1954,45 @@
|
|||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="patch.db-V3.2-Child-Assoc-QName-CRC" class="org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch" parent="basePatch">
|
||||||
|
<property name="id"><value>patch.db-V3.2-Child-Assoc-QName-CRC</value></property>
|
||||||
|
<property name="description"><value>patch.schemaUpgradeScript.description</value></property>
|
||||||
|
<property name="fixesFromSchema"><value>0</value></property>
|
||||||
|
<property name="fixesToSchema"><value>3005</value></property>
|
||||||
|
<property name="targetSchema"><value>3006</value></property>
|
||||||
|
<property name="scriptUrl">
|
||||||
|
<value>classpath:alfresco/dbscripts/upgrade/3.2/${db.script.dialect}/child-assoc-qname-crc.sql</value>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
<!-- Patch definitions -->
|
||||||
|
<!-- -->
|
||||||
|
|
||||||
|
<bean id="patch.fixNameCrcValues-2" class="org.alfresco.repo.admin.patch.impl.FixNameCrcValuesPatch" parent="basePatch" >
|
||||||
|
<property name="id"><value>patch.fixNameCrcValues-2</value></property>
|
||||||
|
<property name="description"><value>patch.fixNameCrcValues.description</value></property>
|
||||||
|
<property name="fixesFromSchema"><value>0</value></property>
|
||||||
|
<property name="fixesToSchema"><value>3006</value></property>
|
||||||
|
<property name="targetSchema"><value>3007</value></property>
|
||||||
|
<property name="dependsOn" >
|
||||||
|
<list>
|
||||||
|
<ref bean="patch.uniqueChildName" />
|
||||||
|
<ref bean="patch.InvalidNameEnding" />
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
<!-- helper beans -->
|
||||||
|
<property name="sessionFactory">
|
||||||
|
<ref bean="sessionFactory" />
|
||||||
|
</property>
|
||||||
|
<property name="nodeDaoService">
|
||||||
|
<ref bean="nodeDaoService" />
|
||||||
|
</property>
|
||||||
|
<property name="qnameDAO">
|
||||||
|
<ref bean="qnameDAO" />
|
||||||
|
</property>
|
||||||
|
<property name="ruleService">
|
||||||
|
<ref bean="ruleService" />
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
</beans>
|
</beans>
|
||||||
|
@@ -1488,34 +1488,6 @@
|
|||||||
</props>
|
</props>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<!-- The public user registry synchronizer. -->
|
|
||||||
<bean id="userRegistrySynchronizerWriteTxnAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
|
|
||||||
<property name="advice">
|
|
||||||
<ref bean="retryingWriteTxnAdvice"/>
|
|
||||||
</property>
|
|
||||||
<property name="mappedNames">
|
|
||||||
<list>
|
|
||||||
<value>synchronize</value>
|
|
||||||
</list>
|
|
||||||
</property>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="UserRegistrySynchronizer" class="org.springframework.aop.framework.ProxyFactoryBean">
|
|
||||||
<property name="proxyInterfaces">
|
|
||||||
<value>org.alfresco.repo.security.sync.UserRegistrySynchronizer</value>
|
|
||||||
</property>
|
|
||||||
<property name="target">
|
|
||||||
<ref bean="userRegistrySynchronizer" />
|
|
||||||
</property>
|
|
||||||
<property name="interceptorNames">
|
|
||||||
<list>
|
|
||||||
<value>userRegistrySynchronizerWriteTxnAdvisor</value>
|
|
||||||
<!--value>userRegistrySynchronizerReadTxnAdvisor</value-->
|
|
||||||
<value>checkTxnAdvisor</value>
|
|
||||||
</list>
|
|
||||||
</property>
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
<bean id="PublicServiceAccessService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
<bean id="PublicServiceAccessService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||||
<property name="proxyInterfaces">
|
<property name="proxyInterfaces">
|
||||||
|
@@ -189,7 +189,7 @@ lucene.indexer.writerMinMergeDocs=1000
|
|||||||
#
|
#
|
||||||
lucene.indexer.mergerTargetIndexCount=5
|
lucene.indexer.mergerTargetIndexCount=5
|
||||||
lucene.indexer.mergerTargetOverlayCount=5
|
lucene.indexer.mergerTargetOverlayCount=5
|
||||||
lucene.indexer.mergerTargetOverlaysBlockingFactor=2
|
lucene.indexer.mergerTargetOverlaysBlockingFactor=1
|
||||||
lucene.indexer.maxDocsForInMemoryMerge=10000
|
lucene.indexer.maxDocsForInMemoryMerge=10000
|
||||||
#
|
#
|
||||||
# Other lucene properties
|
# Other lucene properties
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
<property name="jobDataAsMap">
|
<property name="jobDataAsMap">
|
||||||
<map>
|
<map>
|
||||||
<entry key="userRegistrySynchronizer">
|
<entry key="userRegistrySynchronizer">
|
||||||
<ref bean="UserRegistrySynchronizer" />
|
<ref bean="userRegistrySynchronizer" />
|
||||||
</entry>
|
</entry>
|
||||||
<entry key="synchronizeChangesOnly">
|
<entry key="synchronizeChangesOnly">
|
||||||
<value>${synchronization.synchronizeChangesOnly}</value>
|
<value>${synchronization.synchronizeChangesOnly}</value>
|
||||||
@@ -59,6 +59,9 @@
|
|||||||
<property name="retryingTransactionHelper">
|
<property name="retryingTransactionHelper">
|
||||||
<ref bean="retryingTransactionHelper" />
|
<ref bean="retryingTransactionHelper" />
|
||||||
</property>
|
</property>
|
||||||
|
<property name="ruleService">
|
||||||
|
<ref bean="ruleService" />
|
||||||
|
</property>
|
||||||
<property name="jobLockService">
|
<property name="jobLockService">
|
||||||
<ref bean="jobLockService" />
|
<ref bean="jobLockService" />
|
||||||
</property>
|
</property>
|
||||||
|
@@ -19,4 +19,4 @@ version.build=@build-number@
|
|||||||
|
|
||||||
# Schema number
|
# Schema number
|
||||||
|
|
||||||
version.schema=3005
|
version.schema=3007
|
||||||
|
@@ -43,7 +43,11 @@ import org.alfresco.repo.domain.Node;
|
|||||||
import org.alfresco.repo.domain.QNameDAO;
|
import org.alfresco.repo.domain.QNameDAO;
|
||||||
import org.alfresco.repo.domain.hibernate.ChildAssocImpl;
|
import org.alfresco.repo.domain.hibernate.ChildAssocImpl;
|
||||||
import org.alfresco.repo.node.db.NodeDaoService;
|
import org.alfresco.repo.node.db.NodeDaoService;
|
||||||
|
import org.alfresco.repo.security.sync.BatchProcessor;
|
||||||
|
import org.alfresco.repo.security.sync.BatchProcessor.Worker;
|
||||||
import org.alfresco.service.cmr.admin.PatchException;
|
import org.alfresco.service.cmr.admin.PatchException;
|
||||||
|
import org.alfresco.service.cmr.rule.RuleService;
|
||||||
|
import org.alfresco.service.namespace.QName;
|
||||||
import org.hibernate.SQLQuery;
|
import org.hibernate.SQLQuery;
|
||||||
import org.hibernate.ScrollMode;
|
import org.hibernate.ScrollMode;
|
||||||
import org.hibernate.ScrollableResults;
|
import org.hibernate.ScrollableResults;
|
||||||
@@ -51,17 +55,19 @@ import org.hibernate.Session;
|
|||||||
import org.hibernate.SessionFactory;
|
import org.hibernate.SessionFactory;
|
||||||
import org.hibernate.type.LongType;
|
import org.hibernate.type.LongType;
|
||||||
import org.hibernate.type.StringType;
|
import org.hibernate.type.StringType;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.context.ApplicationEventPublisherAware;
|
||||||
import org.springframework.orm.hibernate3.HibernateCallback;
|
import org.springframework.orm.hibernate3.HibernateCallback;
|
||||||
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
|
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fixes <a href=https://issues.alfresco.com/jira/browse/ETWOTWO-1133>ETWOTWO-1133</a>.
|
* Fixes <a href=https://issues.alfresco.com/jira/browse/ETWOTWO-1133>ETWOTWO-1133</a>.
|
||||||
* Checks all CRC values for <b>alf_child_assoc.child_node_name_crc</b>.
|
* Checks all CRC values for <b>alf_child_assoc.child_node_name_crc and alf_child_assoc.qname_crc</b>.
|
||||||
*
|
*
|
||||||
* @author Derek Hulley
|
* @author Derek Hulley
|
||||||
* @since V2.2SP4
|
* @since V2.2SP4
|
||||||
*/
|
*/
|
||||||
public class FixNameCrcValuesPatch extends AbstractPatch
|
public class FixNameCrcValuesPatch extends AbstractPatch implements ApplicationEventPublisherAware
|
||||||
{
|
{
|
||||||
private static final String MSG_SUCCESS = "patch.fixNameCrcValues.result";
|
private static final String MSG_SUCCESS = "patch.fixNameCrcValues.result";
|
||||||
private static final String MSG_REWRITTEN = "patch.fixNameCrcValues.fixed";
|
private static final String MSG_REWRITTEN = "patch.fixNameCrcValues.fixed";
|
||||||
@@ -70,6 +76,8 @@ public class FixNameCrcValuesPatch extends AbstractPatch
|
|||||||
private SessionFactory sessionFactory;
|
private SessionFactory sessionFactory;
|
||||||
private NodeDaoService nodeDaoService;
|
private NodeDaoService nodeDaoService;
|
||||||
private QNameDAO qnameDAO;
|
private QNameDAO qnameDAO;
|
||||||
|
private RuleService ruleService;
|
||||||
|
private ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
public FixNameCrcValuesPatch()
|
public FixNameCrcValuesPatch()
|
||||||
{
|
{
|
||||||
@@ -95,6 +103,22 @@ public class FixNameCrcValuesPatch extends AbstractPatch
|
|||||||
{
|
{
|
||||||
this.qnameDAO = qnameDAO;
|
this.qnameDAO = qnameDAO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ruleService the rule service
|
||||||
|
*/
|
||||||
|
public void setRuleService(RuleService ruleService)
|
||||||
|
{
|
||||||
|
this.ruleService = ruleService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher)
|
||||||
|
*/
|
||||||
|
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)
|
||||||
|
{
|
||||||
|
this.applicationEventPublisher = applicationEventPublisher;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void checkProperties()
|
protected void checkProperties()
|
||||||
@@ -103,6 +127,7 @@ public class FixNameCrcValuesPatch extends AbstractPatch
|
|||||||
checkPropertyNotNull(sessionFactory, "sessionFactory");
|
checkPropertyNotNull(sessionFactory, "sessionFactory");
|
||||||
checkPropertyNotNull(nodeDaoService, "nodeDaoService");
|
checkPropertyNotNull(nodeDaoService, "nodeDaoService");
|
||||||
checkPropertyNotNull(qnameDAO, "qnameDAO");
|
checkPropertyNotNull(qnameDAO, "qnameDAO");
|
||||||
|
checkPropertyNotNull(applicationEventPublisher, "applicationEventPublisher");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -111,7 +136,7 @@ public class FixNameCrcValuesPatch extends AbstractPatch
|
|||||||
// initialise the helper
|
// initialise the helper
|
||||||
HibernateHelper helper = new HibernateHelper();
|
HibernateHelper helper = new HibernateHelper();
|
||||||
helper.setSessionFactory(sessionFactory);
|
helper.setSessionFactory(sessionFactory);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
String msg = helper.fixCrcValues();
|
String msg = helper.fixCrcValues();
|
||||||
@@ -161,66 +186,79 @@ public class FixNameCrcValuesPatch extends AbstractPatch
|
|||||||
public String fixCrcValues() throws Exception
|
public String fixCrcValues() throws Exception
|
||||||
{
|
{
|
||||||
// get the association types to check
|
// get the association types to check
|
||||||
@SuppressWarnings("unused")
|
BatchProcessor<Long> batchProcessor = new BatchProcessor<Long>(transactionService
|
||||||
List<Long> childAssocIds = findMismatchedCrcs();
|
.getRetryingTransactionHelper(), ruleService, applicationEventPublisher, findMismatchedCrcs(),
|
||||||
|
"FixNameCrcValuesPatch", 100, 2, 20);
|
||||||
|
|
||||||
// Precautionary flush and clear so that we have an empty session
|
// Precautionary flush and clear so that we have an empty session
|
||||||
getSession().flush();
|
getSession().flush();
|
||||||
getSession().clear();
|
getSession().clear();
|
||||||
|
|
||||||
int updated = 0;
|
|
||||||
for (Long childAssocId : childAssocIds)
|
int updated = batchProcessor.process(new Worker<Long>(){
|
||||||
{
|
|
||||||
ChildAssoc assoc = (ChildAssoc) getHibernateTemplate().get(ChildAssocImpl.class, childAssocId);
|
public String getIdentifier(Long entry)
|
||||||
if (assoc == null)
|
|
||||||
{
|
{
|
||||||
// Missing now ...
|
return entry.toString();
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
// Get the old CRC
|
|
||||||
long oldCrc = assoc.getChildNodeNameCrc();
|
public void process(Long childAssocId) throws Throwable
|
||||||
// Get the child node
|
|
||||||
Node childNode = assoc.getChild();
|
|
||||||
// Get the name
|
|
||||||
String childName = (String) nodeDaoService.getNodeProperty(childNode.getId(), ContentModel.PROP_NAME);
|
|
||||||
if (childName == null)
|
|
||||||
{
|
{
|
||||||
childName = childNode.getUuid();
|
ChildAssoc assoc = (ChildAssoc) getHibernateTemplate().get(ChildAssocImpl.class, childAssocId);
|
||||||
}
|
if (assoc == null)
|
||||||
// Update the CRC
|
|
||||||
long crc = getCrc(childName);
|
|
||||||
// Update the assoc
|
|
||||||
assoc.setChildNodeNameCrc(crc);
|
|
||||||
// Persist
|
|
||||||
updated++;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
getSession().flush();
|
|
||||||
}
|
|
||||||
catch (Throwable e)
|
|
||||||
{
|
|
||||||
String msg = I18NUtil.getMessage(MSG_UNABLE_TO_CHANGE, childNode.getId(), childName, oldCrc, crc, e.getMessage());
|
|
||||||
// We just log this and add details to the message file
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
{
|
{
|
||||||
logger.debug(msg, e);
|
// Missing now ...
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
// Get the old CRCs
|
||||||
|
long oldChildCrc = assoc.getChildNodeNameCrc();
|
||||||
|
long oldQNameCrc = assoc.getQnameCrc();
|
||||||
|
|
||||||
|
// Get the child node
|
||||||
|
Node childNode = assoc.getChild();
|
||||||
|
// Get the name
|
||||||
|
String childName = (String) nodeDaoService.getNodeProperty(childNode.getId(), ContentModel.PROP_NAME);
|
||||||
|
if (childName == null)
|
||||||
{
|
{
|
||||||
logger.warn(msg);
|
childName = childNode.getUuid();
|
||||||
}
|
}
|
||||||
writeLine(msg);
|
// Update the CRCs
|
||||||
}
|
long childCrc = getCrc(childName);
|
||||||
getSession().clear();
|
long qnameCrc = ChildAssocImpl.getCrc(assoc.getQName(qnameDAO));
|
||||||
// Record
|
|
||||||
writeLine(I18NUtil.getMessage(MSG_REWRITTEN, childNode.getId(), childName, oldCrc, crc));
|
// Update the assoc
|
||||||
}
|
assoc.setChildNodeNameCrc(childCrc);
|
||||||
|
assoc.setQnameCrc(qnameCrc);
|
||||||
|
// Persist
|
||||||
|
try
|
||||||
|
{
|
||||||
|
getSession().flush();
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
String msg = I18NUtil.getMessage(MSG_UNABLE_TO_CHANGE, childNode.getId(), childName, oldChildCrc,
|
||||||
|
childCrc, oldQNameCrc, qnameCrc, e.getMessage());
|
||||||
|
// We just log this and add details to the message file
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug(msg, e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.warn(msg);
|
||||||
|
}
|
||||||
|
writeLine(msg);
|
||||||
|
}
|
||||||
|
getSession().clear();
|
||||||
|
// Record
|
||||||
|
writeLine(I18NUtil.getMessage(MSG_REWRITTEN, childNode.getId(), childName, oldChildCrc, childCrc, oldQNameCrc, qnameCrc));
|
||||||
|
}}, true);
|
||||||
|
|
||||||
|
|
||||||
String msg = I18NUtil.getMessage(MSG_SUCCESS, updated, logFile);
|
String msg = I18NUtil.getMessage(MSG_SUCCESS, updated, logFile);
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private List<Long> findMismatchedCrcs() throws Exception
|
private List<Long> findMismatchedCrcs() throws Exception
|
||||||
{
|
{
|
||||||
final Long qnameId = qnameDAO.getOrCreateQName(ContentModel.PROP_NAME).getFirst();
|
final Long qnameId = qnameDAO.getOrCreateQName(ContentModel.PROP_NAME).getFirst();
|
||||||
@@ -236,17 +274,23 @@ public class FixNameCrcValuesPatch extends AbstractPatch
|
|||||||
" ca.id AS child_assoc_id," +
|
" ca.id AS child_assoc_id," +
|
||||||
" ca.child_node_name_crc AS child_assoc_crc," +
|
" ca.child_node_name_crc AS child_assoc_crc," +
|
||||||
" np.string_value AS node_name," +
|
" np.string_value AS node_name," +
|
||||||
" n.uuid as node_uuid" +
|
" n.uuid as node_uuid," +
|
||||||
|
" ca.qname_crc AS qname_crc," +
|
||||||
|
" ca.qname_ns_id AS qname_ns_id," +
|
||||||
|
" ca.qname_localname AS qname_localname" +
|
||||||
" FROM" +
|
" FROM" +
|
||||||
" alf_child_assoc ca" +
|
" alf_child_assoc ca" +
|
||||||
" JOIN alf_node n ON (ca.child_node_id = n.id AND ca.child_node_name_crc > 0)" +
|
" JOIN alf_node n ON (ca.child_node_id = n.id)" +
|
||||||
" JOIN alf_node_properties np on (np.node_id = n.id AND np.qname_id = :qnameId)" +
|
" LEFT OUTER JOIN alf_node_properties np on (np.node_id = n.id AND np.qname_id = :qnameId)" +
|
||||||
"");
|
"");
|
||||||
query.setLong("qnameId", qnameId);
|
query.setLong("qnameId", qnameId);
|
||||||
query.addScalar("child_assoc_id", new LongType());
|
query.addScalar("child_assoc_id", new LongType());
|
||||||
query.addScalar("child_assoc_crc", new LongType());
|
query.addScalar("child_assoc_crc", new LongType());
|
||||||
query.addScalar("node_name", new StringType());
|
query.addScalar("node_name", new StringType());
|
||||||
query.addScalar("node_uuid", new StringType());
|
query.addScalar("node_uuid", new StringType());
|
||||||
|
query.addScalar("qname_crc", new LongType());
|
||||||
|
query.addScalar("qname_ns_id", new LongType());
|
||||||
|
query.addScalar("qname_localname", new StringType());
|
||||||
return query.scroll(ScrollMode.FORWARD_ONLY);
|
return query.scroll(ScrollMode.FORWARD_ONLY);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -256,21 +300,31 @@ public class FixNameCrcValuesPatch extends AbstractPatch
|
|||||||
rs = (ScrollableResults) getHibernateTemplate().execute(callback);
|
rs = (ScrollableResults) getHibernateTemplate().execute(callback);
|
||||||
while (rs.next())
|
while (rs.next())
|
||||||
{
|
{
|
||||||
|
// Compute child name crc
|
||||||
Long assocId = (Long) rs.get(0);
|
Long assocId = (Long) rs.get(0);
|
||||||
Long dbCrc = (Long) rs.get(1);
|
Long dbChildCrc = (Long) rs.get(1);
|
||||||
String name = (String) rs.get(2);
|
String name = (String) rs.get(2);
|
||||||
String uuid = (String) rs.get(3);
|
String uuid = (String) rs.get(3);
|
||||||
long utf8Crc = -1L;
|
long utf8ChildCrc;
|
||||||
if (name != null)
|
if (name != null)
|
||||||
{
|
{
|
||||||
utf8Crc = getCrc(name);
|
utf8ChildCrc = getCrc(name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
utf8Crc = getCrc(uuid);
|
utf8ChildCrc = getCrc(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compute qname crc
|
||||||
|
Long dbQNameCrc = (Long) rs.get(4);
|
||||||
|
Long namespaceId = (Long) rs.get(5);
|
||||||
|
String namespace = qnameDAO.getNamespace(namespaceId).getSecond();
|
||||||
|
String localName = (String) rs.get(6);
|
||||||
|
QName qname = QName.createQName(namespace, localName);
|
||||||
|
long utf8QNameCrc = ChildAssocImpl.getCrc(qname);
|
||||||
|
|
||||||
// Check
|
// Check
|
||||||
if (dbCrc != null && utf8Crc == dbCrc.longValue())
|
if (dbChildCrc != null && utf8ChildCrc == dbChildCrc.longValue() && dbQNameCrc != null && utf8QNameCrc == dbQNameCrc.longValue())
|
||||||
{
|
{
|
||||||
// It is a match, so ignore
|
// It is a match, so ignore
|
||||||
continue;
|
continue;
|
||||||
|
@@ -1648,6 +1648,14 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern,
|
||||||
|
QNamePattern qnamePattern, boolean preload) throws InvalidNodeRefException
|
||||||
|
{
|
||||||
|
return getChildAssocs(nodeRef, typeQNamePattern, qnamePattern);
|
||||||
|
}
|
||||||
|
|
||||||
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, Set<QName> childNodeTypes)
|
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, Set<QName> childNodeTypes)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@@ -158,6 +158,16 @@ public interface ChildAssoc extends Comparable<ChildAssoc>
|
|||||||
*/
|
*/
|
||||||
public void setQnameLocalName(String localName);
|
public void setQnameLocalName(String localName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the crc value for the association's local QName
|
||||||
|
*/
|
||||||
|
public long getQnameCrc();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param crc the crc value
|
||||||
|
*/
|
||||||
|
public void setQnameCrc(long crc);
|
||||||
|
|
||||||
public boolean getIsPrimary();
|
public boolean getIsPrimary();
|
||||||
|
|
||||||
public void setIsPrimary(boolean isPrimary);
|
public void setIsPrimary(boolean isPrimary);
|
||||||
|
@@ -25,9 +25,11 @@
|
|||||||
package org.alfresco.repo.domain.hibernate;
|
package org.alfresco.repo.domain.hibernate;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
import org.alfresco.repo.domain.ChildAssoc;
|
import org.alfresco.repo.domain.ChildAssoc;
|
||||||
import org.alfresco.repo.domain.Node;
|
import org.alfresco.repo.domain.Node;
|
||||||
@@ -50,6 +52,7 @@ public class ChildAssocImpl implements ChildAssoc, Serializable
|
|||||||
private Long typeQNameId;
|
private Long typeQNameId;
|
||||||
private Long qnameNamespaceId;
|
private Long qnameNamespaceId;
|
||||||
private String qnameLocalName;
|
private String qnameLocalName;
|
||||||
|
private long qnameCrc;
|
||||||
private String childNodeName;
|
private String childNodeName;
|
||||||
private long childNodeNameCrc;
|
private long childNodeNameCrc;
|
||||||
private boolean isPrimary;
|
private boolean isPrimary;
|
||||||
@@ -230,18 +233,36 @@ public class ChildAssocImpl implements ChildAssoc, Serializable
|
|||||||
String assocQNameNamespace = qname.getNamespaceURI();
|
String assocQNameNamespace = qname.getNamespaceURI();
|
||||||
String assocQNameLocalName = qname.getLocalName();
|
String assocQNameLocalName = qname.getLocalName();
|
||||||
Long assocQNameNamespaceId = qnameDAO.getOrCreateNamespace(assocQNameNamespace).getFirst();
|
Long assocQNameNamespaceId = qnameDAO.getOrCreateNamespace(assocQNameNamespace).getFirst();
|
||||||
|
Long assocQNameCrc = getCrc(qname);
|
||||||
// get write lock
|
// get write lock
|
||||||
refWriteLock.lock();
|
refWriteLock.lock();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
setQnameNamespaceId(assocQNameNamespaceId);
|
setQnameNamespaceId(assocQNameNamespaceId);
|
||||||
setQnameLocalName(assocQNameLocalName);
|
setQnameLocalName(assocQNameLocalName);
|
||||||
|
setQnameCrc(assocQNameCrc);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
refWriteLock.unlock();
|
refWriteLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long getCrc(QName qname)
|
||||||
|
{
|
||||||
|
CRC32 crc = new CRC32();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
crc.update(qname.getNamespaceURI().getBytes("UTF-8"));
|
||||||
|
crc.update(qname.getLocalName().getBytes("UTF-8"));
|
||||||
|
}
|
||||||
|
catch (UnsupportedEncodingException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("UTF-8 encoding is not supported");
|
||||||
|
}
|
||||||
|
return crc.getValue();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public boolean equals(Object obj)
|
public boolean equals(Object obj)
|
||||||
{
|
{
|
||||||
@@ -290,6 +311,7 @@ public class ChildAssocImpl implements ChildAssoc, Serializable
|
|||||||
.append(", assoc type=").append(typeQNameId)
|
.append(", assoc type=").append(typeQNameId)
|
||||||
.append(", assoc qname ns=").append(qnameNamespaceId)
|
.append(", assoc qname ns=").append(qnameNamespaceId)
|
||||||
.append(", assoc qname localname=").append(qnameLocalName)
|
.append(", assoc qname localname=").append(qnameLocalName)
|
||||||
|
.append(", assoc qname crc=").append(qnameCrc)
|
||||||
.append(", isPrimary=").append(isPrimary)
|
.append(", isPrimary=").append(isPrimary)
|
||||||
.append("]");
|
.append("]");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
@@ -461,6 +483,16 @@ public class ChildAssocImpl implements ChildAssoc, Serializable
|
|||||||
refWriteLock.unlock();
|
refWriteLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getQnameCrc()
|
||||||
|
{
|
||||||
|
return qnameCrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQnameCrc(long crc)
|
||||||
|
{
|
||||||
|
this.qnameCrc = crc;
|
||||||
|
}
|
||||||
|
|
||||||
public String getChildNodeName()
|
public String getChildNodeName()
|
||||||
{
|
{
|
||||||
|
@@ -185,7 +185,8 @@
|
|||||||
<column name="child_node_id" not-null="true"/>
|
<column name="child_node_id" not-null="true"/>
|
||||||
</many-to-one>
|
</many-to-one>
|
||||||
<property name="qnameNamespaceId" column="qname_ns_id" type="long" not-null="true" /> <!-- fk_alf_cass_qnns -->
|
<property name="qnameNamespaceId" column="qname_ns_id" type="long" not-null="true" /> <!-- fk_alf_cass_qnns -->
|
||||||
<property name="qnameLocalName" column="qname_localname" type="string" length="255" not-null="true" index="idx_alf_cass_qnln" />
|
<property name="qnameLocalName" column="qname_localname" type="string" length="255" not-null="true" />
|
||||||
|
<property name="qnameCrc" column="qname_crc" type="long" not-null="true"/>
|
||||||
<property name="isPrimary" column="is_primary" />
|
<property name="isPrimary" column="is_primary" />
|
||||||
<property name="index" column="assoc_index" />
|
<property name="index" column="assoc_index" />
|
||||||
</class>
|
</class>
|
||||||
@@ -260,14 +261,12 @@
|
|||||||
<query name="node.GetParentAssocs">
|
<query name="node.GetParentAssocs">
|
||||||
select
|
select
|
||||||
assoc,
|
assoc,
|
||||||
parent,
|
parent
|
||||||
child
|
|
||||||
from
|
from
|
||||||
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
||||||
join assoc.parent as parent
|
join assoc.parent as parent
|
||||||
join assoc.child as child
|
|
||||||
where
|
where
|
||||||
child.id = :childId
|
assoc.child.id = :childId
|
||||||
</query>
|
</query>
|
||||||
|
|
||||||
<query name="node.DeleteParentAssocs">
|
<query name="node.DeleteParentAssocs">
|
||||||
@@ -317,7 +316,8 @@
|
|||||||
assoc.child.id = :childId and
|
assoc.child.id = :childId and
|
||||||
assoc.typeQNameId = :typeQNameId and
|
assoc.typeQNameId = :typeQNameId and
|
||||||
assoc.qnameNamespaceId = :qnameNamespaceId and
|
assoc.qnameNamespaceId = :qnameNamespaceId and
|
||||||
assoc.qnameLocalName = :qnameLocalName
|
assoc.qnameLocalName = :qnameLocalName and
|
||||||
|
assoc.qnameCrc = :qnameCrc
|
||||||
order by
|
order by
|
||||||
assoc.index,
|
assoc.index,
|
||||||
assoc.id
|
assoc.id
|
||||||
@@ -356,6 +356,7 @@
|
|||||||
assoc.typeQNameId,
|
assoc.typeQNameId,
|
||||||
assoc.qnameNamespaceId,
|
assoc.qnameNamespaceId,
|
||||||
assoc.qnameLocalName,
|
assoc.qnameLocalName,
|
||||||
|
assoc.qnameCrc,
|
||||||
assoc.childNodeName,
|
assoc.childNodeName,
|
||||||
assoc.childNodeNameCrc,
|
assoc.childNodeNameCrc,
|
||||||
assoc.isPrimary,
|
assoc.isPrimary,
|
||||||
@@ -366,11 +367,10 @@
|
|||||||
child.uuid
|
child.uuid
|
||||||
from
|
from
|
||||||
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
||||||
join assoc.parent as parent
|
|
||||||
join assoc.child as child
|
join assoc.child as child
|
||||||
join child.store as store
|
join child.store as store
|
||||||
where
|
where
|
||||||
parent.id = :parentId and
|
assoc.parent.id = :parentId and
|
||||||
assoc.typeQNameId = :typeQNameId and
|
assoc.typeQNameId = :typeQNameId and
|
||||||
assoc.childNodeName in (:childNodeNames)
|
assoc.childNodeName in (:childNodeNames)
|
||||||
order by
|
order by
|
||||||
@@ -384,6 +384,7 @@
|
|||||||
assoc.typeQNameId,
|
assoc.typeQNameId,
|
||||||
assoc.qnameNamespaceId,
|
assoc.qnameNamespaceId,
|
||||||
assoc.qnameLocalName,
|
assoc.qnameLocalName,
|
||||||
|
assoc.qnameCrc,
|
||||||
assoc.childNodeName,
|
assoc.childNodeName,
|
||||||
assoc.childNodeNameCrc,
|
assoc.childNodeNameCrc,
|
||||||
assoc.isPrimary,
|
assoc.isPrimary,
|
||||||
@@ -394,11 +395,10 @@
|
|||||||
child.uuid
|
child.uuid
|
||||||
from
|
from
|
||||||
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
||||||
join assoc.parent as parent
|
|
||||||
join assoc.child as child
|
join assoc.child as child
|
||||||
join child.store as store
|
join child.store as store
|
||||||
where
|
where
|
||||||
parent.id = :parentId
|
assoc.parent.id = :parentId
|
||||||
order by
|
order by
|
||||||
assoc.index,
|
assoc.index,
|
||||||
assoc.id
|
assoc.id
|
||||||
@@ -410,6 +410,7 @@
|
|||||||
assoc.typeQNameId,
|
assoc.typeQNameId,
|
||||||
assoc.qnameNamespaceId,
|
assoc.qnameNamespaceId,
|
||||||
assoc.qnameLocalName,
|
assoc.qnameLocalName,
|
||||||
|
assoc.qnameCrc,
|
||||||
assoc.childNodeName,
|
assoc.childNodeName,
|
||||||
assoc.childNodeNameCrc,
|
assoc.childNodeNameCrc,
|
||||||
assoc.isPrimary,
|
assoc.isPrimary,
|
||||||
@@ -420,13 +421,13 @@
|
|||||||
child.uuid
|
child.uuid
|
||||||
from
|
from
|
||||||
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
||||||
join assoc.parent as parent
|
|
||||||
join assoc.child as child
|
join assoc.child as child
|
||||||
join child.store as store
|
join child.store as store
|
||||||
where
|
where
|
||||||
parent.id = :parentId and
|
assoc.parent.id = :parentId and
|
||||||
assoc.qnameNamespaceId = :qnameNamespaceId and
|
assoc.qnameNamespaceId = :qnameNamespaceId and
|
||||||
assoc.qnameLocalName = :qnameLocalName
|
assoc.qnameLocalName = :qnameLocalName and
|
||||||
|
assoc.qnameCrc = :qnameCrc
|
||||||
order by
|
order by
|
||||||
assoc.index,
|
assoc.index,
|
||||||
assoc.id
|
assoc.id
|
||||||
@@ -437,6 +438,7 @@
|
|||||||
<return-scalar column="type_qname_id" type="long"/>
|
<return-scalar column="type_qname_id" type="long"/>
|
||||||
<return-scalar column="qname_ns_id" type="long"/>
|
<return-scalar column="qname_ns_id" type="long"/>
|
||||||
<return-scalar column="qname_localname" type="string"/>
|
<return-scalar column="qname_localname" type="string"/>
|
||||||
|
<return-scalar column="qname_crc" type="long"/>
|
||||||
<return-scalar column="child_node_name" type="string"/>
|
<return-scalar column="child_node_name" type="string"/>
|
||||||
<return-scalar column="child_node_name_crc" type="long"/>
|
<return-scalar column="child_node_name_crc" type="long"/>
|
||||||
<return-scalar column="is_primary" type="boolean"/>
|
<return-scalar column="is_primary" type="boolean"/>
|
||||||
@@ -450,6 +452,7 @@
|
|||||||
a.type_qname_id,
|
a.type_qname_id,
|
||||||
a.qname_ns_id,
|
a.qname_ns_id,
|
||||||
a.qname_localname,
|
a.qname_localname,
|
||||||
|
a.qname_crc,
|
||||||
a.child_node_name,
|
a.child_node_name,
|
||||||
a.child_node_name_crc,
|
a.child_node_name_crc,
|
||||||
a.is_primary,
|
a.is_primary,
|
||||||
@@ -471,6 +474,7 @@
|
|||||||
assoc.typeQNameId,
|
assoc.typeQNameId,
|
||||||
assoc.qnameNamespaceId,
|
assoc.qnameNamespaceId,
|
||||||
assoc.qnameLocalName,
|
assoc.qnameLocalName,
|
||||||
|
assoc.qnameCrc,
|
||||||
assoc.childNodeName,
|
assoc.childNodeName,
|
||||||
assoc.childNodeNameCrc,
|
assoc.childNodeNameCrc,
|
||||||
assoc.isPrimary,
|
assoc.isPrimary,
|
||||||
@@ -481,14 +485,14 @@
|
|||||||
child.uuid
|
child.uuid
|
||||||
from
|
from
|
||||||
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
||||||
join assoc.parent as parent
|
|
||||||
join assoc.child as child
|
join assoc.child as child
|
||||||
join child.store as store
|
join child.store as store
|
||||||
where
|
where
|
||||||
parent.id = :parentId and
|
assoc.parent.id = :parentId and
|
||||||
assoc.typeQNameId = :typeQNameId and
|
assoc.typeQNameId = :typeQNameId and
|
||||||
assoc.qnameNamespaceId = :qnameNamespaceId and
|
assoc.qnameNamespaceId = :qnameNamespaceId and
|
||||||
assoc.qnameLocalName = :qnameLocalName
|
assoc.qnameLocalName = :qnameLocalName and
|
||||||
|
assoc.qnameCrc = :qnameCrc
|
||||||
order by
|
order by
|
||||||
assoc.index,
|
assoc.index,
|
||||||
assoc.id
|
assoc.id
|
||||||
@@ -500,6 +504,7 @@
|
|||||||
assoc.typeQNameId,
|
assoc.typeQNameId,
|
||||||
assoc.qnameNamespaceId,
|
assoc.qnameNamespaceId,
|
||||||
assoc.qnameLocalName,
|
assoc.qnameLocalName,
|
||||||
|
assoc.qnameCrc,
|
||||||
assoc.childNodeName,
|
assoc.childNodeName,
|
||||||
assoc.childNodeNameCrc,
|
assoc.childNodeNameCrc,
|
||||||
assoc.isPrimary,
|
assoc.isPrimary,
|
||||||
@@ -510,11 +515,10 @@
|
|||||||
child.uuid
|
child.uuid
|
||||||
from
|
from
|
||||||
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
||||||
join assoc.parent as parent
|
|
||||||
join assoc.child as child
|
join assoc.child as child
|
||||||
join child.store as store
|
join child.store as store
|
||||||
where
|
where
|
||||||
parent.id = :parentId and
|
assoc.parent.id = :parentId and
|
||||||
child.typeQNameId in (:childTypeQNameIds)
|
child.typeQNameId in (:childTypeQNameIds)
|
||||||
order by
|
order by
|
||||||
assoc.index,
|
assoc.index,
|
||||||
@@ -527,6 +531,7 @@
|
|||||||
assoc.typeQNameId,
|
assoc.typeQNameId,
|
||||||
assoc.qnameNamespaceId,
|
assoc.qnameNamespaceId,
|
||||||
assoc.qnameLocalName,
|
assoc.qnameLocalName,
|
||||||
|
assoc.qnameCrc,
|
||||||
assoc.childNodeName,
|
assoc.childNodeName,
|
||||||
assoc.childNodeNameCrc,
|
assoc.childNodeNameCrc,
|
||||||
assoc.isPrimary,
|
assoc.isPrimary,
|
||||||
@@ -537,7 +542,6 @@
|
|||||||
child.uuid
|
child.uuid
|
||||||
from
|
from
|
||||||
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc
|
||||||
join assoc.parent as parent
|
|
||||||
join assoc.child as child
|
join assoc.child as child
|
||||||
join child.store as store
|
join child.store as store
|
||||||
where
|
where
|
||||||
@@ -554,6 +558,7 @@
|
|||||||
assoc.typeQNameId,
|
assoc.typeQNameId,
|
||||||
assoc.qnameNamespaceId,
|
assoc.qnameNamespaceId,
|
||||||
assoc.qnameLocalName,
|
assoc.qnameLocalName,
|
||||||
|
assoc.qnameCrc,
|
||||||
assoc.childNodeName,
|
assoc.childNodeName,
|
||||||
assoc.childNodeNameCrc,
|
assoc.childNodeNameCrc,
|
||||||
assoc.isPrimary,
|
assoc.isPrimary,
|
||||||
@@ -834,6 +839,7 @@
|
|||||||
<return-scalar column="type_qname_id" type="long"/>
|
<return-scalar column="type_qname_id" type="long"/>
|
||||||
<return-scalar column="qname_ns_id" type="long"/>
|
<return-scalar column="qname_ns_id" type="long"/>
|
||||||
<return-scalar column="qname_localname" type="string"/>
|
<return-scalar column="qname_localname" type="string"/>
|
||||||
|
<return-scalar column="qname_crc" type="long"/>
|
||||||
<return-scalar column="child_node_name" type="string"/>
|
<return-scalar column="child_node_name" type="string"/>
|
||||||
<return-scalar column="child_node_name_crc" type="long"/>
|
<return-scalar column="child_node_name_crc" type="long"/>
|
||||||
<return-scalar column="is_primary" type="boolean"/>
|
<return-scalar column="is_primary" type="boolean"/>
|
||||||
@@ -847,6 +853,7 @@
|
|||||||
z1.type_qname_id,
|
z1.type_qname_id,
|
||||||
z1.qname_ns_id,
|
z1.qname_ns_id,
|
||||||
z1.qname_localname,
|
z1.qname_localname,
|
||||||
|
z1.qname_crc,
|
||||||
z1.child_node_name,
|
z1.child_node_name,
|
||||||
z1.child_node_name_crc,
|
z1.child_node_name_crc,
|
||||||
z1.is_primary,
|
z1.is_primary,
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
* As a special exception to the terms and conditions of version 2.0 of
|
* 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
|
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||||
* FLOSS exception. You should have recieved a copy of the text describing
|
* FLOSS exception. You should have received a copy of the text describing
|
||||||
* the FLOSS exception, and it is also available here:
|
* the FLOSS exception, and it is also available here:
|
||||||
* http://www.alfresco.com/legal/licensing"
|
* http://www.alfresco.com/legal/licensing"
|
||||||
*/
|
*/
|
||||||
@@ -59,7 +59,6 @@ import org.alfresco.service.cmr.dictionary.TypeDefinition;
|
|||||||
import org.alfresco.service.cmr.repository.AssociationExistsException;
|
import org.alfresco.service.cmr.repository.AssociationExistsException;
|
||||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.CyclicChildRelationshipException;
|
|
||||||
import org.alfresco.service.cmr.repository.InvalidChildAssociationRefException;
|
import org.alfresco.service.cmr.repository.InvalidChildAssociationRefException;
|
||||||
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
||||||
import org.alfresco.service.cmr.repository.InvalidStoreRefException;
|
import org.alfresco.service.cmr.repository.InvalidStoreRefException;
|
||||||
@@ -655,6 +654,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
// No recurse
|
// No recurse
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean preLoadNodes()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// Get all the QNames to remove
|
// Get all the QNames to remove
|
||||||
List<QName> assocTypeQNamesToRemove = new ArrayList<QName>(aspectDef.getChildAssociations().keySet());
|
List<QName> assocTypeQNamesToRemove = new ArrayList<QName>(aspectDef.getChildAssociations().keySet());
|
||||||
@@ -825,8 +829,14 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
// No recurse
|
// No recurse
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
// Get all the QNames to remove
|
public boolean preLoadNodes()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get all the QNames to remove
|
||||||
nodeDaoService.getPrimaryChildAssocs(nodeId, callback);
|
nodeDaoService.getPrimaryChildAssocs(nodeId, callback);
|
||||||
// Each child must be deleted
|
// Each child must be deleted
|
||||||
for (Pair<Long, NodeRef> childNodePair : childNodePairs)
|
for (Pair<Long, NodeRef> childNodePair : childNodePairs)
|
||||||
@@ -951,6 +961,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
// No recurse
|
// No recurse
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean preLoadNodes()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
nodeDaoService.getChildAssocs(parentNodeId, callback, false);
|
nodeDaoService.getChildAssocs(parentNodeId, callback, false);
|
||||||
|
|
||||||
@@ -1465,19 +1480,35 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
* Filters out any associations if their qname is not a match to the given pattern.
|
* Filters out any associations if their qname is not a match to the given pattern.
|
||||||
*/
|
*/
|
||||||
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, final QNamePattern typeQNamePattern, final QNamePattern qnamePattern)
|
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, final QNamePattern typeQNamePattern, final QNamePattern qnamePattern)
|
||||||
|
{
|
||||||
|
return getChildAssocs(nodeRef, typeQNamePattern, qnamePattern, true) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters out any associations if their qname is not a match to the given pattern.
|
||||||
|
*/
|
||||||
|
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, final QNamePattern typeQNamePattern, final QNamePattern qnamePattern, final boolean preload)
|
||||||
{
|
{
|
||||||
// Get the node
|
// Get the node
|
||||||
Pair<Long, NodeRef> nodePair = getNodePairNotNull(nodeRef);
|
Pair<Long, NodeRef> nodePair = getNodePairNotNull(nodeRef);
|
||||||
Long nodeId = nodePair.getFirst();
|
Long nodeId = nodePair.getFirst();
|
||||||
|
|
||||||
final List<ChildAssociationRef> results = new ArrayList<ChildAssociationRef>(100);
|
final List<ChildAssociationRef> results = new ArrayList<ChildAssociationRef>(100);
|
||||||
|
|
||||||
|
abstract class BaseCallback implements NodeDaoService.ChildAssocRefQueryCallback
|
||||||
|
{
|
||||||
|
public boolean preLoadNodes()
|
||||||
|
{
|
||||||
|
return preload;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (qnamePattern instanceof QName)
|
if (qnamePattern instanceof QName)
|
||||||
{
|
{
|
||||||
// Both explicit QNames
|
// Both explicit QNames
|
||||||
if (typeQNamePattern instanceof QName)
|
if (typeQNamePattern instanceof QName)
|
||||||
{
|
{
|
||||||
NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
NodeDaoService.ChildAssocRefQueryCallback callback = new BaseCallback()
|
||||||
{
|
{
|
||||||
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
||||||
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
||||||
@@ -1496,7 +1527,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
NodeDaoService.ChildAssocRefQueryCallback callback;
|
NodeDaoService.ChildAssocRefQueryCallback callback;
|
||||||
if (typeQNamePattern.equals(RegexQNamePattern.MATCH_ALL))
|
if (typeQNamePattern.equals(RegexQNamePattern.MATCH_ALL))
|
||||||
{
|
{
|
||||||
callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
callback = new BaseCallback()
|
||||||
{
|
{
|
||||||
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
||||||
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
||||||
@@ -1508,7 +1539,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
callback = new BaseCallback()
|
||||||
{
|
{
|
||||||
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
||||||
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
||||||
@@ -1540,7 +1571,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
// if the type is the wildcard type, and the qname is not a search, then use a shortcut query
|
// if the type is the wildcard type, and the qname is not a search, then use a shortcut query
|
||||||
if (qnamePattern.equals(RegexQNamePattern.MATCH_ALL))
|
if (qnamePattern.equals(RegexQNamePattern.MATCH_ALL))
|
||||||
{
|
{
|
||||||
callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
callback = new BaseCallback()
|
||||||
{
|
{
|
||||||
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
||||||
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
||||||
@@ -1553,7 +1584,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
callback = new BaseCallback()
|
||||||
{
|
{
|
||||||
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
||||||
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
||||||
@@ -1579,7 +1610,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
// Local qname is pattern, type name is pattern
|
// Local qname is pattern, type name is pattern
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback()
|
NodeDaoService.ChildAssocRefQueryCallback callback = new BaseCallback()
|
||||||
{
|
{
|
||||||
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
|
||||||
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
|
||||||
@@ -1625,6 +1656,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
results.add(childAssocPair.getSecond());
|
results.add(childAssocPair.getSecond());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean preLoadNodes()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// Get all child associations with the specific qualified name
|
// Get all child associations with the specific qualified name
|
||||||
nodeDaoService.getChildAssocsByChildTypes(nodeId, childNodeTypeQNames, callback);
|
nodeDaoService.getChildAssocsByChildTypes(nodeId, childNodeTypeQNames, callback);
|
||||||
@@ -1693,6 +1729,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
results.add(childAssocPair.getSecond());
|
results.add(childAssocPair.getSecond());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean preLoadNodes()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// Get all child associations with the specific qualified name
|
// Get all child associations with the specific qualified name
|
||||||
nodeDaoService.getChildAssocs(nodeId, assocTypeQName, childNames, callback);
|
nodeDaoService.getChildAssocs(nodeId, assocTypeQName, childNames, callback);
|
||||||
@@ -1761,6 +1802,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
results.add(childAssocPair.getSecond());
|
results.add(childAssocPair.getSecond());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean preLoadNodes()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the child associations that meet the criteria
|
// Get the child associations that meet the criteria
|
||||||
@@ -1838,146 +1884,6 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
return nodeAssocRefs;
|
return nodeAssocRefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursive method used to build up paths from a given node to the root.
|
|
||||||
* <p>
|
|
||||||
* Whilst walking up the hierarchy to the root, some nodes may have a <b>root</b> aspect.
|
|
||||||
* Everytime one of these is encountered, a new path is farmed off, but the method
|
|
||||||
* continues to walk up the hierarchy.
|
|
||||||
*
|
|
||||||
* @param currentNode the node to start from, i.e. the child node to work upwards from
|
|
||||||
* @param currentPath the path from the current node to the descendent that we started from
|
|
||||||
* @param completedPaths paths that have reached the root are added to this collection
|
|
||||||
* @param assocStack the parent-child relationships traversed whilst building the path.
|
|
||||||
* Used to detected cyclic relationships.
|
|
||||||
* @param primaryOnly true if only the primary parent association must be traversed.
|
|
||||||
* If this is true, then the only root is the top level node having no parents.
|
|
||||||
* @throws CyclicChildRelationshipException
|
|
||||||
*/
|
|
||||||
private void prependPaths(
|
|
||||||
Pair<Long, NodeRef> currentNodePair,
|
|
||||||
Pair<StoreRef, NodeRef> currentRootNodePair,
|
|
||||||
Path currentPath,
|
|
||||||
Collection<Path> completedPaths,
|
|
||||||
Stack<Long> assocIdStack,
|
|
||||||
boolean primaryOnly)
|
|
||||||
throws CyclicChildRelationshipException
|
|
||||||
{
|
|
||||||
Long currentNodeId = currentNodePair.getFirst();
|
|
||||||
NodeRef currentNodeRef = currentNodePair.getSecond();
|
|
||||||
|
|
||||||
// Check if we have changed root nodes
|
|
||||||
StoreRef currentStoreRef = currentNodeRef.getStoreRef();
|
|
||||||
if (currentRootNodePair == null || !currentStoreRef.equals(currentRootNodePair.getFirst()))
|
|
||||||
{
|
|
||||||
// We've changed stores
|
|
||||||
Pair<Long, NodeRef> rootNodePair = nodeDaoService.getRootNode(currentStoreRef);
|
|
||||||
currentRootNodePair = new Pair<StoreRef, NodeRef>(currentStoreRef, rootNodePair.getSecond());
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the parent associations of the given node
|
|
||||||
Collection<Pair<Long, ChildAssociationRef>> parentAssocPairs = nodeDaoService.getParentAssocs(currentNodeId);
|
|
||||||
// does the node have parents
|
|
||||||
boolean hasParents = parentAssocPairs.size() > 0;
|
|
||||||
// does the current node have a root aspect?
|
|
||||||
boolean isRoot = nodeDaoService.hasNodeAspect(currentNodeId, ContentModel.ASPECT_ROOT);
|
|
||||||
boolean isStoreRoot = nodeDaoService.getNodeType(currentNodeId).equals(ContentModel.TYPE_STOREROOT);
|
|
||||||
|
|
||||||
// look for a root. If we only want the primary root, then ignore all but the top-level root.
|
|
||||||
if (isRoot && !(primaryOnly && hasParents)) // exclude primary search with parents present
|
|
||||||
{
|
|
||||||
// create a one-sided assoc ref for the root node and prepend to the stack
|
|
||||||
// this effectively spoofs the fact that the current node is not below the root
|
|
||||||
// - we put this assoc in as the first assoc in the path must be a one-sided
|
|
||||||
// reference pointing to the root node
|
|
||||||
ChildAssociationRef assocRef = new ChildAssociationRef(
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
currentRootNodePair.getSecond());
|
|
||||||
// create a path to save and add the 'root' assoc
|
|
||||||
Path pathToSave = new Path();
|
|
||||||
Path.ChildAssocElement first = null;
|
|
||||||
for (Path.Element element: currentPath)
|
|
||||||
{
|
|
||||||
if (first == null)
|
|
||||||
{
|
|
||||||
first = (Path.ChildAssocElement) element;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pathToSave.append(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (first != null)
|
|
||||||
{
|
|
||||||
// mimic an association that would appear if the current node was below the root node
|
|
||||||
// or if first beneath the root node it will make the real thing
|
|
||||||
ChildAssociationRef updateAssocRef = new ChildAssociationRef(
|
|
||||||
isStoreRoot ? ContentModel.ASSOC_CHILDREN : first.getRef().getTypeQName(),
|
|
||||||
currentRootNodePair.getSecond(),
|
|
||||||
first.getRef().getQName(),
|
|
||||||
first.getRef().getChildRef());
|
|
||||||
Path.Element newFirst = new Path.ChildAssocElement(updateAssocRef);
|
|
||||||
pathToSave.prepend(newFirst);
|
|
||||||
}
|
|
||||||
|
|
||||||
Path.Element element = new Path.ChildAssocElement(assocRef);
|
|
||||||
pathToSave.prepend(element);
|
|
||||||
|
|
||||||
// store the path just built
|
|
||||||
completedPaths.add(pathToSave);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentAssocPairs.size() == 0 && !isRoot)
|
|
||||||
{
|
|
||||||
throw new RuntimeException("Node without parents does not have root aspect: " +
|
|
||||||
currentNodeRef);
|
|
||||||
}
|
|
||||||
// walk up each parent association
|
|
||||||
for (Pair<Long, ChildAssociationRef> assocPair : parentAssocPairs)
|
|
||||||
{
|
|
||||||
Long assocId = assocPair.getFirst();
|
|
||||||
ChildAssociationRef assocRef = assocPair.getSecond();
|
|
||||||
// do we consider only primary assocs?
|
|
||||||
if (primaryOnly && !assocRef.isPrimary())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Ordering is meaningless here as we are constructing a path upwards
|
|
||||||
// and have no idea where the node comes in the sibling order or even
|
|
||||||
// if there are like-pathed siblings.
|
|
||||||
assocRef.setNthSibling(-1);
|
|
||||||
// build a path element
|
|
||||||
Path.Element element = new Path.ChildAssocElement(assocRef);
|
|
||||||
// create a new path that builds on the current path
|
|
||||||
Path path = new Path();
|
|
||||||
path.append(currentPath);
|
|
||||||
// prepend element
|
|
||||||
path.prepend(element);
|
|
||||||
// get parent node
|
|
||||||
NodeRef parentRef = assocRef.getParentRef();
|
|
||||||
Pair<Long, NodeRef> parentNodePair = getNodePairNotNull(parentRef);
|
|
||||||
// does the association already exist in the stack
|
|
||||||
if (assocIdStack.contains(assocId))
|
|
||||||
{
|
|
||||||
// the association was present already
|
|
||||||
throw new CyclicChildRelationshipException(
|
|
||||||
"Cyclic parent-child relationship detected: \n" +
|
|
||||||
" current node: " + currentNodeId + "\n" +
|
|
||||||
" current path: " + currentPath + "\n" +
|
|
||||||
" next assoc: " + assocId,
|
|
||||||
assocRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
// push the assoc stack, recurse and pop
|
|
||||||
assocIdStack.push(assocId);
|
|
||||||
prependPaths(parentNodePair, currentRootNodePair, path, completedPaths, assocIdStack, primaryOnly);
|
|
||||||
assocIdStack.pop();
|
|
||||||
}
|
|
||||||
// done
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see #getPaths(NodeRef, boolean)
|
* @see #getPaths(NodeRef, boolean)
|
||||||
* @see #prependPaths(Node, Path, Collection, Stack, boolean)
|
* @see #prependPaths(Node, Path, Collection, Stack, boolean)
|
||||||
@@ -2008,7 +1914,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
// create storage for touched associations
|
// create storage for touched associations
|
||||||
Stack<Long> assocIdStack = new Stack<Long>();
|
Stack<Long> assocIdStack = new Stack<Long>();
|
||||||
// call recursive method to sort it out
|
// call recursive method to sort it out
|
||||||
prependPaths(nodePair, null, currentPath, paths, assocIdStack, primaryOnly);
|
nodeDaoService.prependPaths(nodePair, null, currentPath, paths, assocIdStack, primaryOnly);
|
||||||
|
|
||||||
// check that for the primary only case we have exactly one path
|
// check that for the primary only case we have exactly one path
|
||||||
if (primaryOnly && paths.size() != 1)
|
if (primaryOnly && paths.size() != 1)
|
||||||
@@ -2320,6 +2226,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
childNodePairs.add(childNodePair);
|
childNodePairs.add(childNodePair);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean preLoadNodes()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// We only need to move child nodes that are not already in the same store
|
// We only need to move child nodes that are not already in the same store
|
||||||
nodeDaoService.getPrimaryChildAssocsNotInSameStore(nodeId, callback);
|
nodeDaoService.getPrimaryChildAssocsNotInSameStore(nodeId, callback);
|
||||||
@@ -2392,7 +2303,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
|
|||||||
childNodePairs.add(childNodePair);
|
childNodePairs.add(childNodePair);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean preLoadNodes()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
nodeDaoService.getPrimaryChildAssocs(nodeId, callback);
|
nodeDaoService.getPrimaryChildAssocs(nodeId, callback);
|
||||||
// Each child must be moved to the same store as the parent
|
// Each child must be moved to the same store as the parent
|
||||||
for (Pair<Long, NodeRef> oldChildNodePair : childNodePairs)
|
for (Pair<Long, NodeRef> oldChildNodePair : childNodePairs)
|
||||||
|
@@ -29,6 +29,7 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
import org.alfresco.repo.domain.ChildAssoc;
|
import org.alfresco.repo.domain.ChildAssoc;
|
||||||
import org.alfresco.repo.domain.NodeAssoc;
|
import org.alfresco.repo.domain.NodeAssoc;
|
||||||
@@ -40,7 +41,9 @@ import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
|||||||
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
|
import org.alfresco.service.cmr.dictionary.InvalidTypeException;
|
||||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
|
import org.alfresco.service.cmr.repository.CyclicChildRelationshipException;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.Path;
|
||||||
import org.alfresco.service.cmr.repository.StoreExistsException;
|
import org.alfresco.service.cmr.repository.StoreExistsException;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
@@ -243,6 +246,8 @@ public interface NodeDaoService
|
|||||||
Pair<Long, NodeRef> parentNodePair,
|
Pair<Long, NodeRef> parentNodePair,
|
||||||
Pair<Long, NodeRef> childNodePair
|
Pair<Long, NodeRef> childNodePair
|
||||||
);
|
);
|
||||||
|
|
||||||
|
boolean preLoadNodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -652,4 +657,9 @@ public interface NodeDaoService
|
|||||||
|
|
||||||
@DirtySessionAnnotation(markDirty=false)
|
@DirtySessionAnnotation(markDirty=false)
|
||||||
public Long getMaxTxnCommitTime();
|
public Long getMaxTxnCommitTime();
|
||||||
|
|
||||||
|
@DirtySessionAnnotation(markDirty=false)
|
||||||
|
public void prependPaths(Pair<Long, NodeRef> currentNodePair, Pair<StoreRef, NodeRef> currentRootNodePair,
|
||||||
|
Path currentPath, Collection<Path> completedPaths, Stack<Long> assocIdStack, boolean primaryOnly)
|
||||||
|
throws CyclicChildRelationshipException;
|
||||||
}
|
}
|
||||||
|
@@ -26,6 +26,7 @@ package org.alfresco.repo.node.db.hibernate;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -41,6 +42,7 @@ import java.util.Locale;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.SortedMap;
|
import java.util.SortedMap;
|
||||||
|
import java.util.Stack;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
@@ -99,12 +101,14 @@ import org.alfresco.service.cmr.repository.AssociationExistsException;
|
|||||||
import org.alfresco.service.cmr.repository.AssociationRef;
|
import org.alfresco.service.cmr.repository.AssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||||
import org.alfresco.service.cmr.repository.ContentData;
|
import org.alfresco.service.cmr.repository.ContentData;
|
||||||
|
import org.alfresco.service.cmr.repository.CyclicChildRelationshipException;
|
||||||
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
|
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
|
||||||
import org.alfresco.service.cmr.repository.EntityRef;
|
import org.alfresco.service.cmr.repository.EntityRef;
|
||||||
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
||||||
import org.alfresco.service.cmr.repository.InvalidStoreRefException;
|
import org.alfresco.service.cmr.repository.InvalidStoreRefException;
|
||||||
import org.alfresco.service.cmr.repository.MLText;
|
import org.alfresco.service.cmr.repository.MLText;
|
||||||
import org.alfresco.service.cmr.repository.NodeRef;
|
import org.alfresco.service.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.cmr.repository.Path;
|
||||||
import org.alfresco.service.cmr.repository.StoreExistsException;
|
import org.alfresco.service.cmr.repository.StoreExistsException;
|
||||||
import org.alfresco.service.cmr.repository.StoreRef;
|
import org.alfresco.service.cmr.repository.StoreRef;
|
||||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||||
@@ -207,7 +211,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
/** A cache mapping StoreRef and NodeRef instances to the entity IDs (primary key) */
|
/** A cache mapping StoreRef and NodeRef instances to the entity IDs (primary key) */
|
||||||
private SimpleCache<EntityRef, Long> storeAndNodeIdCache;
|
private SimpleCache<EntityRef, Long> storeAndNodeIdCache;
|
||||||
/** A cache for more performant lookups of the parent associations */
|
/** A cache for more performant lookups of the parent associations */
|
||||||
private SimpleCache<Long, Set<Long>> parentAssocsCache;
|
private SimpleCache<Long, NodeInfo> parentAssocsCache;
|
||||||
private boolean isDebugEnabled = logger.isDebugEnabled();
|
private boolean isDebugEnabled = logger.isDebugEnabled();
|
||||||
private boolean isDebugParentAssocCacheEnabled = loggerParentAssocsCache.isDebugEnabled();
|
private boolean isDebugParentAssocCacheEnabled = loggerParentAssocsCache.isDebugEnabled();
|
||||||
|
|
||||||
@@ -357,7 +361,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
*
|
*
|
||||||
* @param parentAssocsCache the cache
|
* @param parentAssocsCache the cache
|
||||||
*/
|
*/
|
||||||
public void setParentAssocsCache(SimpleCache<Long, Set<Long>> parentAssocsCache)
|
public void setParentAssocsCache(SimpleCache<Long, NodeInfo> parentAssocsCache)
|
||||||
{
|
{
|
||||||
this.parentAssocsCache = parentAssocsCache;
|
this.parentAssocsCache = parentAssocsCache;
|
||||||
}
|
}
|
||||||
@@ -646,7 +650,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
ChildAssoc assoc = (ChildAssoc) getHibernateTemplate().get(ChildAssocImpl.class, childAssocId);
|
ChildAssoc assoc = (ChildAssoc) getHibernateTemplate().get(ChildAssocImpl.class, childAssocId);
|
||||||
if (assoc == null)
|
if (assoc == null)
|
||||||
{
|
{
|
||||||
throw new AlfrescoRuntimeException("ChildAssoc ID " + childAssocId + " is invalid");
|
throw new ObjectNotFoundException(childAssocId, ChildAssocImpl.class.getName());
|
||||||
}
|
}
|
||||||
return assoc;
|
return assoc;
|
||||||
}
|
}
|
||||||
@@ -737,6 +741,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
// Add the root aspect
|
// Add the root aspect
|
||||||
Pair<Long, QName> rootAspectQNamePair = qnameDAO.getOrCreateQName(ContentModel.ASPECT_ROOT);
|
Pair<Long, QName> rootAspectQNamePair = qnameDAO.getOrCreateQName(ContentModel.ASPECT_ROOT);
|
||||||
rootNode.getAspects().add(rootAspectQNamePair.getFirst());
|
rootNode.getAspects().add(rootAspectQNamePair.getFirst());
|
||||||
|
parentAssocsCache.remove(rootNode.getId());
|
||||||
|
|
||||||
// Assign permissions to the root node
|
// Assign permissions to the root node
|
||||||
SimpleAccessControlListProperties properties = DMPermissionsDaoComponentImpl.getDefaultProperties();
|
SimpleAccessControlListProperties properties = DMPermissionsDaoComponentImpl.getDefaultProperties();
|
||||||
@@ -955,8 +960,8 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Long nodeId = node.getId();
|
Long nodeId = node.getId();
|
||||||
Collection<ChildAssoc> parentAssocs = getParentAssocsInternal(nodeId);
|
NodeInfo parentAssocs = getParentAssocsInternal(nodeId);
|
||||||
for (ChildAssoc parentAssoc : parentAssocs)
|
for (ParentAssocInfo parentAssoc : parentAssocs.getParentAssocs().values())
|
||||||
{
|
{
|
||||||
propagateTimestamps(parentAssoc);
|
propagateTimestamps(parentAssoc);
|
||||||
}
|
}
|
||||||
@@ -1004,7 +1009,6 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String QUERY_UPDATE_AUDITABLE_MODIFIED = "node.UpdateAuditableModified";
|
|
||||||
public Integer execute() throws Throwable
|
public Integer execute() throws Throwable
|
||||||
{
|
{
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
@@ -1060,14 +1064,14 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
* Ensures that the timestamps are propogated to the parent node of the association, but only
|
* Ensures that the timestamps are propogated to the parent node of the association, but only
|
||||||
* if the association requires it.
|
* if the association requires it.
|
||||||
*/
|
*/
|
||||||
private void propagateTimestamps(ChildAssoc parentAssoc)
|
private void propagateTimestamps(ParentAssocInfo parentAssocPair)
|
||||||
{
|
{
|
||||||
// Shortcut
|
// Shortcut
|
||||||
if (!enableTimestampPropagation)
|
if (!enableTimestampPropagation)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QName assocTypeQName = parentAssoc.getTypeQName(qnameDAO);
|
QName assocTypeQName = parentAssocPair.getChildAssociationRef().getTypeQName();
|
||||||
AssociationDefinition assocDef = dictionaryService.getAssociation(assocTypeQName);
|
AssociationDefinition assocDef = dictionaryService.getAssociation(assocTypeQName);
|
||||||
if (assocDef == null)
|
if (assocDef == null)
|
||||||
{
|
{
|
||||||
@@ -1093,7 +1097,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
propagator = new TimestampPropagator();
|
propagator = new TimestampPropagator();
|
||||||
AlfrescoTransactionSupport.bindListener(propagator);
|
AlfrescoTransactionSupport.bindListener(propagator);
|
||||||
}
|
}
|
||||||
propagator.addNode(parentAssoc.getParent().getId());
|
propagator.addNode(parentAssocPair.getParentNodeId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pair<Long, NodeRef> newNode(StoreRef storeRef, String uuid, QName nodeTypeQName) throws InvalidTypeException
|
public Pair<Long, NodeRef> newNode(StoreRef storeRef, String uuid, QName nodeTypeQName) throws InvalidTypeException
|
||||||
@@ -1165,6 +1169,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
// Update the node
|
// Update the node
|
||||||
updateNode(nodeId, storeRef, null, null);
|
updateNode(nodeId, storeRef, null, null);
|
||||||
NodeRef nodeRef = node.getNodeRef();
|
NodeRef nodeRef = node.getNodeRef();
|
||||||
|
this.parentAssocsCache.remove(nodeId);
|
||||||
|
|
||||||
return new Pair<Long, NodeRef>(node.getId(), nodeRef);
|
return new Pair<Long, NodeRef>(node.getId(), nodeRef);
|
||||||
}
|
}
|
||||||
@@ -1511,7 +1516,6 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
Collections.singletonMap(qname, propertyValue));
|
Collections.singletonMap(qname, propertyValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void addNodeProperties(Long nodeId, Map<QName, Serializable> properties)
|
public void addNodeProperties(Long nodeId, Map<QName, Serializable> properties)
|
||||||
{
|
{
|
||||||
Node node = getNodeNotNull(nodeId);
|
Node node = getNodeNotNull(nodeId);
|
||||||
@@ -1681,6 +1685,11 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
// Add them
|
// Add them
|
||||||
Set<Long> nodeAspects = node.getAspects();
|
Set<Long> nodeAspects = node.getAspects();
|
||||||
nodeAspects.addAll(aspectQNameIds);
|
nodeAspects.addAll(aspectQNameIds);
|
||||||
|
|
||||||
|
if (hasNodeAspect(node, ContentModel.ASPECT_ROOT))
|
||||||
|
{
|
||||||
|
parentAssocsCache.remove(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
// Record change ID
|
// Record change ID
|
||||||
recordNodeUpdate(node);
|
recordNodeUpdate(node);
|
||||||
@@ -1702,6 +1711,11 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
// Remove them
|
// Remove them
|
||||||
Set<Long> nodeAspects = node.getAspects();
|
Set<Long> nodeAspects = node.getAspects();
|
||||||
nodeAspects.removeAll(aspectQNameIds);
|
nodeAspects.removeAll(aspectQNameIds);
|
||||||
|
|
||||||
|
if (aspectQNames.contains(ContentModel.ASPECT_ROOT))
|
||||||
|
{
|
||||||
|
parentAssocsCache.remove(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
// Record change ID
|
// Record change ID
|
||||||
recordNodeUpdate(node);
|
recordNodeUpdate(node);
|
||||||
@@ -1719,6 +1733,11 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasNodeAspect(Node node, QName aspectQName)
|
private boolean hasNodeAspect(Node node, QName aspectQName)
|
||||||
|
{
|
||||||
|
return hasNodeAspect(qnameDAO, node, aspectQName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasNodeAspect(QNameDAO qnameDAO, Node node, QName aspectQName)
|
||||||
{
|
{
|
||||||
Pair<Long, QName> aspectQNamePair = qnameDAO.getQName(aspectQName);
|
Pair<Long, QName> aspectQNamePair = qnameDAO.getQName(aspectQName);
|
||||||
if (aspectQNamePair == null)
|
if (aspectQNamePair == null)
|
||||||
@@ -2055,30 +2074,24 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
childNameUnique.getFirst());
|
childNameUnique.getFirst());
|
||||||
|
|
||||||
// Add it to the cache
|
// Add it to the cache
|
||||||
Set<Long> parentAssocIds = parentAssocsCache.get(childNodeId);
|
NodeInfo nodeInfo = parentAssocsCache.get(childNodeId);
|
||||||
if (parentAssocIds == null)
|
if (nodeInfo == null)
|
||||||
{
|
{
|
||||||
// There isn't an entry in the cache, so go and make one
|
// There isn't an entry in the cache, so go and make one
|
||||||
Collection<ChildAssoc> parentAssocs = getParentAssocsInternal(childNodeId);
|
nodeInfo = getParentAssocsInternal(childNodeId);
|
||||||
parentAssocIds = new HashSet<Long>(3);
|
|
||||||
for (ChildAssoc childAssoc : parentAssocs)
|
|
||||||
{
|
|
||||||
parentAssocIds.add(childAssoc.getId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Copy the list when we add to it
|
// Copy the list when we add to it
|
||||||
parentAssocIds = new HashSet<Long>(parentAssocIds);
|
nodeInfo = nodeInfo.addAssoc(assocId, assoc, qnameDAO);
|
||||||
parentAssocIds.add(assocId);
|
parentAssocsCache.put(childNodeId, nodeInfo);
|
||||||
}
|
}
|
||||||
parentAssocsCache.put(childNodeId, parentAssocIds);
|
|
||||||
if (isDebugParentAssocCacheEnabled)
|
if (isDebugParentAssocCacheEnabled)
|
||||||
{
|
{
|
||||||
loggerParentAssocsCache.debug("\n" +
|
loggerParentAssocsCache.debug("\n" +
|
||||||
"Parent associations cache - Updating entry: \n" +
|
"Parent associations cache - Updating entry: \n" +
|
||||||
" Node: " + childNodeId + "\n" +
|
" Node: " + childNodeId + "\n" +
|
||||||
" Assocs: " + parentAssocIds);
|
" Assocs: " + nodeInfo.getParentAssocs().keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a primary association then update the permissions
|
// If this is a primary association then update the permissions
|
||||||
@@ -2294,7 +2307,10 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
return new Pair<Long, ChildAssociationRef>(childAssocId, childAssoc.getChildAssocRef(qnameDAO));
|
parentAssocsCache.remove(oldChildNode.getId());
|
||||||
|
parentAssocsCache.remove(childNodeId);
|
||||||
|
ParentAssocInfo parentAssocInfo = new ParentAssocInfo(childAssoc, qnameDAO);
|
||||||
|
return new Pair<Long, ChildAssociationRef>(childAssocId, parentAssocInfo.getChildAssociationRef());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2335,6 +2351,11 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
childNodeIds.add(childNodePair.getFirst());
|
childNodeIds.add(childNodePair.getFirst());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean preLoadNodes()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// Get all child associations with the specific qualified name
|
// Get all child associations with the specific qualified name
|
||||||
getChildAssocs(nodeId, callback, false);
|
getChildAssocs(nodeId, callback, false);
|
||||||
@@ -2364,7 +2385,6 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void getChildAssocs(final Long parentNodeId, final ChildAssocRefQueryCallback resultsCallback, final boolean recurse)
|
public void getChildAssocs(final Long parentNodeId, final ChildAssocRefQueryCallback resultsCallback, final boolean recurse)
|
||||||
{
|
{
|
||||||
Node parentNode = getNodeNotNull(parentNodeId);
|
Node parentNode = getNodeNotNull(parentNodeId);
|
||||||
@@ -2391,6 +2411,11 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean preLoadNodes()
|
||||||
|
{
|
||||||
|
return resultsCallback.preLoadNodes();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2431,7 +2456,6 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
// Done
|
// Done
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void getChildAssocs(final Long parentNodeId, final QName assocQName, ChildAssocRefQueryCallback resultsCallback)
|
public void getChildAssocs(final Long parentNodeId, final QName assocQName, ChildAssocRefQueryCallback resultsCallback)
|
||||||
{
|
{
|
||||||
final Pair<Long, String> assocQNameNamespacePair = qnameDAO.getNamespace(assocQName.getNamespaceURI());
|
final Pair<Long, String> assocQNameNamespacePair = qnameDAO.getNamespace(assocQName.getNamespaceURI());
|
||||||
@@ -2451,7 +2475,8 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
.getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_REFS_BY_QNAME)
|
.getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_REFS_BY_QNAME)
|
||||||
.setLong("parentId", parentNodeId)
|
.setLong("parentId", parentNodeId)
|
||||||
.setLong("qnameNamespaceId", assocQNameNamespacePair.getFirst())
|
.setLong("qnameNamespaceId", assocQNameNamespacePair.getFirst())
|
||||||
.setString("qnameLocalName", assocQNameLocalName);
|
.setString("qnameLocalName", assocQNameLocalName)
|
||||||
|
.setLong("qnameCrc", ChildAssocImpl.getCrc(assocQName));
|
||||||
DirtySessionMethodInterceptor.setQueryFlushMode(session, query);
|
DirtySessionMethodInterceptor.setQueryFlushMode(session, query);
|
||||||
return query.scroll(ScrollMode.FORWARD_ONLY);
|
return query.scroll(ScrollMode.FORWARD_ONLY);
|
||||||
}
|
}
|
||||||
@@ -2541,6 +2566,11 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
{
|
{
|
||||||
return resultsCallback.handle(childAssocPair, parentNodePair, childNodePair);
|
return resultsCallback.handle(childAssocPair, parentNodePair, childNodePair);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean preLoadNodes()
|
||||||
|
{
|
||||||
|
return resultsCallback.preLoadNodes();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ScrollableResults queryResults = null;
|
ScrollableResults queryResults = null;
|
||||||
@@ -2628,7 +2658,8 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
.setLong("parentId", parentNodeId)
|
.setLong("parentId", parentNodeId)
|
||||||
.setLong("typeQNameId", assocTypeQNamePair.getFirst())
|
.setLong("typeQNameId", assocTypeQNamePair.getFirst())
|
||||||
.setLong("qnameNamespaceId", assocQNameNamespacePair.getFirst())
|
.setLong("qnameNamespaceId", assocQNameNamespacePair.getFirst())
|
||||||
.setString("qnameLocalName", assocQNameLocalName);
|
.setString("qnameLocalName", assocQNameLocalName)
|
||||||
|
.setLong("qnameCrc", ChildAssocImpl.getCrc(assocQName));
|
||||||
DirtySessionMethodInterceptor.setQueryFlushMode(session, query);
|
DirtySessionMethodInterceptor.setQueryFlushMode(session, query);
|
||||||
return query.scroll(ScrollMode.FORWARD_ONLY);
|
return query.scroll(ScrollMode.FORWARD_ONLY);
|
||||||
}
|
}
|
||||||
@@ -2816,12 +2847,12 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
.setLong("childId", childNodeId)
|
.setLong("childId", childNodeId)
|
||||||
.setLong("typeQNameId", assocTypeQNamePair.getFirst())
|
.setLong("typeQNameId", assocTypeQNamePair.getFirst())
|
||||||
.setParameter("qnameNamespaceId", assocQNameNamespacePair.getFirst())
|
.setParameter("qnameNamespaceId", assocQNameNamespacePair.getFirst())
|
||||||
.setParameter("qnameLocalName", assocQNameLocalName);
|
.setParameter("qnameLocalName", assocQNameLocalName)
|
||||||
|
.setLong("qnameCrc", ChildAssocImpl.getCrc(assocQName));
|
||||||
DirtySessionMethodInterceptor.setQueryFlushMode(session, query);
|
DirtySessionMethodInterceptor.setQueryFlushMode(session, query);
|
||||||
return query.list();
|
return query.list();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
List<ChildAssoc> childAssocs = (List<ChildAssoc>) getHibernateTemplate().execute(callback);
|
List<ChildAssoc> childAssocs = (List<ChildAssoc>) getHibernateTemplate().execute(callback);
|
||||||
Pair<Long, ChildAssociationRef> ret = null;
|
Pair<Long, ChildAssociationRef> ret = null;
|
||||||
for (ChildAssoc childAssoc : childAssocs)
|
for (ChildAssoc childAssoc : childAssocs)
|
||||||
@@ -2912,16 +2943,19 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
/**
|
/**
|
||||||
* Columns returned are:
|
* Columns returned are:
|
||||||
* <pre>
|
* <pre>
|
||||||
0 assoc.id,
|
0 assoc.id,
|
||||||
1 assoc.typeQName,
|
1 assoc.typeQName,
|
||||||
2 assoc.qnameNamespace,
|
2 assoc.qnameNamespace,
|
||||||
3 assoc.qnameLocalName,
|
3 assoc.qnameLocalName,
|
||||||
4 assoc.isPrimary,
|
4 assoc.qnameCrc,
|
||||||
5 assoc.index,
|
5 assoc.childNodeName
|
||||||
6 child.id,
|
6 assoc.childNodeNameCrc
|
||||||
7 child.store.key.protocol,
|
7 assoc.isPrimary,
|
||||||
8 child.store.key.identifier,
|
8 assoc.index,
|
||||||
9 child.uuid
|
9 child.id,
|
||||||
|
10 child.store.key.protocol,
|
||||||
|
11 child.store.key.identifier,
|
||||||
|
12 child.uuid
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@@ -2942,14 +2976,14 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
String assocQNameNamespace = qnameDAO.getNamespace((Long) row[2]).getSecond();
|
String assocQNameNamespace = qnameDAO.getNamespace((Long) row[2]).getSecond();
|
||||||
String assocQNameLocalName = (String) row[3];
|
String assocQNameLocalName = (String) row[3];
|
||||||
QName assocQName = QName.createQName(assocQNameNamespace, assocQNameLocalName);
|
QName assocQName = QName.createQName(assocQNameNamespace, assocQNameLocalName);
|
||||||
String assocChildNodeName = (String) row[4];
|
String assocChildNodeName = (String) row[5];
|
||||||
Long assocChildNodeNameCrc = (Long) row[5];
|
Long assocChildNodeNameCrc = (Long) row[6];
|
||||||
Boolean assocIsPrimary = (Boolean) row[6];
|
Boolean assocIsPrimary = (Boolean) row[7];
|
||||||
Integer assocIndex = (Integer) row[7];
|
Integer assocIndex = (Integer) row[8];
|
||||||
Long childNodeId = (Long) row[8];
|
Long childNodeId = (Long) row[9];
|
||||||
String childProtocol = (String) row[9];
|
String childProtocol = (String) row[10];
|
||||||
String childIdentifier = (String) row[10];
|
String childIdentifier = (String) row[11];
|
||||||
String childUuid = (String) row[11];
|
String childUuid = (String) row[12];
|
||||||
NodeRef childNodeRef = new NodeRef(new StoreRef(childProtocol, childIdentifier), childUuid);
|
NodeRef childNodeRef = new NodeRef(new StoreRef(childProtocol, childIdentifier), childUuid);
|
||||||
ChildAssociationRef assocRef = new ChildAssociationRef(
|
ChildAssociationRef assocRef = new ChildAssociationRef(
|
||||||
assocTypeQName,
|
assocTypeQName,
|
||||||
@@ -2982,7 +3016,10 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cache the nodes
|
// Cache the nodes
|
||||||
cacheNodes(childNodeRefs);
|
if (resultsCallback.preLoadNodes() && !childNodeRefs.isEmpty())
|
||||||
|
{
|
||||||
|
cacheNodes(childNodeRefs);
|
||||||
|
}
|
||||||
|
|
||||||
// Pass results to callback
|
// Pass results to callback
|
||||||
for (Object[] callbackResult : callbackResults)
|
for (Object[] callbackResult : callbackResults)
|
||||||
@@ -3094,7 +3131,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
Long nodeId = node.getId();
|
Long nodeId = node.getId();
|
||||||
storeAndNodeIdCache.put(node.getNodeRef(), nodeId);
|
storeAndNodeIdCache.put(node.getNodeRef(), nodeId);
|
||||||
nodeIds.add(nodeId);
|
nodeIds.add(nodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodeIds.size() == 0)
|
if (nodeIds.size() == 0)
|
||||||
{
|
{
|
||||||
@@ -3108,20 +3145,17 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
criteria.setCacheMode(CacheMode.PUT);
|
criteria.setCacheMode(CacheMode.PUT);
|
||||||
criteria.setFlushMode(FlushMode.MANUAL);
|
criteria.setFlushMode(FlushMode.MANUAL);
|
||||||
List<ChildAssoc> parentAssocs = criteria.list();
|
List<ChildAssoc> parentAssocs = criteria.list();
|
||||||
|
Map<Long, List<ChildAssoc>> parentAssocMap = new HashMap<Long, List<ChildAssoc>>(nodeIds.size() * 2);
|
||||||
for (ChildAssoc parentAssoc : parentAssocs)
|
for (ChildAssoc parentAssoc : parentAssocs)
|
||||||
{
|
{
|
||||||
Long nodeId = parentAssoc.getChild().getId();
|
Long nodeId = parentAssoc.getChild().getId();
|
||||||
Set<Long> parentAssocsOfNode = parentAssocsCache.get(nodeId);
|
List<ChildAssoc> parentAssocsOfNode = parentAssocMap.get(nodeId);
|
||||||
if (parentAssocsOfNode == null)
|
if (parentAssocsOfNode == null)
|
||||||
{
|
{
|
||||||
parentAssocsOfNode = new HashSet<Long>(3);
|
parentAssocsOfNode = new ArrayList<ChildAssoc>(3);
|
||||||
|
parentAssocMap.put(nodeId, parentAssocsOfNode);
|
||||||
}
|
}
|
||||||
else
|
parentAssocsOfNode.add(parentAssoc);
|
||||||
{
|
|
||||||
parentAssocsOfNode = new HashSet<Long>(parentAssocsOfNode);
|
|
||||||
}
|
|
||||||
parentAssocsOfNode.add(parentAssoc.getId());
|
|
||||||
parentAssocsCache.put(nodeId, parentAssocsOfNode);
|
|
||||||
if (isDebugParentAssocCacheEnabled)
|
if (isDebugParentAssocCacheEnabled)
|
||||||
{
|
{
|
||||||
loggerParentAssocsCache.debug("\n" +
|
loggerParentAssocsCache.debug("\n" +
|
||||||
@@ -3130,6 +3164,17 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
" Assocs: " + parentAssocsOfNode);
|
" Assocs: " + parentAssocsOfNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Cache NodeInfo for each node
|
||||||
|
for (Node node : nodeList)
|
||||||
|
{
|
||||||
|
Long nodeId = node.getId();
|
||||||
|
List<ChildAssoc> parentAsssocsOfNode = parentAssocMap.get(nodeId);
|
||||||
|
if (parentAsssocsOfNode == null)
|
||||||
|
{
|
||||||
|
parentAsssocsOfNode = Collections.emptyList();
|
||||||
|
}
|
||||||
|
parentAssocsCache.put(nodeId, new NodeInfo(node, qnameDAO, parentAsssocsOfNode));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<Pair<Long, AssociationRef>> convertToAssocRefs(List<NodeAssoc> queryResults)
|
private Collection<Pair<Long, AssociationRef>> convertToAssocRefs(List<NodeAssoc> queryResults)
|
||||||
@@ -3364,19 +3409,18 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
Long childNodeId = childNode.getId();
|
Long childNodeId = childNode.getId();
|
||||||
|
|
||||||
// Add remove the child association from the cache
|
// Add remove the child association from the cache
|
||||||
Set<Long> oldParentAssocIds = parentAssocsCache.get(childNodeId);
|
NodeInfo oldNodeInfo = parentAssocsCache.get(childNodeId);
|
||||||
if (oldParentAssocIds != null)
|
if (oldNodeInfo != null)
|
||||||
{
|
{
|
||||||
Set<Long> newParentAssocIds = new HashSet<Long>(oldParentAssocIds);
|
NodeInfo newNodeInfo = oldNodeInfo.removeAssoc(childAssocId);
|
||||||
newParentAssocIds.remove(childAssocId);
|
parentAssocsCache.put(childNodeId, newNodeInfo);
|
||||||
parentAssocsCache.put(childNodeId, newParentAssocIds);
|
|
||||||
if (this.isDebugParentAssocCacheEnabled)
|
if (this.isDebugParentAssocCacheEnabled)
|
||||||
{
|
{
|
||||||
loggerParentAssocsCache.debug("\n" +
|
loggerParentAssocsCache.debug("\n" +
|
||||||
"Parent associations cache - Updating entry: \n" +
|
"Parent associations cache - Updating entry: \n" +
|
||||||
" Node: " + childNodeId + "\n" +
|
" Node: " + childNodeId + "\n" +
|
||||||
" Before: " + oldParentAssocIds + "\n" +
|
" Before: " + oldNodeInfo.getParentAssocs().keySet() + "\n" +
|
||||||
" After: " + newParentAssocIds);
|
" After: " + newNodeInfo.getParentAssocs().keySet());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3404,45 +3448,47 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
* @return Returns the parent associations without any interpretation
|
* @return Returns the parent associations without any interpretation
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Collection<ChildAssoc> getParentAssocsInternal(final Long childNodeId)
|
private NodeInfo getParentAssocsInternal(final Long childNodeId)
|
||||||
{
|
{
|
||||||
List<ChildAssoc> parentAssocs = null;
|
|
||||||
// First check the cache
|
// First check the cache
|
||||||
Set<Long> parentAssocIds = parentAssocsCache.get(childNodeId);
|
NodeInfo nodeInfo = parentAssocsCache.get(childNodeId);
|
||||||
if (parentAssocIds != null)
|
if (nodeInfo != null)
|
||||||
{
|
{
|
||||||
if (isDebugParentAssocCacheEnabled)
|
// Let's ensure this ref hasn't become stale due to a concurrent cascade delete
|
||||||
|
try
|
||||||
{
|
{
|
||||||
loggerParentAssocsCache.debug("\n" +
|
for (Long assocId : nodeInfo.getParentAssocs().keySet())
|
||||||
"Parent associations cache - Hit: \n" +
|
|
||||||
" Node: " + childNodeId + "\n" +
|
|
||||||
" Assocs: " + parentAssocIds);
|
|
||||||
}
|
|
||||||
parentAssocs = new ArrayList<ChildAssoc>(parentAssocIds.size());
|
|
||||||
for (Long parentAssocId : parentAssocIds)
|
|
||||||
{
|
|
||||||
ChildAssoc parentAssoc = (ChildAssoc) getSession().get(ChildAssocImpl.class, parentAssocId);
|
|
||||||
if (parentAssoc == null)
|
|
||||||
{
|
{
|
||||||
// The cache is out of date, so just repopulate it
|
getChildAssocNotNull(assocId);
|
||||||
parentAssocs = null;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
else
|
if (isDebugParentAssocCacheEnabled)
|
||||||
{
|
{
|
||||||
parentAssocs.add(parentAssoc);
|
loggerParentAssocsCache.debug("\n" + "Parent associations cache - Hit: \n" + " Node: "
|
||||||
|
+ childNodeId + "\n" + " Assocs: " + nodeInfo.getParentAssocs().keySet());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (ObjectNotFoundException e)
|
||||||
|
{
|
||||||
|
parentAssocsCache.remove(childNodeId);
|
||||||
|
nodeInfo = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Did we manage to get the parent assocs
|
// Did we manage to get the parent assocs
|
||||||
if (parentAssocs == null)
|
if (nodeInfo == null)
|
||||||
{
|
{
|
||||||
|
// Assume stale data if the node has been deleted
|
||||||
|
Node node = getNodeNotNull(childNodeId);
|
||||||
|
if (node.getDeleted())
|
||||||
|
{
|
||||||
|
throw new ObjectNotFoundException(childNodeId, NodeImpl.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
if (isDebugParentAssocCacheEnabled)
|
if (isDebugParentAssocCacheEnabled)
|
||||||
{
|
{
|
||||||
loggerParentAssocsCache.debug("\n" +
|
loggerParentAssocsCache.debug("\n" +
|
||||||
"Parent associations cache - Miss: \n" +
|
"Parent associations cache - Miss: \n" +
|
||||||
" Node: " + childNodeId + "\n" +
|
" Node: " + childNodeId + "\n" +
|
||||||
" Assocs: " + parentAssocIds);
|
" Assocs: null");
|
||||||
}
|
}
|
||||||
HibernateCallback callback = new HibernateCallback()
|
HibernateCallback callback = new HibernateCallback()
|
||||||
{
|
{
|
||||||
@@ -3456,29 +3502,163 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
List<Object[]> rows = (List<Object[]>) getHibernateTemplate().execute(callback);
|
List<Object[]> rows = (List<Object[]>) getHibernateTemplate().execute(callback);
|
||||||
parentAssocs = new ArrayList<ChildAssoc>(rows.size());
|
|
||||||
parentAssocIds = new HashSet<Long>(parentAssocs.size());
|
nodeInfo = new NodeInfo(node, qnameDAO, rows);
|
||||||
for (Object[] row : rows)
|
|
||||||
{
|
|
||||||
ChildAssoc parentAssoc = (ChildAssoc) row[0];
|
|
||||||
// Populate the results
|
|
||||||
parentAssocs.add(parentAssoc);
|
|
||||||
parentAssocIds.add(parentAssoc.getId());
|
|
||||||
}
|
|
||||||
// Populate the cache
|
// Populate the cache
|
||||||
parentAssocsCache.put(childNodeId, parentAssocIds);
|
parentAssocsCache.put(childNodeId, nodeInfo);
|
||||||
if (isDebugParentAssocCacheEnabled)
|
if (isDebugParentAssocCacheEnabled)
|
||||||
{
|
{
|
||||||
loggerParentAssocsCache.debug("\n" +
|
loggerParentAssocsCache.debug("\n" +
|
||||||
"Parent associations cache - Adding entry: \n" +
|
"Parent associations cache - Adding entry: \n" +
|
||||||
" Node: " + childNodeId + "\n" +
|
" Node: " + childNodeId + "\n" +
|
||||||
" Assocs: " + parentAssocIds);
|
" Assocs: " + nodeInfo.getParentAssocs().keySet());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
return parentAssocs;
|
return nodeInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive method used to build up paths from a given node to the root.
|
||||||
|
* <p>
|
||||||
|
* Whilst walking up the hierarchy to the root, some nodes may have a <b>root</b> aspect.
|
||||||
|
* Everytime one of these is encountered, a new path is farmed off, but the method
|
||||||
|
* continues to walk up the hierarchy.
|
||||||
|
*
|
||||||
|
* @param currentNode the node to start from, i.e. the child node to work upwards from
|
||||||
|
* @param currentPath the path from the current node to the descendent that we started from
|
||||||
|
* @param completedPaths paths that have reached the root are added to this collection
|
||||||
|
* @param assocStack the parent-child relationships traversed whilst building the path.
|
||||||
|
* Used to detected cyclic relationships.
|
||||||
|
* @param primaryOnly true if only the primary parent association must be traversed.
|
||||||
|
* If this is true, then the only root is the top level node having no parents.
|
||||||
|
* @throws CyclicChildRelationshipException
|
||||||
|
*/
|
||||||
|
public void prependPaths(
|
||||||
|
Pair<Long, NodeRef> currentNodePair,
|
||||||
|
Pair<StoreRef, NodeRef> currentRootNodePair,
|
||||||
|
Path currentPath,
|
||||||
|
Collection<Path> completedPaths,
|
||||||
|
Stack<Long> assocIdStack,
|
||||||
|
boolean primaryOnly)
|
||||||
|
throws CyclicChildRelationshipException
|
||||||
|
{
|
||||||
|
Long currentNodeId = currentNodePair.getFirst();
|
||||||
|
NodeRef currentNodeRef = currentNodePair.getSecond();
|
||||||
|
|
||||||
|
// Check if we have changed root nodes
|
||||||
|
StoreRef currentStoreRef = currentNodeRef.getStoreRef();
|
||||||
|
if (currentRootNodePair == null || !currentStoreRef.equals(currentRootNodePair.getFirst()))
|
||||||
|
{
|
||||||
|
// We've changed stores
|
||||||
|
Pair<Long, NodeRef> rootNodePair = getRootNode(currentStoreRef);
|
||||||
|
currentRootNodePair = new Pair<StoreRef, NodeRef>(currentStoreRef, rootNodePair.getSecond());
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the parent associations of the given node
|
||||||
|
NodeInfo nodeInfo = getParentAssocsInternal(currentNodeId);
|
||||||
|
|
||||||
|
// does the node have parents
|
||||||
|
boolean hasParents = nodeInfo.getParentAssocs().size() > 0;
|
||||||
|
// does the current node have a root aspect?
|
||||||
|
|
||||||
|
// look for a root. If we only want the primary root, then ignore all but the top-level root.
|
||||||
|
if (!(primaryOnly && hasParents) && nodeInfo.isRoot()) // exclude primary search with parents present
|
||||||
|
{
|
||||||
|
// create a one-sided assoc ref for the root node and prepend to the stack
|
||||||
|
// this effectively spoofs the fact that the current node is not below the root
|
||||||
|
// - we put this assoc in as the first assoc in the path must be a one-sided
|
||||||
|
// reference pointing to the root node
|
||||||
|
ChildAssociationRef assocRef = new ChildAssociationRef(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
currentRootNodePair.getSecond());
|
||||||
|
// create a path to save and add the 'root' assoc
|
||||||
|
Path pathToSave = new Path();
|
||||||
|
Path.ChildAssocElement first = null;
|
||||||
|
for (Path.Element element: currentPath)
|
||||||
|
{
|
||||||
|
if (first == null)
|
||||||
|
{
|
||||||
|
first = (Path.ChildAssocElement) element;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pathToSave.append(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (first != null)
|
||||||
|
{
|
||||||
|
// mimic an association that would appear if the current node was below the root node
|
||||||
|
// or if first beneath the root node it will make the real thing
|
||||||
|
ChildAssociationRef updateAssocRef = new ChildAssociationRef(
|
||||||
|
nodeInfo.isStoreRoot() ? ContentModel.ASSOC_CHILDREN : first.getRef().getTypeQName(),
|
||||||
|
currentRootNodePair.getSecond(),
|
||||||
|
first.getRef().getQName(),
|
||||||
|
first.getRef().getChildRef());
|
||||||
|
Path.Element newFirst = new Path.ChildAssocElement(updateAssocRef);
|
||||||
|
pathToSave.prepend(newFirst);
|
||||||
|
}
|
||||||
|
|
||||||
|
Path.Element element = new Path.ChildAssocElement(assocRef);
|
||||||
|
pathToSave.prepend(element);
|
||||||
|
|
||||||
|
// store the path just built
|
||||||
|
completedPaths.add(pathToSave);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasParents && !nodeInfo.isRoot())
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Node without parents does not have root aspect: " +
|
||||||
|
currentNodeRef);
|
||||||
|
}
|
||||||
|
// walk up each parent association
|
||||||
|
for (Map.Entry<Long, ParentAssocInfo> entry: nodeInfo.getParentAssocs().entrySet())
|
||||||
|
{
|
||||||
|
Long assocId = entry.getKey();
|
||||||
|
ParentAssocInfo parentAssocInfo = entry.getValue();
|
||||||
|
ChildAssociationRef assocRef = parentAssocInfo.getChildAssociationRef();
|
||||||
|
// do we consider only primary assocs?
|
||||||
|
if (primaryOnly && !assocRef.isPrimary())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Ordering is meaningless here as we are constructing a path upwards
|
||||||
|
// and have no idea where the node comes in the sibling order or even
|
||||||
|
// if there are like-pathed siblings.
|
||||||
|
assocRef.setNthSibling(-1);
|
||||||
|
// build a path element
|
||||||
|
Path.Element element = new Path.ChildAssocElement(assocRef);
|
||||||
|
// create a new path that builds on the current path
|
||||||
|
Path path = new Path();
|
||||||
|
path.append(currentPath);
|
||||||
|
// prepend element
|
||||||
|
path.prepend(element);
|
||||||
|
// get parent node pair
|
||||||
|
Pair<Long, NodeRef> parentNodePair = new Pair<Long, NodeRef>(parentAssocInfo.getParentNodeId(), assocRef.getParentRef());
|
||||||
|
|
||||||
|
// does the association already exist in the stack
|
||||||
|
if (assocIdStack.contains(assocId))
|
||||||
|
{
|
||||||
|
// the association was present already
|
||||||
|
throw new CyclicChildRelationshipException(
|
||||||
|
"Cyclic parent-child relationship detected: \n" +
|
||||||
|
" current node: " + currentNodeId + "\n" +
|
||||||
|
" current path: " + currentPath + "\n" +
|
||||||
|
" next assoc: " + assocId,
|
||||||
|
assocRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// push the assoc stack, recurse and pop
|
||||||
|
assocIdStack.push(assocId);
|
||||||
|
prependPaths(parentNodePair, currentRootNodePair, path, completedPaths, assocIdStack, primaryOnly);
|
||||||
|
assocIdStack.pop();
|
||||||
|
}
|
||||||
|
// done
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
@@ -3486,14 +3666,14 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
*/
|
*/
|
||||||
public Collection<Pair<Long, ChildAssociationRef>> getParentAssocs(final Long childNodeId)
|
public Collection<Pair<Long, ChildAssociationRef>> getParentAssocs(final Long childNodeId)
|
||||||
{
|
{
|
||||||
Collection<ChildAssoc> parentAssocs = getParentAssocsInternal(childNodeId);
|
NodeInfo nodeInfo = getParentAssocsInternal(childNodeId);
|
||||||
|
Map <Long, ParentAssocInfo> parentAssocs = nodeInfo.getParentAssocs();
|
||||||
Collection<Pair<Long, ChildAssociationRef>> ret = new ArrayList<Pair<Long, ChildAssociationRef>>(parentAssocs.size());
|
Collection<Pair<Long, ChildAssociationRef>> ret = new ArrayList<Pair<Long, ChildAssociationRef>>(parentAssocs.size());
|
||||||
|
|
||||||
for (ChildAssoc childAssoc : parentAssocs)
|
for (Map.Entry<Long, ParentAssocInfo> entry : parentAssocs.entrySet())
|
||||||
{
|
{
|
||||||
Long childAssocId = childAssoc.getId();
|
Pair<Long, ChildAssociationRef> childAssocPair = new Pair<Long, ChildAssociationRef>(entry.getKey(), entry
|
||||||
ChildAssociationRef childAssocRef = childAssoc.getChildAssocRef(qnameDAO);
|
.getValue().getChildAssociationRef());
|
||||||
Pair<Long, ChildAssociationRef> childAssocPair = new Pair<Long, ChildAssociationRef>(childAssocId, childAssocRef);
|
|
||||||
ret.add(childAssocPair);
|
ret.add(childAssocPair);
|
||||||
}
|
}
|
||||||
// Done
|
// Done
|
||||||
@@ -3512,12 +3692,13 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
public Pair<Long, ChildAssociationRef> getPrimaryParentAssoc(Long childNodeId)
|
public Pair<Long, ChildAssociationRef> getPrimaryParentAssoc(Long childNodeId)
|
||||||
{
|
{
|
||||||
// get the assocs pointing to the node
|
// get the assocs pointing to the node
|
||||||
Collection<ChildAssoc> parentAssocs = getParentAssocsInternal(childNodeId);
|
NodeInfo nodeInfo = getParentAssocsInternal(childNodeId);
|
||||||
ChildAssoc primaryAssoc = null;
|
Pair<Long, ChildAssociationRef> primaryAssoc = null;
|
||||||
for (ChildAssoc assoc : parentAssocs)
|
for (Map.Entry<Long, ParentAssocInfo> entry : nodeInfo.getParentAssocs().entrySet())
|
||||||
{
|
{
|
||||||
|
ChildAssociationRef assoc = entry.getValue().getChildAssociationRef();
|
||||||
// ignore non-primary assocs
|
// ignore non-primary assocs
|
||||||
if (!assoc.getIsPrimary())
|
if (!assoc.isPrimary())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -3537,7 +3718,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
primaryAssoc = assoc;
|
primaryAssoc = new Pair<Long, ChildAssociationRef>(entry.getKey(), assoc);
|
||||||
// we keep looping to hunt out data integrity issues
|
// we keep looping to hunt out data integrity issues
|
||||||
}
|
}
|
||||||
// done
|
// done
|
||||||
@@ -3547,7 +3728,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new Pair<Long, ChildAssociationRef>(primaryAssoc.getId(), primaryAssoc.getChildAssocRef(qnameDAO));
|
return primaryAssoc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4092,7 +4273,6 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void getNodesDeletedInOldTxns(
|
public void getNodesDeletedInOldTxns(
|
||||||
final Long minNodeId,
|
final Long minNodeId,
|
||||||
long maxCommitTime,
|
long maxCommitTime,
|
||||||
@@ -4243,7 +4423,6 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
return txns;
|
return txns;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public int getTxnUpdateCount(final long txnId)
|
public int getTxnUpdateCount(final long txnId)
|
||||||
{
|
{
|
||||||
HibernateCallback callback = new HibernateCallback()
|
HibernateCallback callback = new HibernateCallback()
|
||||||
@@ -4262,7 +4441,6 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
return count.intValue();
|
return count.intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public int getTxnDeleteCount(final long txnId)
|
public int getTxnDeleteCount(final long txnId)
|
||||||
{
|
{
|
||||||
HibernateCallback callback = new HibernateCallback()
|
HibernateCallback callback = new HibernateCallback()
|
||||||
@@ -4281,7 +4459,6 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
return count.intValue();
|
return count.intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public int getTransactionCount()
|
public int getTransactionCount()
|
||||||
{
|
{
|
||||||
HibernateCallback callback = new HibernateCallback()
|
HibernateCallback callback = new HibernateCallback()
|
||||||
@@ -4669,7 +4846,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
if (propertyTypeQName.equals(DataTypeDefinition.ANY))
|
if (propertyTypeQName.equals(DataTypeDefinition.ANY))
|
||||||
{
|
{
|
||||||
// It is multi-valued if required (we are not in a collection and the property is a new collection)
|
// It is multi-valued if required (we are not in a collection and the property is a new collection)
|
||||||
isMultiValued = (value != null) && (value instanceof Collection) && (collectionIndex == IDX_NO_COLLECTION);
|
isMultiValued = (value != null) && (value instanceof Collection<?>) && (collectionIndex == IDX_NO_COLLECTION);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -4679,7 +4856,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
// Handle different scenarios.
|
// Handle different scenarios.
|
||||||
// - Do we need to explode a collection?
|
// - Do we need to explode a collection?
|
||||||
// - Does the property allow collections?
|
// - Does the property allow collections?
|
||||||
if (collectionIndex == IDX_NO_COLLECTION && isMultiValued && !(value instanceof Collection))
|
if (collectionIndex == IDX_NO_COLLECTION && isMultiValued && !(value instanceof Collection<?>))
|
||||||
{
|
{
|
||||||
// We are not (yet) processing a collection but the property should be part of a collection
|
// We are not (yet) processing a collection but the property should be part of a collection
|
||||||
HibernateNodeDaoServiceImpl.addValueToPersistedProperties(
|
HibernateNodeDaoServiceImpl.addValueToPersistedProperties(
|
||||||
@@ -4692,7 +4869,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
localeDAO,
|
localeDAO,
|
||||||
contentDataDAO);
|
contentDataDAO);
|
||||||
}
|
}
|
||||||
else if (collectionIndex == IDX_NO_COLLECTION && value instanceof Collection)
|
else if (collectionIndex == IDX_NO_COLLECTION && value instanceof Collection<?>)
|
||||||
{
|
{
|
||||||
// We are not (yet) processing a collection and the property is a collection i.e. needs exploding
|
// We are not (yet) processing a collection and the property is a collection i.e. needs exploding
|
||||||
// Check that multi-valued properties are supported if the property is a collection
|
// Check that multi-valued properties are supported if the property is a collection
|
||||||
@@ -4762,7 +4939,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
{
|
{
|
||||||
// We are either processing collection elements OR the property is not a collection
|
// We are either processing collection elements OR the property is not a collection
|
||||||
// Collections of collections are only supported by type d:any
|
// Collections of collections are only supported by type d:any
|
||||||
if (value instanceof Collection && !propertyTypeQName.equals(DataTypeDefinition.ANY))
|
if (value instanceof Collection<?> && !propertyTypeQName.equals(DataTypeDefinition.ANY))
|
||||||
{
|
{
|
||||||
throw new DictionaryException(
|
throw new DictionaryException(
|
||||||
"Collections of collections (Serializable) are only supported by type 'd:any': \n" +
|
"Collections of collections (Serializable) are only supported by type 'd:any': \n" +
|
||||||
@@ -4959,7 +5136,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
// If the property is multi-valued then the output property must be a collection
|
// If the property is multi-valued then the output property must be a collection
|
||||||
if (currentPropertyDef != null && currentPropertyDef.isMultiValued())
|
if (currentPropertyDef != null && currentPropertyDef.isMultiValued())
|
||||||
{
|
{
|
||||||
if (collapsedValue != null && !(collapsedValue instanceof Collection))
|
if (collapsedValue != null && !(collapsedValue instanceof Collection<?>))
|
||||||
{
|
{
|
||||||
// Can't use Collections.singletonList: ETHREEOH-1172
|
// Can't use Collections.singletonList: ETHREEOH-1172
|
||||||
ArrayList<Serializable> collection = new ArrayList<Serializable>(1);
|
ArrayList<Serializable> collection = new ArrayList<Serializable>(1);
|
||||||
@@ -5059,7 +5236,7 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Make sure that multi-valued properties are returned as a collection
|
// Make sure that multi-valued properties are returned as a collection
|
||||||
if (propertyDef != null && propertyDef.isMultiValued() && result != null && !(result instanceof Collection))
|
if (propertyDef != null && propertyDef.isMultiValued() && result != null && !(result instanceof Collection<?>))
|
||||||
{
|
{
|
||||||
// Can't use Collections.singletonList: ETHREEOH-1172
|
// Can't use Collections.singletonList: ETHREEOH-1172
|
||||||
ArrayList<Serializable> collection = new ArrayList<Serializable>(1);
|
ArrayList<Serializable> collection = new ArrayList<Serializable>(1);
|
||||||
@@ -5198,4 +5375,104 @@ public class HibernateNodeDaoServiceImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class NodeInfo implements Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = -2167221525380802365L;
|
||||||
|
private final boolean isRoot;
|
||||||
|
private final boolean isStoreRoot;
|
||||||
|
private final Map<Long, ParentAssocInfo> parentAssocInfo;
|
||||||
|
|
||||||
|
public NodeInfo(Node node, QNameDAO qnameDAO, List<? extends Object> parents)
|
||||||
|
{
|
||||||
|
this.isRoot = hasNodeAspect(qnameDAO, node, ContentModel.ASPECT_ROOT);
|
||||||
|
this.isStoreRoot = node.getTypeQName(qnameDAO).equals(ContentModel.TYPE_STOREROOT);
|
||||||
|
this.parentAssocInfo = new HashMap<Long, ParentAssocInfo>(5);
|
||||||
|
for (Object parent : parents)
|
||||||
|
{
|
||||||
|
ChildAssoc parentAssoc = null;
|
||||||
|
if (parent instanceof ChildAssoc)
|
||||||
|
{
|
||||||
|
parentAssoc = (ChildAssoc) parent;
|
||||||
|
}
|
||||||
|
else if (parent.getClass().isArray())
|
||||||
|
{
|
||||||
|
parentAssoc = (ChildAssoc) Array.get(parent, 0);
|
||||||
|
}
|
||||||
|
if (parentAssoc != null)
|
||||||
|
{
|
||||||
|
// Populate the results
|
||||||
|
parentAssocInfo.put(parentAssoc.getId(), new ParentAssocInfo(parentAssoc, qnameDAO));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private NodeInfo(NodeInfo copy)
|
||||||
|
{
|
||||||
|
this.isRoot = copy.isRoot;
|
||||||
|
this.isStoreRoot = copy.isStoreRoot;
|
||||||
|
this.parentAssocInfo = new HashMap<Long, ParentAssocInfo>(copy.parentAssocInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRoot()
|
||||||
|
{
|
||||||
|
return isRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStoreRoot()
|
||||||
|
{
|
||||||
|
return isStoreRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Long, ParentAssocInfo> getParentAssocs()
|
||||||
|
{
|
||||||
|
return parentAssocInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeInfo addAssoc(Long assocId, ChildAssoc parentAssoc, QNameDAO qnameDAO)
|
||||||
|
{
|
||||||
|
return addAssoc(assocId, new ParentAssocInfo(parentAssoc, qnameDAO));
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeInfo addAssoc(Long assocId, ParentAssocInfo parentAssocInfo)
|
||||||
|
{
|
||||||
|
NodeInfo copy = new NodeInfo(this);
|
||||||
|
copy.parentAssocInfo.put(assocId, parentAssocInfo);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeInfo removeAssoc(Long assocId)
|
||||||
|
{
|
||||||
|
NodeInfo copy = new NodeInfo(this);
|
||||||
|
copy.parentAssocInfo.remove(assocId);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ParentAssocInfo implements Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = -3888870827401574704L;
|
||||||
|
private final ChildAssociationRef childAssociationRef;
|
||||||
|
private final Long parentNodeId;
|
||||||
|
|
||||||
|
public ParentAssocInfo(ChildAssoc parentAssoc, QNameDAO qnameDAO)
|
||||||
|
{
|
||||||
|
this.childAssociationRef = parentAssoc.getChildAssocRef(qnameDAO);
|
||||||
|
this.parentNodeId = parentAssoc.getParent().getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChildAssociationRef getChildAssociationRef()
|
||||||
|
{
|
||||||
|
// Return a copy, as it's mutated by prependPaths
|
||||||
|
return new ChildAssociationRef(childAssociationRef.getTypeQName(), childAssociationRef.getParentRef(),
|
||||||
|
childAssociationRef.getQName(), childAssociationRef.getChildRef(), childAssociationRef.isPrimary(),
|
||||||
|
childAssociationRef.getNthSibling());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getParentNodeId()
|
||||||
|
{
|
||||||
|
return parentNodeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@@ -179,7 +179,7 @@ public abstract class AbstractLuceneIndexerAndSearcherFactory implements LuceneI
|
|||||||
|
|
||||||
private int mergerTargetOverlayCount = 5;
|
private int mergerTargetOverlayCount = 5;
|
||||||
|
|
||||||
private int mergerTargetOverlaysBlockingFactor = 2;
|
private int mergerTargetOverlaysBlockingFactor = 1;
|
||||||
|
|
||||||
private int termIndexInterval =IndexWriter.DEFAULT_TERM_INDEX_INTERVAL;
|
private int termIndexInterval =IndexWriter.DEFAULT_TERM_INDEX_INTERVAL;
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@@ -677,7 +677,7 @@ public abstract class AbstractLuceneIndexerImpl<T> extends AbstractLuceneBase
|
|||||||
{
|
{
|
||||||
if (commandList.size() > 0)
|
if (commandList.size() > 0)
|
||||||
{
|
{
|
||||||
Command last = commandList.get(commandList.size() - 1);
|
Command<T> last = commandList.get(commandList.size() - 1);
|
||||||
if ((last.action == command.action) && (last.ref.equals(command.ref)))
|
if ((last.action == command.action) && (last.ref.equals(command.ref)))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -692,7 +692,7 @@ public abstract class AbstractLuceneIndexerImpl<T> extends AbstractLuceneBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void purgeCommandList(Command command)
|
private void purgeCommandList(Command<T> command)
|
||||||
{
|
{
|
||||||
if (command.action == Action.DELETE)
|
if (command.action == Action.DELETE)
|
||||||
{
|
{
|
||||||
@@ -712,17 +712,27 @@ public abstract class AbstractLuceneIndexerImpl<T> extends AbstractLuceneBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeFromCommandList(Command command, boolean matchExact)
|
private void removeFromCommandList(Command<T> command, boolean matchExact)
|
||||||
{
|
{
|
||||||
for (ListIterator<Command<T>> it = commandList.listIterator(commandList.size()); it.hasPrevious(); /**/)
|
for (ListIterator<Command<T>> it = commandList.listIterator(commandList.size()); it.hasPrevious(); /**/)
|
||||||
{
|
{
|
||||||
Command<T> current = it.previous();
|
Command<T> current = it.previous();
|
||||||
if (matchExact)
|
if (matchExact)
|
||||||
{
|
{
|
||||||
if ((current.action == command.action) && (current.ref.equals(command.ref)))
|
if (current.ref.equals(command.ref))
|
||||||
{
|
{
|
||||||
it.remove();
|
if ((current.action == command.action))
|
||||||
return;
|
{
|
||||||
|
it.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If there is an INDEX in this same transaction and the current command is a reindex, remove it and
|
||||||
|
// replace the current command with it
|
||||||
|
else if (command.action != Action.DELETE && current.action == Action.INDEX)
|
||||||
|
{
|
||||||
|
it.remove();
|
||||||
|
command.action = Action.INDEX;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -746,7 +756,7 @@ public abstract class AbstractLuceneIndexerImpl<T> extends AbstractLuceneBase
|
|||||||
mainReader = getReader();
|
mainReader = getReader();
|
||||||
Set<String> forIndex = new LinkedHashSet<String>();
|
Set<String> forIndex = new LinkedHashSet<String>();
|
||||||
|
|
||||||
for (Command command : commandList)
|
for (Command<T> command : commandList)
|
||||||
{
|
{
|
||||||
if (command.action == Action.INDEX)
|
if (command.action == Action.INDEX)
|
||||||
{
|
{
|
||||||
|
@@ -323,7 +323,7 @@ public class IndexInfo implements IndexMonitor
|
|||||||
|
|
||||||
private int mergerTargetOverlays = 5;
|
private int mergerTargetOverlays = 5;
|
||||||
|
|
||||||
private int mergerTargetOverlaysBlockingFactor = 2;
|
private int mergerTargetOverlaysBlockingFactor = 1;
|
||||||
|
|
||||||
// Common properties for indexers
|
// Common properties for indexers
|
||||||
|
|
||||||
|
@@ -251,7 +251,7 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
|
|||||||
if (container != null)
|
if (container != null)
|
||||||
{
|
{
|
||||||
for (ChildAssociationRef childRef : nodeService.getChildAssocs(container,
|
for (ChildAssociationRef childRef : nodeService.getChildAssocs(container,
|
||||||
ContentModel.ASSOC_CHILDREN, RegexQNamePattern.MATCH_ALL))
|
ContentModel.ASSOC_CHILDREN, RegexQNamePattern.MATCH_ALL, false))
|
||||||
{
|
{
|
||||||
addAuthorityNameIfMatches(authorities, childRef.getQName().getLocalName(), type, pattern);
|
addAuthorityNameIfMatches(authorities, childRef.getQName().getLocalName(), type, pattern);
|
||||||
}
|
}
|
||||||
@@ -267,7 +267,7 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
|
|||||||
if (container != null)
|
if (container != null)
|
||||||
{
|
{
|
||||||
for (ChildAssociationRef childRef : nodeService.getChildAssocs(container,
|
for (ChildAssociationRef childRef : nodeService.getChildAssocs(container,
|
||||||
ContentModel.ASSOC_IN_ZONE, RegexQNamePattern.MATCH_ALL))
|
ContentModel.ASSOC_IN_ZONE, RegexQNamePattern.MATCH_ALL, false))
|
||||||
{
|
{
|
||||||
addAuthorityNameIfMatches(authorities, childRef.getQName().getLocalName(), type,
|
addAuthorityNameIfMatches(authorities, childRef.getQName().getLocalName(), type,
|
||||||
pattern);
|
pattern);
|
||||||
@@ -427,7 +427,7 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
List<ChildAssociationRef> results = nodeService.getChildAssocs(getAuthorityContainer(),
|
List<ChildAssociationRef> results = nodeService.getChildAssocs(getAuthorityContainer(),
|
||||||
ContentModel.ASSOC_CHILDREN, QName.createQName("cm", name, namespacePrefixResolver));
|
ContentModel.ASSOC_CHILDREN, QName.createQName("cm", name, namespacePrefixResolver), false);
|
||||||
return results.isEmpty() ? null : results.get(0).getChildRef();
|
return results.isEmpty() ? null : results.get(0).getChildRef();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -468,13 +468,13 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
|
|||||||
if (systemContainerRef == null)
|
if (systemContainerRef == null)
|
||||||
{
|
{
|
||||||
NodeRef rootNodeRef = nodeService.getRootNode(this.storeRef);
|
NodeRef rootNodeRef = nodeService.getRootNode(this.storeRef);
|
||||||
List<ChildAssociationRef> results = nodeService.getChildAssocs(rootNodeRef, RegexQNamePattern.MATCH_ALL, qnameAssocSystem);
|
List<ChildAssociationRef> results = nodeService.getChildAssocs(rootNodeRef, RegexQNamePattern.MATCH_ALL, qnameAssocSystem, false);
|
||||||
if (results.size() == 0)
|
if (results.size() == 0)
|
||||||
{
|
{
|
||||||
throw new AlfrescoRuntimeException("Required system path not found: " + qnameAssocSystem);
|
throw new AlfrescoRuntimeException("Required system path not found: " + qnameAssocSystem);
|
||||||
}
|
}
|
||||||
NodeRef sysNodeRef = results.get(0).getChildRef();
|
NodeRef sysNodeRef = results.get(0).getChildRef();
|
||||||
results = nodeService.getChildAssocs(sysNodeRef, RegexQNamePattern.MATCH_ALL, assocQName);
|
results = nodeService.getChildAssocs(sysNodeRef, RegexQNamePattern.MATCH_ALL, assocQName, false);
|
||||||
if (results.size() == 0)
|
if (results.size() == 0)
|
||||||
{
|
{
|
||||||
throw new AlfrescoRuntimeException("Required path not found: " + assocQName);
|
throw new AlfrescoRuntimeException("Required path not found: " + assocQName);
|
||||||
@@ -543,7 +543,7 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
|
|||||||
{
|
{
|
||||||
NodeRef zoneContainerRef = getZoneContainer();
|
NodeRef zoneContainerRef = getZoneContainer();
|
||||||
QName zoneQName = QName.createQName("cm", zoneName, namespacePrefixResolver);
|
QName zoneQName = QName.createQName("cm", zoneName, namespacePrefixResolver);
|
||||||
List<ChildAssociationRef> results = nodeService.getChildAssocs(zoneContainerRef, ContentModel.ASSOC_CHILDREN, zoneQName);
|
List<ChildAssociationRef> results = nodeService.getChildAssocs(zoneContainerRef, ContentModel.ASSOC_CHILDREN, zoneQName, false);
|
||||||
if (results.isEmpty())
|
if (results.isEmpty())
|
||||||
{
|
{
|
||||||
if (create)
|
if (create)
|
||||||
@@ -605,7 +605,7 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
|
|||||||
NodeRef zoneRef = getZone(zoneName);
|
NodeRef zoneRef = getZone(zoneName);
|
||||||
if (zoneRef != null)
|
if (zoneRef != null)
|
||||||
{
|
{
|
||||||
for (ChildAssociationRef childRef : nodeService.getChildAssocs(zoneRef, ContentModel.ASSOC_IN_ZONE, RegexQNamePattern.MATCH_ALL))
|
for (ChildAssociationRef childRef : nodeService.getChildAssocs(zoneRef, ContentModel.ASSOC_IN_ZONE, RegexQNamePattern.MATCH_ALL, false))
|
||||||
{
|
{
|
||||||
addAuthorityNameIfMatches(authorities, childRef.getQName().getLocalName(), type, null);
|
addAuthorityNameIfMatches(authorities, childRef.getQName().getLocalName(), type, null);
|
||||||
}
|
}
|
||||||
|
@@ -116,9 +116,20 @@ public class HomeFolderManager implements NodeServicePolicies.OnCreateNodePolicy
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the provider and call.
|
* Find the provider and call if eager home folder creation is enabled.
|
||||||
*/
|
*/
|
||||||
public void onCreateNode(ChildAssociationRef childAssocRef)
|
public void onCreateNode(ChildAssociationRef childAssocRef)
|
||||||
|
{
|
||||||
|
if (enableHomeFolderCreationAsPeopleAreCreated)
|
||||||
|
{
|
||||||
|
makeHomeFolder(childAssocRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the provider and call.
|
||||||
|
*/
|
||||||
|
public void makeHomeFolder(ChildAssociationRef childAssocRef)
|
||||||
{
|
{
|
||||||
HomeFolderProvider provider = defaultProvider;
|
HomeFolderProvider provider = defaultProvider;
|
||||||
String providerName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(childAssocRef
|
String providerName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(childAssocRef
|
||||||
|
@@ -350,7 +350,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
|
|||||||
{
|
{
|
||||||
List<ChildAssociationRef> childRefs = nodeService.getChildAssocs(getPeopleContainer(),
|
List<ChildAssociationRef> childRefs = nodeService.getChildAssocs(getPeopleContainer(),
|
||||||
ContentModel.ASSOC_CHILDREN, QName.createQName("cm", searchUserName.toLowerCase(),
|
ContentModel.ASSOC_CHILDREN, QName.createQName("cm", searchUserName.toLowerCase(),
|
||||||
namespacePrefixResolver));
|
namespacePrefixResolver), false);
|
||||||
allRefs = new LinkedHashMap<String, NodeRef>(childRefs.size() * 2);
|
allRefs = new LinkedHashMap<String, NodeRef>(childRefs.size() * 2);
|
||||||
// add to cache
|
// add to cache
|
||||||
personCache.put(cacheKey, allRefs);
|
personCache.put(cacheKey, allRefs);
|
||||||
@@ -569,6 +569,11 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setPersonProperties(String userName, Map<QName, Serializable> properties)
|
public void setPersonProperties(String userName, Map<QName, Serializable> properties)
|
||||||
|
{
|
||||||
|
setPersonProperties(userName, properties, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPersonProperties(String userName, Map<QName, Serializable> properties, boolean autoCreate)
|
||||||
{
|
{
|
||||||
NodeRef personNode = getPersonOrNull(userName);
|
NodeRef personNode = getPersonOrNull(userName);
|
||||||
if (personNode == null)
|
if (personNode == null)
|
||||||
@@ -584,7 +589,10 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
makeHomeFolderIfRequired(personNode);
|
if (autoCreate)
|
||||||
|
{
|
||||||
|
makeHomeFolderIfRequired(personNode);
|
||||||
|
}
|
||||||
String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(personNode, ContentModel.PROP_USERNAME));
|
String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(personNode, ContentModel.PROP_USERNAME));
|
||||||
properties.put(ContentModel.PROP_USERNAME, realUserName);
|
properties.put(ContentModel.PROP_USERNAME, realUserName);
|
||||||
}
|
}
|
||||||
@@ -603,7 +611,6 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
|
|||||||
{
|
{
|
||||||
HashMap<QName, Serializable> properties = getDefaultProperties(userName);
|
HashMap<QName, Serializable> properties = getDefaultProperties(userName);
|
||||||
NodeRef person = createPerson(properties);
|
NodeRef person = createPerson(properties);
|
||||||
makeHomeFolderIfRequired(person);
|
|
||||||
return person;
|
return person;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,7 +626,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
|
|||||||
{
|
{
|
||||||
public Object execute() throws Throwable
|
public Object execute() throws Throwable
|
||||||
{
|
{
|
||||||
homeFolderManager.onCreateNode(ref);
|
homeFolderManager.makeHomeFolder(ref);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}, transactionService.isReadOnly(), false);
|
}, transactionService.isReadOnly(), false);
|
||||||
@@ -688,7 +695,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
|
|||||||
{
|
{
|
||||||
NodeRef rootNodeRef = nodeService.getRootNode(tenantService.getName(storeRef));
|
NodeRef rootNodeRef = nodeService.getRootNode(tenantService.getName(storeRef));
|
||||||
List<ChildAssociationRef> children = nodeService.getChildAssocs(rootNodeRef, RegexQNamePattern.MATCH_ALL,
|
List<ChildAssociationRef> children = nodeService.getChildAssocs(rootNodeRef, RegexQNamePattern.MATCH_ALL,
|
||||||
QName.createQName(SYSTEM_FOLDER_SHORT_QNAME, namespacePrefixResolver));
|
QName.createQName(SYSTEM_FOLDER_SHORT_QNAME, namespacePrefixResolver), false);
|
||||||
|
|
||||||
if (children.size() == 0)
|
if (children.size() == 0)
|
||||||
{
|
{
|
||||||
@@ -699,7 +706,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
|
|||||||
NodeRef systemNodeRef = children.get(0).getChildRef();
|
NodeRef systemNodeRef = children.get(0).getChildRef();
|
||||||
|
|
||||||
children = nodeService.getChildAssocs(systemNodeRef, RegexQNamePattern.MATCH_ALL, QName.createQName(
|
children = nodeService.getChildAssocs(systemNodeRef, RegexQNamePattern.MATCH_ALL, QName.createQName(
|
||||||
PEOPLE_FOLDER_SHORT_QNAME, namespacePrefixResolver));
|
PEOPLE_FOLDER_SHORT_QNAME, namespacePrefixResolver), false);
|
||||||
|
|
||||||
if (children.size() == 0)
|
if (children.size() == 0)
|
||||||
{
|
{
|
||||||
@@ -763,7 +770,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per
|
|||||||
public Set<NodeRef> getAllPeople()
|
public Set<NodeRef> getAllPeople()
|
||||||
{
|
{
|
||||||
List<ChildAssociationRef> childRefs = nodeService.getChildAssocs(getPeopleContainer(),
|
List<ChildAssociationRef> childRefs = nodeService.getChildAssocs(getPeopleContainer(),
|
||||||
ContentModel.ASSOC_CHILDREN, RegexQNamePattern.MATCH_ALL);
|
ContentModel.ASSOC_CHILDREN, RegexQNamePattern.MATCH_ALL, false);
|
||||||
Set<NodeRef> refs = new HashSet<NodeRef>(childRefs.size()*2);
|
Set<NodeRef> refs = new HashSet<NodeRef>(childRefs.size()*2);
|
||||||
for (ChildAssociationRef childRef : childRefs)
|
for (ChildAssociationRef childRef : childRefs)
|
||||||
{
|
{
|
||||||
|
@@ -41,6 +41,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
|
import org.alfresco.service.cmr.rule.RuleService;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
@@ -65,6 +66,9 @@ public class BatchProcessor<T> implements BatchMonitor
|
|||||||
/** The retrying transaction helper. */
|
/** The retrying transaction helper. */
|
||||||
private RetryingTransactionHelper retryingTransactionHelper;
|
private RetryingTransactionHelper retryingTransactionHelper;
|
||||||
|
|
||||||
|
/** The rule service. */
|
||||||
|
private RuleService ruleService;
|
||||||
|
|
||||||
/** The collection. */
|
/** The collection. */
|
||||||
private Collection<T> collection;
|
private Collection<T> collection;
|
||||||
|
|
||||||
@@ -106,6 +110,8 @@ public class BatchProcessor<T> implements BatchMonitor
|
|||||||
*
|
*
|
||||||
* @param retryingTransactionHelper
|
* @param retryingTransactionHelper
|
||||||
* the retrying transaction helper
|
* the retrying transaction helper
|
||||||
|
* @param ruleService
|
||||||
|
* the rule service
|
||||||
* @param collection
|
* @param collection
|
||||||
* the collection
|
* the collection
|
||||||
* @param processName
|
* @param processName
|
||||||
@@ -119,11 +125,12 @@ public class BatchProcessor<T> implements BatchMonitor
|
|||||||
* @param batchSize
|
* @param batchSize
|
||||||
* the number of entries we process at a time in a transaction
|
* the number of entries we process at a time in a transaction
|
||||||
*/
|
*/
|
||||||
public BatchProcessor(RetryingTransactionHelper retryingTransactionHelper,
|
public BatchProcessor(RetryingTransactionHelper retryingTransactionHelper, RuleService ruleService,
|
||||||
ApplicationEventPublisher applicationEventPublisher, Collection<T> collection, String processName,
|
ApplicationEventPublisher applicationEventPublisher, Collection<T> collection, String processName,
|
||||||
int loggingInterval, int workerThreads, int batchSize)
|
int loggingInterval, int workerThreads, int batchSize)
|
||||||
{
|
{
|
||||||
this.retryingTransactionHelper = retryingTransactionHelper;
|
this.retryingTransactionHelper = retryingTransactionHelper;
|
||||||
|
this.ruleService = ruleService;
|
||||||
this.collection = collection;
|
this.collection = collection;
|
||||||
this.processName = processName;
|
this.processName = processName;
|
||||||
this.loggingInterval = loggingInterval;
|
this.loggingInterval = loggingInterval;
|
||||||
@@ -272,7 +279,7 @@ public class BatchProcessor<T> implements BatchMonitor
|
|||||||
// Create a thread pool executor with the specified number of threads and a finite blocking queue of jobs
|
// Create a thread pool executor with the specified number of threads and a finite blocking queue of jobs
|
||||||
ExecutorService executorService = splitTxns && this.workerThreads > 1 ? new ThreadPoolExecutor(
|
ExecutorService executorService = splitTxns && this.workerThreads > 1 ? new ThreadPoolExecutor(
|
||||||
this.workerThreads, this.workerThreads, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(
|
this.workerThreads, this.workerThreads, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(
|
||||||
this.workerThreads * 10)
|
this.workerThreads * batchSize * 10)
|
||||||
{
|
{
|
||||||
// Add blocking behaviour to work queue
|
// Add blocking behaviour to work queue
|
||||||
@Override
|
@Override
|
||||||
@@ -378,10 +385,10 @@ public class BatchProcessor<T> implements BatchMonitor
|
|||||||
NumberFormat.getPercentInstance().format(
|
NumberFormat.getPercentInstance().format(
|
||||||
totalResults == 0 ? 1.0F : (float) processed / totalResults)).append(" complete");
|
totalResults == 0 ? 1.0F : (float) processed / totalResults)).append(" complete");
|
||||||
}
|
}
|
||||||
long duration = System.currentTimeMillis() - startTime.getTime();
|
long duration = System.currentTimeMillis() - this.startTime.getTime();
|
||||||
if (duration > 0)
|
if (duration > 0)
|
||||||
{
|
{
|
||||||
message.append(". Rate: ").append(processed * 1000 / duration).append(" per second");
|
message.append(". Rate: ").append(processed * 1000L / duration).append(" per second");
|
||||||
}
|
}
|
||||||
message.append(". " + this.totalErrors + " failures detected.");
|
message.append(". " + this.totalErrors + " failures detected.");
|
||||||
BatchProcessor.logger.info(message);
|
BatchProcessor.logger.info(message);
|
||||||
@@ -454,13 +461,13 @@ public class BatchProcessor<T> implements BatchMonitor
|
|||||||
|
|
||||||
/** The current entry being processed in the transaction */
|
/** The current entry being processed in the transaction */
|
||||||
private String txnEntryId;
|
private String txnEntryId;
|
||||||
|
|
||||||
/** The last error. */
|
/** The last error. */
|
||||||
private Throwable txnLastError;
|
private Throwable txnLastError;
|
||||||
|
|
||||||
/** The last error entry id. */
|
/** The last error entry id. */
|
||||||
private String txnLastErrorEntryId;
|
private String txnLastErrorEntryId;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback#execute ()
|
* @see org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback#execute ()
|
||||||
@@ -473,7 +480,7 @@ public class BatchProcessor<T> implements BatchMonitor
|
|||||||
this.txnEntryId = this.worker.getIdentifier(entry);
|
this.txnEntryId = this.worker.getIdentifier(entry);
|
||||||
synchronized (BatchProcessor.this)
|
synchronized (BatchProcessor.this)
|
||||||
{
|
{
|
||||||
BatchProcessor.this.currentEntryId = txnEntryId;
|
BatchProcessor.this.currentEntryId = this.txnEntryId;
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -486,11 +493,11 @@ public class BatchProcessor<T> implements BatchMonitor
|
|||||||
{
|
{
|
||||||
if (BatchProcessor.logger.isWarnEnabled())
|
if (BatchProcessor.logger.isWarnEnabled())
|
||||||
{
|
{
|
||||||
BatchProcessor.logger.warn(getProcessName() + ": Failed to process entry \"" + txnEntryId
|
BatchProcessor.logger.warn(getProcessName() + ": Failed to process entry \""
|
||||||
+ "\".", t);
|
+ this.txnEntryId + "\".", t);
|
||||||
}
|
}
|
||||||
this.txnLastError = t;
|
this.txnLastError = t;
|
||||||
this.txnLastErrorEntryId = txnEntryId;
|
this.txnLastErrorEntryId = this.txnEntryId;
|
||||||
this.txnErrors++;
|
this.txnErrors++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -508,6 +515,8 @@ public class BatchProcessor<T> implements BatchMonitor
|
|||||||
*/
|
*/
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
|
// Disable rules for this thread
|
||||||
|
BatchProcessor.this.ruleService.disableRules();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
BatchProcessor.this.retryingTransactionHelper.doInTransaction(this, false, this.splitTxns);
|
BatchProcessor.this.retryingTransactionHelper.doInTransaction(this, false, this.splitTxns);
|
||||||
@@ -540,6 +549,12 @@ public class BatchProcessor<T> implements BatchMonitor
|
|||||||
throw new AlfrescoRuntimeException("Transactional error during " + getProcessName(), t);
|
throw new AlfrescoRuntimeException("Transactional error during " + getProcessName(), t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Re-enable rules
|
||||||
|
BatchProcessor.this.ruleService.enableRules();
|
||||||
|
}
|
||||||
|
|
||||||
commitProgress();
|
commitProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -606,6 +621,7 @@ public class BatchProcessor<T> implements BatchMonitor
|
|||||||
BatchProcessor.this.lastError = this.txnLastError;
|
BatchProcessor.this.lastError = this.txnLastError;
|
||||||
BatchProcessor.this.lastErrorEntryId = this.txnLastErrorEntryId;
|
BatchProcessor.this.lastErrorEntryId = this.txnLastErrorEntryId;
|
||||||
}
|
}
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -53,6 +53,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
|||||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
import org.alfresco.service.cmr.attributes.AttributeService;
|
import org.alfresco.service.cmr.attributes.AttributeService;
|
||||||
|
import org.alfresco.service.cmr.rule.RuleService;
|
||||||
import org.alfresco.service.cmr.security.AuthorityService;
|
import org.alfresco.service.cmr.security.AuthorityService;
|
||||||
import org.alfresco.service.cmr.security.AuthorityType;
|
import org.alfresco.service.cmr.security.AuthorityType;
|
||||||
import org.alfresco.service.cmr.security.PersonService;
|
import org.alfresco.service.cmr.security.PersonService;
|
||||||
@@ -134,6 +135,9 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
/** The retrying transaction helper. */
|
/** The retrying transaction helper. */
|
||||||
private RetryingTransactionHelper retryingTransactionHelper;
|
private RetryingTransactionHelper retryingTransactionHelper;
|
||||||
|
|
||||||
|
/** The rule service. */
|
||||||
|
private RuleService ruleService;
|
||||||
|
|
||||||
/** The job lock service. */
|
/** The job lock service. */
|
||||||
private JobLockService jobLockService;
|
private JobLockService jobLockService;
|
||||||
|
|
||||||
@@ -221,6 +225,17 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
this.retryingTransactionHelper = retryingTransactionHelper;
|
this.retryingTransactionHelper = retryingTransactionHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the rule service.
|
||||||
|
*
|
||||||
|
* @param ruleService
|
||||||
|
* the new rule service
|
||||||
|
*/
|
||||||
|
public void setRuleService(RuleService ruleService)
|
||||||
|
{
|
||||||
|
this.ruleService = ruleService;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the job lock service.
|
* Sets the job lock service.
|
||||||
*
|
*
|
||||||
@@ -304,6 +319,8 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
*/
|
*/
|
||||||
public void synchronize(boolean force, boolean splitTxns)
|
public void synchronize(boolean force, boolean splitTxns)
|
||||||
{
|
{
|
||||||
|
String lockToken = null;
|
||||||
|
|
||||||
// Let's ensure all exceptions get logged
|
// Let's ensure all exceptions get logged
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -314,8 +331,16 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
{
|
{
|
||||||
// If this is an automated sync on startup or scheduled sync, don't even wait around for the lock.
|
// If this is an automated sync on startup or scheduled sync, don't even wait around for the lock.
|
||||||
// Assume the sync will be completed on another node.
|
// Assume the sync will be completed on another node.
|
||||||
this.jobLockService.getTransactionalLock(ChainingUserRegistrySynchronizer.LOCK_QNAME,
|
lockToken = this.retryingTransactionHelper.doInTransaction(
|
||||||
ChainingUserRegistrySynchronizer.LOCK_TTL, 0, 1);
|
new RetryingTransactionCallback<String>()
|
||||||
|
{
|
||||||
|
public String execute() throws Throwable
|
||||||
|
{
|
||||||
|
return ChainingUserRegistrySynchronizer.this.jobLockService.getLock(
|
||||||
|
ChainingUserRegistrySynchronizer.LOCK_QNAME,
|
||||||
|
ChainingUserRegistrySynchronizer.LOCK_TTL, 0, 1);
|
||||||
|
}
|
||||||
|
}, false, splitTxns);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -382,6 +407,23 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
ChainingUserRegistrySynchronizer.logger.error("Synchronization aborted due to error", e);
|
ChainingUserRegistrySynchronizer.logger.error("Synchronization aborted due to error", e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
// Release the lock if necessary
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (lockToken != null)
|
||||||
|
{
|
||||||
|
final String token = lockToken;
|
||||||
|
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||||
|
{
|
||||||
|
public Object execute() throws Throwable
|
||||||
|
{
|
||||||
|
ChainingUserRegistrySynchronizer.this.jobLockService.releaseLock(token,
|
||||||
|
ChainingUserRegistrySynchronizer.LOCK_QNAME);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, false, splitTxns);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -458,7 +500,7 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
final Set<String> zoneSet = getZones(zoneId);
|
final Set<String> zoneSet = getZones(zoneId);
|
||||||
|
|
||||||
long lastModifiedMillis = getMostRecentUpdateTime(
|
long lastModifiedMillis = getMostRecentUpdateTime(
|
||||||
ChainingUserRegistrySynchronizer.GROUP_LAST_MODIFIED_ATTRIBUTE, zoneId);
|
ChainingUserRegistrySynchronizer.GROUP_LAST_MODIFIED_ATTRIBUTE, zoneId, splitTxns);
|
||||||
Date lastModified = lastModifiedMillis == -1 ? null : new Date(lastModifiedMillis);
|
Date lastModified = lastModifiedMillis == -1 ? null : new Date(lastModifiedMillis);
|
||||||
|
|
||||||
if (ChainingUserRegistrySynchronizer.logger.isInfoEnabled())
|
if (ChainingUserRegistrySynchronizer.logger.isInfoEnabled())
|
||||||
@@ -474,33 +516,22 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current set of known authorities
|
|
||||||
Set<String> allZoneAuthorities = this.retryingTransactionHelper.doInTransaction(
|
|
||||||
new RetryingTransactionCallback<Set<String>>()
|
|
||||||
{
|
|
||||||
public Set<String> execute() throws Throwable
|
|
||||||
{
|
|
||||||
return ChainingUserRegistrySynchronizer.this.authorityService.getAllAuthoritiesInZone(zoneId,
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
}, false, splitTxns);
|
|
||||||
|
|
||||||
// First, analyze the group structure. Create maps of authorities to their parents for associations to create
|
// First, analyze the group structure. Create maps of authorities to their parents for associations to create
|
||||||
// and delete. Also deal with 'overlaps' with other zones in the authentication chain.
|
// and delete. Also deal with 'overlaps' with other zones in the authentication chain.
|
||||||
final BatchProcessor<NodeDescription> groupProcessor = new BatchProcessor<NodeDescription>(
|
final BatchProcessor<NodeDescription> groupProcessor = new BatchProcessor<NodeDescription>(
|
||||||
this.retryingTransactionHelper, this.applicationEventPublisher, userRegistry.getGroups(lastModified),
|
this.retryingTransactionHelper, this.ruleService, this.applicationEventPublisher, userRegistry
|
||||||
zone + " Group Analysis", this.loggingInterval, this.workerThreads, 20);
|
.getGroups(lastModified), zone + " Group Analysis", this.loggingInterval, this.workerThreads,
|
||||||
|
20);
|
||||||
class Analyzer implements Worker<NodeDescription>
|
class Analyzer implements Worker<NodeDescription>
|
||||||
{
|
{
|
||||||
private final Set<String> allZoneAuthorities;
|
private final Set<String> allZoneAuthorities = new TreeSet<String>();
|
||||||
private final Set<String> groupsToCreate = new TreeSet<String>();
|
private final Set<String> groupsToCreate = new TreeSet<String>();
|
||||||
private final Map<String, Set<String>> groupAssocsToCreate = new TreeMap<String, Set<String>>();
|
private final Map<String, Set<String>> groupAssocsToCreate = new TreeMap<String, Set<String>>();
|
||||||
private final Map<String, Set<String>> groupAssocsToDelete = new TreeMap<String, Set<String>>();
|
private final Map<String, Set<String>> groupAssocsToDelete = new TreeMap<String, Set<String>>();
|
||||||
private long latestTime;
|
private long latestTime;
|
||||||
|
|
||||||
public Analyzer(final Set<String> allZoneAuthorities, final long latestTime)
|
public Analyzer(final long latestTime)
|
||||||
{
|
{
|
||||||
this.allZoneAuthorities = allZoneAuthorities;
|
|
||||||
this.latestTime = latestTime;
|
this.latestTime = latestTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,6 +540,11 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
return this.latestTime;
|
return this.latestTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getAllZoneAuthorities()
|
||||||
|
{
|
||||||
|
return this.allZoneAuthorities;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<String> getGroupsToCreate()
|
public Set<String> getGroupsToCreate()
|
||||||
{
|
{
|
||||||
return this.groupsToCreate;
|
return this.groupsToCreate;
|
||||||
@@ -665,105 +701,129 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Analyzer groupAnalyzer = new Analyzer(allZoneAuthorities, lastModifiedMillis);
|
Analyzer groupAnalyzer = new Analyzer(lastModifiedMillis);
|
||||||
int groupProcessedCount = groupProcessor.process(groupAnalyzer, splitTxns);
|
int groupProcessedCount = groupProcessor.process(groupAnalyzer, splitTxns);
|
||||||
final Map<String, Set<String>> groupAssocsToCreate = groupAnalyzer.getGroupAssocsToCreate();
|
final Map<String, Set<String>> groupAssocsToCreate = groupAnalyzer.getGroupAssocsToCreate();
|
||||||
final Map<String, Set<String>> groupAssocsToDelete = groupAnalyzer.getGroupAssocsToDelete();
|
final Map<String, Set<String>> groupAssocsToDelete = groupAnalyzer.getGroupAssocsToDelete();
|
||||||
|
|
||||||
// Prune our set of authorities according to deletions
|
|
||||||
Set<String> deletionCandidates = null;
|
Set<String> deletionCandidates = null;
|
||||||
if (force)
|
|
||||||
|
// If we got back some groups, we have to cross reference them with the set of known authorities
|
||||||
|
if (force || !groupAssocsToCreate.isEmpty())
|
||||||
{
|
{
|
||||||
deletionCandidates = new TreeSet<String>(allZoneAuthorities);
|
// Get current set of known authorities
|
||||||
userRegistry.processDeletions(deletionCandidates);
|
Set<String> allZoneAuthorities = this.retryingTransactionHelper.doInTransaction(
|
||||||
allZoneAuthorities.removeAll(deletionCandidates);
|
new RetryingTransactionCallback<Set<String>>()
|
||||||
groupAssocsToCreate.keySet().removeAll(deletionCandidates);
|
|
||||||
groupAssocsToDelete.keySet().removeAll(deletionCandidates);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort the group associations in depth-first order (root groups first)
|
|
||||||
Map<String, Set<String>> sortedGroupAssociations = new LinkedHashMap<String, Set<String>>(groupAssocsToCreate
|
|
||||||
.size() * 2);
|
|
||||||
List<String> authorityPath = new ArrayList<String>(5);
|
|
||||||
for (String authority : groupAssocsToCreate.keySet())
|
|
||||||
{
|
|
||||||
if (allZoneAuthorities.contains(authority))
|
|
||||||
{
|
|
||||||
authorityPath.add(authority);
|
|
||||||
visitGroupAssociations(authorityPath, allZoneAuthorities, groupAssocsToCreate, sortedGroupAssociations);
|
|
||||||
authorityPath.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the groups and their parent associations in depth-first order
|
|
||||||
final Set<String> groupsToCreate = groupAnalyzer.getGroupsToCreate();
|
|
||||||
BatchProcessor<Map.Entry<String, Set<String>>> groupCreator = new BatchProcessor<Map.Entry<String, Set<String>>>(
|
|
||||||
this.retryingTransactionHelper, this.applicationEventPublisher, sortedGroupAssociations.entrySet(),
|
|
||||||
zone + " Group Creation and Association", this.loggingInterval, 1, 20);
|
|
||||||
groupCreator.process(new Worker<Map.Entry<String, Set<String>>>()
|
|
||||||
{
|
|
||||||
|
|
||||||
public String getIdentifier(Map.Entry<String, Set<String>> entry)
|
|
||||||
{
|
|
||||||
return entry.getKey() + " " + entry.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void process(Map.Entry<String, Set<String>> entry) throws Throwable
|
|
||||||
{
|
|
||||||
Set<String> parents = entry.getValue();
|
|
||||||
String child = entry.getKey();
|
|
||||||
|
|
||||||
if (groupsToCreate.contains(child))
|
|
||||||
{
|
|
||||||
String groupShortName = ChainingUserRegistrySynchronizer.this.authorityService.getShortName(child);
|
|
||||||
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled())
|
|
||||||
{
|
{
|
||||||
ChainingUserRegistrySynchronizer.logger.debug("Creating group '" + groupShortName + "'");
|
public Set<String> execute() throws Throwable
|
||||||
}
|
|
||||||
// create the group
|
|
||||||
ChainingUserRegistrySynchronizer.this.authorityService.createAuthority(AuthorityType
|
|
||||||
.getAuthorityType(child), groupShortName, groupShortName, zoneSet);
|
|
||||||
}
|
|
||||||
if (!parents.isEmpty())
|
|
||||||
{
|
|
||||||
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled())
|
|
||||||
{
|
|
||||||
for (String groupName : parents)
|
|
||||||
{
|
{
|
||||||
ChainingUserRegistrySynchronizer.logger.debug("Adding '"
|
return ChainingUserRegistrySynchronizer.this.authorityService.getAllAuthoritiesInZone(
|
||||||
+ ChainingUserRegistrySynchronizer.this.authorityService.getShortName(child)
|
zoneId, null);
|
||||||
+ "' to group '"
|
|
||||||
+ ChainingUserRegistrySynchronizer.this.authorityService.getShortName(groupName)
|
|
||||||
+ "'");
|
|
||||||
}
|
}
|
||||||
}
|
}, true, splitTxns);
|
||||||
ChainingUserRegistrySynchronizer.this.authorityService.addAuthority(parents, child);
|
// Add in those that will be created or moved
|
||||||
}
|
allZoneAuthorities.addAll(groupAnalyzer.getAllZoneAuthorities());
|
||||||
Set<String> parentsToDelete = groupAssocsToDelete.get(child);
|
|
||||||
if (parentsToDelete != null && !parentsToDelete.isEmpty())
|
// Prune our set of authorities according to deletions
|
||||||
|
if (force)
|
||||||
|
{
|
||||||
|
deletionCandidates = new TreeSet<String>(allZoneAuthorities);
|
||||||
|
userRegistry.processDeletions(deletionCandidates);
|
||||||
|
allZoneAuthorities.removeAll(deletionCandidates);
|
||||||
|
groupAssocsToCreate.keySet().removeAll(deletionCandidates);
|
||||||
|
groupAssocsToDelete.keySet().removeAll(deletionCandidates);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!groupAssocsToCreate.isEmpty())
|
||||||
|
{
|
||||||
|
// Sort the group associations in depth-first order (root groups first)
|
||||||
|
Map<String, Set<String>> sortedGroupAssociations = new LinkedHashMap<String, Set<String>>(
|
||||||
|
groupAssocsToCreate.size() * 2);
|
||||||
|
List<String> authorityPath = new ArrayList<String>(5);
|
||||||
|
for (String authority : groupAssocsToCreate.keySet())
|
||||||
{
|
{
|
||||||
for (String parent : parentsToDelete)
|
if (allZoneAuthorities.contains(authority))
|
||||||
{
|
{
|
||||||
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled())
|
authorityPath.add(authority);
|
||||||
|
visitGroupAssociations(authorityPath, allZoneAuthorities, groupAssocsToCreate,
|
||||||
|
sortedGroupAssociations);
|
||||||
|
authorityPath.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the groups and their parent associations in depth-first order
|
||||||
|
final Set<String> groupsToCreate = groupAnalyzer.getGroupsToCreate();
|
||||||
|
BatchProcessor<Map.Entry<String, Set<String>>> groupCreator = new BatchProcessor<Map.Entry<String, Set<String>>>(
|
||||||
|
this.retryingTransactionHelper, this.ruleService, this.applicationEventPublisher,
|
||||||
|
sortedGroupAssociations.entrySet(), zone + " Group Creation and Association",
|
||||||
|
this.loggingInterval, this.workerThreads, 20);
|
||||||
|
groupCreator.process(new Worker<Map.Entry<String, Set<String>>>()
|
||||||
|
{
|
||||||
|
|
||||||
|
public String getIdentifier(Map.Entry<String, Set<String>> entry)
|
||||||
|
{
|
||||||
|
return entry.getKey() + " " + entry.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void process(Map.Entry<String, Set<String>> entry) throws Throwable
|
||||||
|
{
|
||||||
|
Set<String> parents = entry.getValue();
|
||||||
|
String child = entry.getKey();
|
||||||
|
|
||||||
|
if (groupsToCreate.contains(child))
|
||||||
{
|
{
|
||||||
ChainingUserRegistrySynchronizer.logger
|
String groupShortName = ChainingUserRegistrySynchronizer.this.authorityService
|
||||||
.debug("Removing '"
|
.getShortName(child);
|
||||||
|
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
ChainingUserRegistrySynchronizer.logger
|
||||||
|
.debug("Creating group '" + groupShortName + "'");
|
||||||
|
}
|
||||||
|
// create the group
|
||||||
|
ChainingUserRegistrySynchronizer.this.authorityService.createAuthority(AuthorityType
|
||||||
|
.getAuthorityType(child), groupShortName, groupShortName, zoneSet);
|
||||||
|
}
|
||||||
|
if (!parents.isEmpty())
|
||||||
|
{
|
||||||
|
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
for (String groupName : parents)
|
||||||
|
{
|
||||||
|
ChainingUserRegistrySynchronizer.logger.debug("Adding '"
|
||||||
|
+ ChainingUserRegistrySynchronizer.this.authorityService
|
||||||
|
.getShortName(child)
|
||||||
|
+ "' to group '"
|
||||||
|
+ ChainingUserRegistrySynchronizer.this.authorityService
|
||||||
|
.getShortName(groupName) + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ChainingUserRegistrySynchronizer.this.authorityService.addAuthority(parents, child);
|
||||||
|
}
|
||||||
|
Set<String> parentsToDelete = groupAssocsToDelete.get(child);
|
||||||
|
if (parentsToDelete != null && !parentsToDelete.isEmpty())
|
||||||
|
{
|
||||||
|
for (String parent : parentsToDelete)
|
||||||
|
{
|
||||||
|
if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
ChainingUserRegistrySynchronizer.logger.debug("Removing '"
|
||||||
+ ChainingUserRegistrySynchronizer.this.authorityService
|
+ ChainingUserRegistrySynchronizer.this.authorityService
|
||||||
.getShortName(child)
|
.getShortName(child)
|
||||||
+ "' from group '"
|
+ "' from group '"
|
||||||
+ ChainingUserRegistrySynchronizer.this.authorityService
|
+ ChainingUserRegistrySynchronizer.this.authorityService
|
||||||
.getShortName(parent) + "'");
|
.getShortName(parent) + "'");
|
||||||
|
}
|
||||||
|
ChainingUserRegistrySynchronizer.this.authorityService.removeAuthority(parent, child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ChainingUserRegistrySynchronizer.this.authorityService.removeAuthority(parent, child);
|
|
||||||
}
|
}
|
||||||
}
|
}, splitTxns);
|
||||||
}
|
}
|
||||||
}, splitTxns);
|
}
|
||||||
|
|
||||||
// Process persons and their parent associations
|
// Process persons and their parent associations
|
||||||
|
|
||||||
lastModifiedMillis = getMostRecentUpdateTime(ChainingUserRegistrySynchronizer.PERSON_LAST_MODIFIED_ATTRIBUTE,
|
lastModifiedMillis = getMostRecentUpdateTime(ChainingUserRegistrySynchronizer.PERSON_LAST_MODIFIED_ATTRIBUTE,
|
||||||
zoneId);
|
zoneId, splitTxns);
|
||||||
lastModified = lastModifiedMillis == -1 ? null : new Date(lastModifiedMillis);
|
lastModified = lastModifiedMillis == -1 ? null : new Date(lastModifiedMillis);
|
||||||
if (ChainingUserRegistrySynchronizer.logger.isInfoEnabled())
|
if (ChainingUserRegistrySynchronizer.logger.isInfoEnabled())
|
||||||
{
|
{
|
||||||
@@ -778,8 +838,9 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
final BatchProcessor<NodeDescription> personProcessor = new BatchProcessor<NodeDescription>(
|
final BatchProcessor<NodeDescription> personProcessor = new BatchProcessor<NodeDescription>(
|
||||||
this.retryingTransactionHelper, this.applicationEventPublisher, userRegistry.getPersons(lastModified),
|
this.retryingTransactionHelper, this.ruleService, this.applicationEventPublisher, userRegistry
|
||||||
zone + " User Creation and Association", this.loggingInterval, this.workerThreads, 10);
|
.getPersons(lastModified), zone + " User Creation and Association", this.loggingInterval,
|
||||||
|
this.workerThreads, 10);
|
||||||
class PersonWorker implements Worker<NodeDescription>
|
class PersonWorker implements Worker<NodeDescription>
|
||||||
{
|
{
|
||||||
private long latestTime;
|
private long latestTime;
|
||||||
@@ -822,7 +883,7 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
ChainingUserRegistrySynchronizer.logger.debug("Updating user '" + personName + "'");
|
ChainingUserRegistrySynchronizer.logger.debug("Updating user '" + personName + "'");
|
||||||
}
|
}
|
||||||
ChainingUserRegistrySynchronizer.this.personService.setPersonProperties(personName,
|
ChainingUserRegistrySynchronizer.this.personService.setPersonProperties(personName,
|
||||||
personProperties);
|
personProperties, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -936,8 +997,8 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
if (force)
|
if (force)
|
||||||
{
|
{
|
||||||
BatchProcessor<String> authorityDeletionProcessor = new BatchProcessor<String>(
|
BatchProcessor<String> authorityDeletionProcessor = new BatchProcessor<String>(
|
||||||
this.retryingTransactionHelper, this.applicationEventPublisher, deletionCandidates, zone
|
this.retryingTransactionHelper, this.ruleService, this.applicationEventPublisher,
|
||||||
+ " Authority Deletion", this.loggingInterval, this.workerThreads, 10);
|
deletionCandidates, zone + " Authority Deletion", this.loggingInterval, this.workerThreads, 10);
|
||||||
class AuthorityDeleter implements Worker<String>
|
class AuthorityDeleter implements Worker<String>
|
||||||
{
|
{
|
||||||
private int personProcessedCount;
|
private int personProcessedCount;
|
||||||
@@ -1062,11 +1123,18 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
* the zone id
|
* the zone id
|
||||||
* @return the most recent update time in milliseconds
|
* @return the most recent update time in milliseconds
|
||||||
*/
|
*/
|
||||||
private long getMostRecentUpdateTime(String label, String zoneId)
|
private long getMostRecentUpdateTime(final String label, final String zoneId, boolean splitTxns)
|
||||||
{
|
{
|
||||||
Attribute attribute = this.attributeService.getAttribute(ChainingUserRegistrySynchronizer.ROOT_ATTRIBUTE_PATH
|
return this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Long>()
|
||||||
+ '/' + label + '/' + zoneId);
|
{
|
||||||
return attribute == null ? -1 : attribute.getLongValue();
|
|
||||||
|
public Long execute() throws Throwable
|
||||||
|
{
|
||||||
|
Attribute attribute = ChainingUserRegistrySynchronizer.this.attributeService
|
||||||
|
.getAttribute(ChainingUserRegistrySynchronizer.ROOT_ATTRIBUTE_PATH + '/' + label + '/' + zoneId);
|
||||||
|
return attribute == null ? -1 : attribute.getLongValue();
|
||||||
|
}
|
||||||
|
}, true, splitTxns);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1144,24 +1212,16 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl
|
|||||||
{
|
{
|
||||||
public Object doWork() throws Exception
|
public Object doWork() throws Exception
|
||||||
{
|
{
|
||||||
return ChainingUserRegistrySynchronizer.this.retryingTransactionHelper
|
try
|
||||||
.doInTransaction(new RetryingTransactionCallback<Object>()
|
{
|
||||||
{
|
synchronize(false, true);
|
||||||
|
}
|
||||||
public Object execute() throws Throwable
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
try
|
ChainingUserRegistrySynchronizer.logger.warn("Failed initial synchronize with user registries",
|
||||||
{
|
e);
|
||||||
synchronize(false, true);
|
}
|
||||||
}
|
return null;
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
ChainingUserRegistrySynchronizer.logger.warn(
|
|
||||||
"Failed initial synchronize with user registries", e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, AuthenticationUtil.getSystemUserName());
|
}, AuthenticationUtil.getSystemUserName());
|
||||||
}
|
}
|
||||||
|
@@ -171,15 +171,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
|||||||
{
|
{
|
||||||
newGroup("G2", "U1", "U3", "U4"), newGroup("G6", "U3", "U4", "G7"), newGroup("G7", "U5")
|
newGroup("G2", "U1", "U3", "U4"), newGroup("G6", "U3", "U4", "G7"), newGroup("G7", "U5")
|
||||||
}));
|
}));
|
||||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
this.synchronizer.synchronize(true, true);
|
||||||
{
|
|
||||||
|
|
||||||
public Object execute() throws Throwable
|
|
||||||
{
|
|
||||||
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -200,7 +192,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
|||||||
assertExists("Z2", "G7", "U5");
|
assertExists("Z2", "G7", "U5");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
}, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -209,22 +201,14 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
|||||||
* @throws Exception
|
* @throws Exception
|
||||||
* the exception
|
* the exception
|
||||||
*/
|
*/
|
||||||
private void tearDownTestUsersAndGroups() throws Exception
|
public void tearDownTestUsersAndGroups() throws Exception
|
||||||
{
|
{
|
||||||
// Wipe out everything that was in Z1 and Z2
|
// Wipe out everything that was in Z1 and Z2
|
||||||
this.applicationContextManager.setUserRegistries(new MockUserRegistry("Z0", new NodeDescription[] {},
|
this.applicationContextManager.setUserRegistries(new MockUserRegistry("Z0", new NodeDescription[] {},
|
||||||
new NodeDescription[] {}), new MockUserRegistry("Z1", new NodeDescription[] {},
|
new NodeDescription[] {}), new MockUserRegistry("Z1", new NodeDescription[] {},
|
||||||
new NodeDescription[] {}), new MockUserRegistry("Z2", new NodeDescription[] {},
|
new NodeDescription[] {}), new MockUserRegistry("Z2", new NodeDescription[] {},
|
||||||
new NodeDescription[] {}));
|
new NodeDescription[] {}));
|
||||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
this.synchronizer.synchronize(true, true);
|
||||||
{
|
|
||||||
|
|
||||||
public Object execute() throws Throwable
|
|
||||||
{
|
|
||||||
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -245,7 +229,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
|||||||
assertNotExists("G7");
|
assertNotExists("G7");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
}, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -348,15 +332,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
|||||||
{
|
{
|
||||||
newGroup("G2", "U1", "U3", "U4", "U6"), newGroup("G6", "U3", "U4", "G7"), newGroup("G7", "U4", "U5")
|
newGroup("G2", "U1", "U3", "U4", "U6"), newGroup("G6", "U3", "U4", "G7"), newGroup("G7", "U4", "U5")
|
||||||
}));
|
}));
|
||||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
this.synchronizer.synchronize(true, true);
|
||||||
{
|
|
||||||
|
|
||||||
public Object execute() throws Throwable
|
|
||||||
{
|
|
||||||
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -378,7 +354,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
|||||||
assertExists("Z2", "G7");
|
assertExists("Z2", "G7");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
}, false, true);
|
||||||
tearDownTestUsersAndGroups();
|
tearDownTestUsersAndGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,15 +369,7 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
|||||||
List<NodeDescription> persons = new ArrayList<NodeDescription>(new RandomPersonCollection(100));
|
List<NodeDescription> persons = new ArrayList<NodeDescription>(new RandomPersonCollection(100));
|
||||||
List<NodeDescription> groups = new ArrayList<NodeDescription>(new RandomGroupCollection(100, persons));
|
List<NodeDescription> groups = new ArrayList<NodeDescription>(new RandomGroupCollection(100, persons));
|
||||||
this.applicationContextManager.setUserRegistries(new MockUserRegistry("Z0", persons, groups));
|
this.applicationContextManager.setUserRegistries(new MockUserRegistry("Z0", persons, groups));
|
||||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
this.synchronizer.synchronize(true, true);
|
||||||
{
|
|
||||||
|
|
||||||
public Object execute() throws Throwable
|
|
||||||
{
|
|
||||||
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
tearDownTestUsersAndGroups();
|
tearDownTestUsersAndGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,20 +381,20 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public void dontTestAssocs() throws Exception
|
public void dontTestAssocs() throws Exception
|
||||||
{
|
{
|
||||||
this.retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Object>()
|
List<NodeDescription> groups = this.retryingTransactionHelper.doInTransaction(
|
||||||
{
|
new RetryingTransactionCallback<List<NodeDescription>>()
|
||||||
public Object execute() throws Throwable
|
{
|
||||||
{
|
|
||||||
List<NodeDescription> groups = new ArrayList<NodeDescription>(new RandomGroupCollection(1000,
|
public List<NodeDescription> execute() throws Throwable
|
||||||
ChainingUserRegistrySynchronizerTest.this.authorityService.getAllAuthoritiesInZone(
|
{
|
||||||
AuthorityService.ZONE_AUTH_EXT_PREFIX + "Z0", null)));
|
return new ArrayList<NodeDescription>(new RandomGroupCollection(1000,
|
||||||
ChainingUserRegistrySynchronizerTest.this.applicationContextManager
|
ChainingUserRegistrySynchronizerTest.this.authorityService.getAllAuthoritiesInZone(
|
||||||
.setUserRegistries(new MockUserRegistry("Z0", Collections.<NodeDescription> emptyList(), groups));
|
AuthorityService.ZONE_AUTH_EXT_PREFIX + "Z0", null)));
|
||||||
;
|
}
|
||||||
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true);
|
}, true, true);
|
||||||
return null;
|
ChainingUserRegistrySynchronizerTest.this.applicationContextManager.setUserRegistries(new MockUserRegistry(
|
||||||
}
|
"Z0", Collections.<NodeDescription> emptyList(), groups));
|
||||||
});
|
ChainingUserRegistrySynchronizerTest.this.synchronizer.synchronize(true, true);
|
||||||
tearDownTestUsersAndGroups();
|
tearDownTestUsersAndGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,10 +599,9 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
|||||||
{
|
{
|
||||||
return this.zoneId;
|
return this.zoneId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
* @see org.alfresco.repo.security.sync.UserRegistry#processDeletions(java.util.Set)
|
* @see org.alfresco.repo.security.sync.UserRegistry#processDeletions(java.util.Set)
|
||||||
*/
|
*/
|
||||||
public void processDeletions(Set<String> candidateAuthoritiesForDeletion)
|
public void processDeletions(Set<String> candidateAuthoritiesForDeletion)
|
||||||
@@ -649,7 +616,8 @@ public class ChainingUserRegistrySynchronizerTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
* @see org.alfresco.repo.security.sync.UserRegistry#getGroups(java.util.Date)
|
* @see org.alfresco.repo.security.sync.UserRegistry#getGroups(java.util.Date)
|
||||||
*/
|
*/
|
||||||
public Collection<NodeDescription> getGroups(Date modifiedSince)
|
public Collection<NodeDescription> getGroups(Date modifiedSince)
|
||||||
|
@@ -489,6 +489,13 @@ public class NodeServiceImpl implements NodeService, VersionModel
|
|||||||
return getChildAssocs(VersionUtil.convertNodeRef(nodeRef), RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL);
|
return getChildAssocs(VersionUtil.convertNodeRef(nodeRef), RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern,
|
||||||
|
QNamePattern qnamePattern, boolean preload) throws InvalidNodeRefException
|
||||||
|
{
|
||||||
|
return getChildAssocs(nodeRef, typeQNamePattern, qnamePattern);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs conversion from version store properties to <i>real</i> associations
|
* Performs conversion from version store properties to <i>real</i> associations
|
||||||
*/
|
*/
|
||||||
|
@@ -519,6 +519,32 @@ public interface NodeService
|
|||||||
QNamePattern qnamePattern)
|
QNamePattern qnamePattern)
|
||||||
throws InvalidNodeRefException;
|
throws InvalidNodeRefException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all child associations where the pattern of the association qualified
|
||||||
|
* name is a match. Using a {@link org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL wildcard}
|
||||||
|
* for the type and a specific {@link QName qualified name} for the association is
|
||||||
|
* akin to using the XPath browse expression <b>./{url}localname</b> in the context of the
|
||||||
|
* parent node.
|
||||||
|
*
|
||||||
|
* @param nodeRef the parent node - usually a <b>container</b>
|
||||||
|
* @param typeQNamePattern the pattern that the type qualified name of the association must match
|
||||||
|
* @param qnamePattern the pattern that the qnames of the assocs must match
|
||||||
|
* @param preload should the nodes be preloaded into the cache?
|
||||||
|
* @return Returns a list of <code>ChildAssociationRef</code> instances. If the
|
||||||
|
* node is not a <b>container</b> then the result will be empty.
|
||||||
|
* @throws InvalidNodeRefException if the node could not be found
|
||||||
|
*
|
||||||
|
* @see QName
|
||||||
|
* @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL
|
||||||
|
*/
|
||||||
|
@Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "typeQNamePattern", "qnamePattern"})
|
||||||
|
public List<ChildAssociationRef> getChildAssocs(
|
||||||
|
NodeRef nodeRef,
|
||||||
|
QNamePattern typeQNamePattern,
|
||||||
|
QNamePattern qnamePattern,
|
||||||
|
boolean preload)
|
||||||
|
throws InvalidNodeRefException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve immediate children of a given node where the child nodes are in the given inclusive list
|
* Retrieve immediate children of a given node where the child nodes are in the given inclusive list
|
||||||
* and not in the given exclusive list.
|
* and not in the given exclusive list.
|
||||||
|
@@ -137,6 +137,20 @@ public interface PersonService
|
|||||||
@Auditable(parameters = {"userName", "properties"})
|
@Auditable(parameters = {"userName", "properties"})
|
||||||
public void setPersonProperties(String userName, Map<QName, Serializable> properties);
|
public void setPersonProperties(String userName, Map<QName, Serializable> properties);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the properties on a person - some of these may be persisted in different locations.
|
||||||
|
*
|
||||||
|
* @param userName
|
||||||
|
* - the user for which the properties should be set.
|
||||||
|
* @param properties
|
||||||
|
* - the map of properties to set (as the NodeService)
|
||||||
|
* @param autoCreate
|
||||||
|
* should we auto-create the home folder if it doesn't exist? (and configuration allows us to)
|
||||||
|
*/
|
||||||
|
@Auditable(parameters = {"userName", "properties", "autoCreate"})
|
||||||
|
public void setPersonProperties(String userName, Map<QName, Serializable> properties, boolean autoCreate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can this service create, delete and update person information?
|
* Can this service create, delete and update person information?
|
||||||
*
|
*
|
||||||
|
@@ -18,6 +18,9 @@
|
|||||||
<property name="retryingTransactionHelper">
|
<property name="retryingTransactionHelper">
|
||||||
<ref bean="retryingTransactionHelper" />
|
<ref bean="retryingTransactionHelper" />
|
||||||
</property>
|
</property>
|
||||||
|
<property name="ruleService">
|
||||||
|
<ref bean="ruleService" />
|
||||||
|
</property>
|
||||||
<property name="jobLockService">
|
<property name="jobLockService">
|
||||||
<ref bean="jobLockService" />
|
<ref bean="jobLockService" />
|
||||||
</property>
|
</property>
|
||||||
@@ -25,7 +28,7 @@
|
|||||||
<value>userRegistry</value>
|
<value>userRegistry</value>
|
||||||
</property>
|
</property>
|
||||||
<property name="loggingInterval">
|
<property name="loggingInterval">
|
||||||
<value>10</value>
|
<value>100</value>
|
||||||
</property>
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user