From 111296d4dca79778e55db44feb9bc4a4e73a4eb4 Mon Sep 17 00:00:00 2001 From: Britt Park Date: Wed, 18 Oct 2006 02:24:36 +0000 Subject: [PATCH] Heinous merge from HEAD. Seems to basically work. Be on guard however. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@4137 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/action-services-context.xml | 3 + config/alfresco/auditConfig.xml | 381 +- .../authentication-services-context.xml | 92 +- config/alfresco/bootstrap-context.xml | 29 + config/alfresco/bootstrap/system.xml | 4 +- config/alfresco/bootstrap/tutorial.xml | 26 +- config/alfresco/core-services-context.xml | 1345 +++--- config/alfresco/desktop/dumpRequest.js | 38 + .../index-recovery-context.xml.sample | 38 + .../ldap-authentication-context.xml.sample | 463 +++ config/alfresco/file-servers.xml | 10 + config/alfresco/import-export-context.xml | 41 + config/alfresco/index-recovery-context.xml | 79 +- .../alfresco/messages/bpm-messages.properties | 32 +- .../messages/content-service.properties | 8 +- .../mimetype/openoffice-document-formats.xml | 5 +- config/alfresco/model/contentModel.xml | 1416 +++---- .../model/dataTypeAnalyzers.properties | 18 +- config/alfresco/model/dictionaryModel.xml | 20 +- .../alfresco/model/permissionDefinitions.xml | 196 +- config/alfresco/network-protocol-context.xml | 2 +- config/alfresco/node-services-context.xml | 2 +- config/alfresco/policy-context.xml | 6 + config/alfresco/repository.properties | 273 +- config/alfresco/scheduled-jobs-context.xml | 154 +- config/alfresco/version.properties | 2 +- config/alfresco/workflow-context.xml | 50 +- .../workflow/adhoc_processdefinition.xml | 55 + .../workflow/review_processdefinition.xml | 47 + .../workflow/workflow-messages.properties | 54 + config/alfresco/workflow/workflowModel.xml | 65 + .../auth/EnterpriseCifsAuthenticator.java | 24 +- .../server/config/ServerConfiguration.java | 2 +- .../smb/server/repo/ContentDiskDriver.java | 211 +- .../smb/server/repo/DesktopAction.java | 11 +- .../smb/server/repo/DesktopResponse.java | 70 +- .../repo/desk/CheckInOutDesktopAction.java | 40 +- .../repo/desk/JavaScriptDesktopAction.java | 448 ++ .../repo/pseudo/ContentPseudoFileImpl.java | 21 + .../org/alfresco/filesys/util/DataBuffer.java | 4 +- .../jcr/repository/RepositoryImpl.java | 4 +- .../java/org/alfresco/model/ContentModel.java | 30 +- .../action/executer/MailActionExecuter.java | 19 + .../action/executer/ScriptActionExecuter.java | 4 + .../executer/TransformActionExecuter.java | 13 +- .../repo/audit/AuditComponentImpl.java | 25 +- .../alfresco/repo/audit/AuditableAspect.java | 11 +- .../alfresco/repo/audit/MethodAuditModel.java | 8 + .../repo/audit/hibernate/Audit.hbm.xml | 24 +- .../repo/audit/model/AbstractAuditEntry.java | 43 + .../alfresco/repo/audit/model/AuditEntry.java | 19 + .../repo/audit/model/MethodAuditEntry.java | 9 + .../repo/audit/model/ServiceAuditEntry.java | 18 + .../InternalEhCacheManagerFactoryBean.java | 2 +- .../repo/content/AbstractContentStore.java | 2 +- .../alfresco/repo/content/MimetypeMap.java | 1 + .../repo/content/RoutingContentService.java | 1 - .../content/cleanup/ContentStoreCleaner.java | 511 ++- .../AbstractContentTransformerTest.java | 74 +- .../OpenOfficeContentTransformerTest.java | 27 + ...AbstractImageMagickContentTransformer.java | 4 + .../repo/dictionary/DictionaryComponent.java | 2 +- .../org/alfresco/repo/dictionary/M2Model.java | 2 +- .../dictionary/dictionarydaotest_model.xml | 2 +- .../repo/domain/DbAccessControlList.java | 166 +- .../alfresco/repo/domain/PropertyValue.java | 45 +- .../repo/domain/hibernate/ChildAssocImpl.java | 23 - .../hibernate/DbAccessControlListImpl.java | 500 +-- .../domain/hibernate/HibernateNodeTest.java | 918 +++-- .../repo/domain/hibernate/Node.hbm.xml | 62 +- .../repo/domain/hibernate/Transaction.hbm.xml | 77 + .../repo/domain/schema/SchemaBootstrap.java | 1074 ++--- .../org/alfresco/repo/jscript/Actions.java | 2 +- .../java/org/alfresco/repo/jscript/Node.java | 47 +- .../filefolder/FileFolderServiceImpl.java | 6 +- .../filefolder/FileFolderServiceImplTest.java | 4 + .../repo/node/BaseNodeServiceTest.java | 4 + .../repo/node/PerformanceNodeServiceTest.java | 2 + .../node/archive/ArchiveAndRestoreTest.java | 4 + .../repo/node/db/DbNodeServiceImpl.java | 3643 ++++++++-------- .../repo/node/db/DbNodeServiceImplTest.java | 39 +- .../alfresco/repo/node/db/NodeDaoService.java | 25 +- .../HibernateNodeDaoServiceImpl.java | 278 +- .../node/index/AbstractReindexComponent.java | 227 + .../node/index/FtsIndexRecoveryComponent.java | 134 - .../index/FtsIndexRecoveryComponentTest.java | 60 - .../index/FullIndexRecoveryComponent.java | 813 ++-- .../index/FullIndexRecoveryComponentTest.java | 127 +- .../index/MissingContentReindexComponent.java | 882 +--- .../MissingContentReindexComponentTest.java | 172 + .../repo/node/integrity/IntegrityChecker.java | 35 +- .../repo/node/integrity/IntegrityTest.java | 12 + .../repo/ownable/impl/OwnableServiceTest.java | 8 + .../policy/TransactionBehaviourQueue.java | 3 +- .../org/alfresco/repo/search/IndexerSPI.java | 2 +- .../impl/lucene/ClosingIndexSearcher.java | 5 + .../search/impl/lucene/LuceneAnalyser.java | 6 +- .../repo/search/impl/lucene/LuceneBase2.java | 2 +- .../search/impl/lucene/LuceneIndexerImpl.java | 16 +- .../impl/lucene/LuceneIndexerImpl2.java | 16 +- .../search/impl/lucene/LuceneQueryParser.java | 41 +- .../impl/lucene/LuceneSearcherImpl2.java | 42 +- .../repo/search/impl/lucene/LuceneTest2.java | 54 +- .../analysis/AlfrescoStandardAnalyser.java | 63 + .../analysis/AlfrescoStandardFilter.java | 138 + .../lucene/fts/FullTextSearchIndexerImpl.java | 65 +- .../search/impl/lucene/index/IndexInfo.java | 10 +- .../impl/lucene/index/IndexInfoTest.java | 14 +- .../DefaultMutableAuthenticationDao.java | 315 +- .../ldap/LDAPGroupExportSource.java | 1532 +++---- .../LDAPInitialDirContextFactoryImpl.java | 124 +- .../ldap/LDAPPersonExportSource.java | 676 +-- .../ntlm/NTLMAuthenticationComponentImpl.java | 8 + .../dynamic/LockOwnerDynamicAuthority.java | 32 +- .../impl/PermissionServiceImpl.java | 2264 +++++----- .../impl/PermissionServiceTest.java | 3664 +++++++++-------- .../impl/model/PermissionModel.java | 1936 +++++---- .../impl/model/PermissionModelTest.java | 41 +- .../person/AbstractHomeFolderProvider.java | 439 ++ .../person/BootstrapHomeFolderProvider.java | 37 + .../ExistingPathBasedHomeFolderProvider.java | 50 + .../security/person/HomeFolderManager.java | 123 + .../security/person/HomeFolderProvider.java | 34 + .../security/person/HomeSpaceNodeRef.java | 53 + .../security/person/PersonServiceImpl.java | 798 ++-- .../person/UIDBasedHomeFolderProvider.java | 105 + .../service/ServiceDescriptorRegistry.java | 726 ++-- .../transaction/DummyTransactionService.java | 4 + .../TransactionAwareSingleton.java | 143 + .../TransactionAwareSingletonTest.java | 224 + .../workflow/StartWorkflowActionExecuter.java | 40 +- .../StartWorkflowActionExecuterTest.java | 9 +- .../repo/workflow/WorkflowComponent.java | 8 + .../repo/workflow/WorkflowDeployer.java | 46 + .../alfresco/repo/workflow/WorkflowModel.java | 24 +- .../workflow/WorkflowPackageComponent.java | 22 +- .../repo/workflow/WorkflowPackageImpl.java | 90 +- .../repo/workflow/WorkflowServiceImpl.java | 33 + .../workflow/WorkflowServiceImplTest.java | 51 +- .../workflow/jbpm/AlfrescoJavaScript.java | 16 +- .../workflow/jbpm/JBPMDeleteProcessTest.java | 186 + .../repo/workflow/jbpm/JBPMEngine.java | 348 +- .../repo/workflow/jbpm/JBPMEngineTest.java | 28 +- .../jbpm/JBPMTransactionTemplate.java | 225 + .../workflow/jbpm/NodeListConverterTest.java | 2 +- .../workflow/jbpm/ReviewAndApproveTest.java | 13 +- .../workflow/jbpm/WorkflowTaskInstance.java | 26 +- .../repo/workflow/jbpm/test_script.xml | 108 +- .../org/alfresco/service/ServiceRegistry.java | 602 +-- .../service/cmr/repository/CopyService.java | 4 + .../service/cmr/repository/NodeRef.java | 9 + .../service/cmr/repository/NodeService.java | 1128 ++--- .../cmr/workflow/WorkflowInstance.java | 11 +- .../service/cmr/workflow/WorkflowService.java | 30 +- .../test-resources/jbpmresources/ehcache.xml | 48 + .../jbpmresources/hibernate.cfg.xml | 166 + 156 files changed, 18940 insertions(+), 14167 deletions(-) create mode 100644 config/alfresco/desktop/dumpRequest.js create mode 100644 config/alfresco/extension/index-recovery-context.xml.sample create mode 100644 config/alfresco/extension/ldap-authentication-context.xml.sample create mode 100644 config/alfresco/workflow/adhoc_processdefinition.xml create mode 100644 config/alfresco/workflow/review_processdefinition.xml create mode 100644 config/alfresco/workflow/workflow-messages.properties create mode 100644 config/alfresco/workflow/workflowModel.xml create mode 100644 source/java/org/alfresco/filesys/smb/server/repo/desk/JavaScriptDesktopAction.java create mode 100644 source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java delete mode 100644 source/java/org/alfresco/repo/node/index/FtsIndexRecoveryComponent.java delete mode 100644 source/java/org/alfresco/repo/node/index/FtsIndexRecoveryComponentTest.java create mode 100644 source/java/org/alfresco/repo/node/index/MissingContentReindexComponentTest.java create mode 100644 source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardAnalyser.java create mode 100644 source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardFilter.java create mode 100644 source/java/org/alfresco/repo/security/person/AbstractHomeFolderProvider.java create mode 100644 source/java/org/alfresco/repo/security/person/BootstrapHomeFolderProvider.java create mode 100644 source/java/org/alfresco/repo/security/person/ExistingPathBasedHomeFolderProvider.java create mode 100644 source/java/org/alfresco/repo/security/person/HomeFolderManager.java create mode 100644 source/java/org/alfresco/repo/security/person/HomeFolderProvider.java create mode 100644 source/java/org/alfresco/repo/security/person/HomeSpaceNodeRef.java create mode 100644 source/java/org/alfresco/repo/security/person/UIDBasedHomeFolderProvider.java create mode 100644 source/java/org/alfresco/repo/transaction/TransactionAwareSingleton.java create mode 100644 source/java/org/alfresco/repo/transaction/TransactionAwareSingletonTest.java create mode 100644 source/java/org/alfresco/repo/workflow/jbpm/JBPMDeleteProcessTest.java create mode 100644 source/java/org/alfresco/repo/workflow/jbpm/JBPMTransactionTemplate.java create mode 100644 source/test-resources/jbpmresources/ehcache.xml create mode 100644 source/test-resources/jbpmresources/hibernate.cfg.xml diff --git a/config/alfresco/action-services-context.xml b/config/alfresco/action-services-context.xml index 0fc579e6de..8dcfa3395a 100644 --- a/config/alfresco/action-services-context.xml +++ b/config/alfresco/action-services-context.xml @@ -285,6 +285,9 @@ + + ${mail.header} + diff --git a/config/alfresco/auditConfig.xml b/config/alfresco/auditConfig.xml index f2e43fbb38..1478d733f1 100644 --- a/config/alfresco/auditConfig.xml +++ b/config/alfresco/auditConfig.xml @@ -1,181 +1,202 @@ - - - - - - - - - - - - - - - false - false - false - false - false - false - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + false + false + false + false + false + false + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/authentication-services-context.xml b/config/alfresco/authentication-services-context.xml index fe8bfc971a..4fce7dd6db 100644 --- a/config/alfresco/authentication-services-context.xml +++ b/config/alfresco/authentication-services-context.xml @@ -204,8 +204,12 @@ + @@ -237,12 +241,6 @@ ${spaces.store} - - - - - /${spaces.company_home.childname} - @@ -260,6 +258,88 @@ + + + + + + + + + + + + + + + + + + /${spaces.company_home.childname} + + + ${spaces.store} + + + + + + + + + + + + /${spaces.company_home.childname}/${spaces.guest_home.childname} + + + ${spaces.store} + + + + + + + Consumer + + + + + + + + + + + + + + + + /${spaces.company_home.childname} + + + ${spaces.store} + + + + + + false + + + + All + + + + + All + + + + + diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml index d7c0a90535..4aba97e21a 100644 --- a/config/alfresco/bootstrap-context.xml +++ b/config/alfresco/bootstrap-context.xml @@ -157,6 +157,35 @@ + + + + + jbpm + alfresco/workflow/review_processdefinition.xml + text/xml + true + + + jbpm + alfresco/workflow/adhoc_processdefinition.xml + text/xml + true + + + + + + alfresco/model/workflowModel.xml + + + + + alfresco/workflow/workflow-messages + + + + diff --git a/config/alfresco/bootstrap/system.xml b/config/alfresco/bootstrap/system.xml index a868e910c7..3ce1d4c801 100644 --- a/config/alfresco/bootstrap/system.xml +++ b/config/alfresco/bootstrap/system.xml @@ -24,6 +24,7 @@ /${spaces.company_home.childname} + bootstrapHomeFolderProvider @@ -39,10 +40,11 @@ /${spaces.company_home.childname}/${spaces.guest_home.childname} + bootstrapHomeFolderProvider - + diff --git a/config/alfresco/bootstrap/tutorial.xml b/config/alfresco/bootstrap/tutorial.xml index c8d531cbd2..6c3f83397e 100644 --- a/config/alfresco/bootstrap/tutorial.xml +++ b/config/alfresco/bootstrap/tutorial.xml @@ -2,24 +2,12 @@ xmlns:cm="http://www.alfresco.org/model/content/1.0" xmlns:app="http://www.alfresco.org/model/application/1.0"> - - - - ${tutorial.document.name} - ${tutorial.document.title} - ${tutorial.document.description} - contentUrl=classpath:alfresco/bootstrap/${tutorial.document.name}|mimetype=application/pdf|size=|encoding= - - + + + ${tutorial.document.name} + ${tutorial.document.title} + ${tutorial.document.description} + contentUrl=classpath:alfresco/bootstrap/Alfresco-Tutorial.pdf|mimetype=application/pdf|size=|encoding= + diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index 324452b6eb..48c7f94107 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -1,672 +1,673 @@ - - - - - - - - - - - - - - true - - - - classpath:alfresco/repository.properties - classpath:alfresco/version.properties - classpath:alfresco/domain/transaction.properties - - - - - - - - ${db.driver} - - - ${db.url} - - - ${db.username} - - - ${db.password} - - - ${db.pool.initial} - - - ${db.pool.max} - - - ${db.pool.maxIdleTime} - - - 1 - - - - - - - - - - ${server.transaction.allow-writes} - - - - - - - - - - - alfresco.messages.system-messages - alfresco.messages.dictionary-messages - alfresco.messages.version-service - alfresco.messages.permissions-service - alfresco.messages.content-service - alfresco.messages.coci-service - alfresco.messages.template-service - alfresco.messages.lock-service - alfresco.messages.patch-service - alfresco.messages.schema-update - alfresco.messages.webdav-messages - - - - - - - - - - - - ${mail.host} - - - ${mail.port} - - - ${mail.username} - - - ${mail.password} - - - ${mail.encoding} - - - - - - - - - - org.alfresco.repo.search.Indexer - - - - - - - - - - - - - - indexerComponent - - - - - - - - - - - - - - - - org.alfresco.repo.search.IndexerAndSearcher - - - - - - - - - - - - - - - - - - - - - - org.alfresco.service.cmr.search.CategoryService - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${dir.indexes} - - - - - - - - - ${lucene.maxAtomicTransformationTime} - - - ${lucene.query.maxClauses} - - - ${lucene.indexer.batchSize} - - - ${lucene.indexer.minMergeDocs} - - - ${lucene.indexer.mergeFactor} - - - ${lucene.indexer.maxMergeDocs} - - - ${dir.indexes.lock} - - - ${lucene.indexer.maxFieldLength} - - - ${lucene.write.lock.timeout} - - - ${lucene.commit.lock.timeout} - - - ${lucene.lock.poll.interval} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - org.alfresco.repo.version.common.counter.VersionCounterService - - - - - - - - - - ${server.transaction.mode.default}, PROPAGATION_REQUIRES_NEW - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - alfresco/model/dictionaryModel.xml - alfresco/model/systemModel.xml - alfresco/model/contentModel.xml - alfresco/model/wcmModel.xml - alfresco/model/applicationModel.xml - alfresco/model/forumModel.xml - alfresco/model/recordsModel.xml - alfresco/model/bpmModel.xml - alfresco/model/workflowModel.xml - - - org/alfresco/repo/security/authentication/userModel.xml - org/alfresco/repo/action/actionModel.xml - org/alfresco/repo/rule/ruleModel.xml - org/alfresco/repo/version/version_model.xml - - - - - alfresco/model/dataTypeAnalyzers - alfresco/messages/system-model - alfresco/messages/dictionary-model - alfresco/messages/content-model - alfresco/messages/application-model - alfresco/messages/forum-model - - - - - - - - alfresco/model/defaultCustomModel.xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - - - - - - - - - - - ${dir.root}/backup-lucene-indexes - - - - - - - - - - 5 - - - 20 - - - 60 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - org.alfresco.repo.configuration.ConfigurableService - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - + + + + + + + + + + + + + + true + + + + classpath:alfresco/repository.properties + classpath:alfresco/version.properties + classpath:alfresco/domain/transaction.properties + + + + + + + + ${db.driver} + + + ${db.url} + + + ${db.username} + + + ${db.password} + + + ${db.pool.initial} + + + ${db.pool.max} + + + ${db.pool.maxIdleTime} + + + 1 + + + + + + + + + + ${server.transaction.allow-writes} + + + + + + + + + + + alfresco.messages.system-messages + alfresco.messages.dictionary-messages + alfresco.messages.version-service + alfresco.messages.permissions-service + alfresco.messages.content-service + alfresco.messages.coci-service + alfresco.messages.template-service + alfresco.messages.lock-service + alfresco.messages.patch-service + alfresco.messages.schema-update + alfresco.messages.webdav-messages + + + + + + + + + + + + ${mail.host} + + + ${mail.port} + + + ${mail.username} + + + ${mail.password} + + + ${mail.encoding} + + + + + + + + + + org.alfresco.repo.search.Indexer + + + + + + + + + + + + + + indexerComponent + + + + + + + + + + + + + + + + org.alfresco.repo.search.IndexerAndSearcher + + + + + + + + + + + + + + + + + + + + + + org.alfresco.service.cmr.search.CategoryService + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${dir.indexes} + + + + + + + + + ${lucene.maxAtomicTransformationTime} + + + ${lucene.query.maxClauses} + + + ${lucene.indexer.batchSize} + + + ${lucene.indexer.minMergeDocs} + + + ${lucene.indexer.mergeFactor} + + + ${lucene.indexer.maxMergeDocs} + + + ${dir.indexes.lock} + + + ${lucene.indexer.maxFieldLength} + + + ${lucene.write.lock.timeout} + + + ${lucene.commit.lock.timeout} + + + ${lucene.lock.poll.interval} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.alfresco.repo.version.common.counter.VersionCounterService + + + + + + + + + + ${server.transaction.mode.default}, PROPAGATION_REQUIRES_NEW + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + alfresco/model/dictionaryModel.xml + alfresco/model/systemModel.xml + alfresco/model/contentModel.xml + alfresco/model/bpmModel.xml + alfresco/model/wcmModel.xml + alfresco/model/applicationModel.xml + alfresco/model/forumModel.xml + alfresco/model/recordsModel.xml + alfresco/model/workflowModel.xml + + + org/alfresco/repo/security/authentication/userModel.xml + org/alfresco/repo/action/actionModel.xml + org/alfresco/repo/rule/ruleModel.xml + org/alfresco/repo/version/version_model.xml + + + + + alfresco/model/dataTypeAnalyzers + alfresco/messages/system-model + alfresco/messages/dictionary-model + alfresco/messages/content-model + alfresco/messages/bpm-messages + alfresco/messages/application-model + alfresco/messages/forum-model + + + + + + + + alfresco/model/defaultCustomModel.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + + + + + + + + + + + ${dir.root}/backup-lucene-indexes + + + + + + + + + + 5 + + + 20 + + + 60 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.alfresco.repo.configuration.ConfigurableService + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + diff --git a/config/alfresco/desktop/dumpRequest.js b/config/alfresco/desktop/dumpRequest.js new file mode 100644 index 0000000000..d22cb154d5 --- /dev/null +++ b/config/alfresco/desktop/dumpRequest.js @@ -0,0 +1,38 @@ +// Main action + +function runAction() +{ + out.println("Dump request details :-"); + out.println(" Folder node = " + deskParams.getFolderNode()); + var folder = deskParams.getFolder(); + out.println(" Folder path = " + folder.getFullName()); + out.println(" Number of targets = " + deskParams.numberOfTargetNodes()); + + if ( deskParams.numberOfTargetNodes() > 0) { + out.println(" Targets:"); + + for ( var i = 0; i < deskParams.numberOfTargetNodes(); i++) { + var target = deskParams.getTarget( i); + out.println(" Type = " + target.getTypeAsString() + ", path = " + target.getTarget()); + out.println(" Node = " + target.getNode()); + } + } +} + +// Run the action +// +// Response :- +// Success - no return or return 0, or "0," +// For error or control response then return a string :- +// Error - "1," +// FileNotFound - "2," +// AccessDenied - "3," +// BadParameter - "4, +// NotWorkingCopy - "5," +// NoSuchAction - "6, +// LaunchURL - "7," +// CommandLine - "8," + +runAction(); +var response = "0,Javascript completed successfully"; +response; \ No newline at end of file diff --git a/config/alfresco/extension/index-recovery-context.xml.sample b/config/alfresco/extension/index-recovery-context.xml.sample new file mode 100644 index 0000000000..415831e277 --- /dev/null +++ b/config/alfresco/extension/index-recovery-context.xml.sample @@ -0,0 +1,38 @@ + + + + + + + + + + + + org.alfresco.repo.node.index.IndexRecoveryJob + + + + + + + + + + + + + + + + 5 + + + 0 + + + + diff --git a/config/alfresco/extension/ldap-authentication-context.xml.sample b/config/alfresco/extension/ldap-authentication-context.xml.sample new file mode 100644 index 0000000000..34dbe20833 --- /dev/null +++ b/config/alfresco/extension/ldap-authentication-context.xml.sample @@ -0,0 +1,463 @@ + + + + + + + + + + org.alfresco.repo.security.authentication.MutableAuthenticationDao + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + + + + + + + + + %s + + + + + + + + + + + com.sun.jndi.ldap.LdapCtxFactory + + + + + + + ldap://openldap.domain.com:389 + + + + + + + + DIGEST-MD5 + + + + + + reader + + + + + secret + + + + + + + + + + + + + + + + (objectclass=inetOrgPerson) + + + + + dc=alfresco,dc=org + + + + + uid + + + + + + + + + + + + + + + + /app:company_home + + + + + + + + uid + + + + + givenName + + + + + sn + + + + + mail + + + + + o + + + + + + + + + + + (objectclass=groupOfNames) + + + + + dc=alfresco,dc=org + + + + + uid + + + + + cn + + + + + groupOfNames + + + + + inetOrgPerson + + + + + + + + + + + member + + + + + + + + + + + + + + + + + + + + + org.alfresco.repo.importer.ImporterJob + + + + + + + + + + + + + 30000 + + + + 3600000 + + + + + + + + + org.alfresco.repo.importer.ImporterJob + + + + + + + + + + + + + 30000 + + + + 3600000 + + + + + + + + + + + + + + + + + + + + + + + ${spaces.store} + + + + + /${system.system_container.childname}/${system.people_container.childname} + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${alfresco_user_store.store} + + + + + /${alfresco_user_store.system_container.childname}/${alfresco_user_store.authorities_container.childname} + + + + + true + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/file-servers.xml b/config/alfresco/file-servers.xml index 7b9039b294..e26cd80af5 100644 --- a/config/alfresco/file-servers.xml +++ b/config/alfresco/file-servers.xml @@ -50,6 +50,7 @@ + diff --git a/config/alfresco/import-export-context.xml b/config/alfresco/import-export-context.xml index c38676999e..6b09562fe9 100644 --- a/config/alfresco/import-export-context.xml +++ b/config/alfresco/import-export-context.xml @@ -53,6 +53,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/alfresco/index-recovery-context.xml b/config/alfresco/index-recovery-context.xml index 31d9566062..ae141b90b7 100644 --- a/config/alfresco/index-recovery-context.xml +++ b/config/alfresco/index-recovery-context.xml @@ -4,10 +4,10 @@ - - + + - + @@ -22,62 +22,33 @@ + + + - - - - - false - - - false - - - 1000 - - - NORMAL - - - - + + + + ${index.recovery.mode} - - - - - org.alfresco.repo.node.index.IndexRecoveryJob - - - - - - - - - - - - 60000 - - - 0 - - - - - - --> - + + + \ No newline at end of file diff --git a/config/alfresco/messages/bpm-messages.properties b/config/alfresco/messages/bpm-messages.properties index 8a8886cb2d..69419ae91b 100644 --- a/config/alfresco/messages/bpm-messages.properties +++ b/config/alfresco/messages/bpm-messages.properties @@ -10,14 +10,14 @@ bpm_businessprocessmodel.transition.description=Done # Base Task bpm_businessprocessmodel.type.bpm_task.title=Task bpm_businessprocessmodel.type.bpm_task.description=Task -bpm_businessprocessmodel.property.bpm_taskId.title=Task Identifier -bpm_businessprocessmodel.property.bpm_taskId.description=Task Identifier -bpm_businessprocessmodel.property.bpm_startDate.title=Task Start Date -bpm_businessprocessmodel.property.bpm_startDate.description=Task Start Date -bpm_businessprocessmodel.property.bpm_completionDate.title=Task Completion Date -bpm_businessprocessmodel.property.bpm_completionDate.description=Task Completion Date -bpm_businessprocessmodel.property.bpm_dueDate.title=Task Due Date -bpm_businessprocessmodel.property.bpm_dueDate.description=Task Due Date +bpm_businessprocessmodel.property.bpm_taskId.title=Identifier +bpm_businessprocessmodel.property.bpm_taskId.description=Identifier +bpm_businessprocessmodel.property.bpm_startDate.title=Start Date +bpm_businessprocessmodel.property.bpm_startDate.description=Start Date +bpm_businessprocessmodel.property.bpm_completionDate.title=Completion Date +bpm_businessprocessmodel.property.bpm_completionDate.description=Completion Date +bpm_businessprocessmodel.property.bpm_dueDate.title=Due Date +bpm_businessprocessmodel.property.bpm_dueDate.description=Due Date bpm_businessprocessmodel.property.bpm_status.title=Status bpm_businessprocessmodel.property.bpm_status.description=Status bpm_businessprocessmodel.property.bpm_priority.title=Priority @@ -36,7 +36,9 @@ bpm_businessprocessmodel.property.bpm_workflowInstanceId.title=Workflow Instance bpm_businessprocessmodel.property.bpm_workflowInstanceId.description=Workflow Instance Id bpm_businessprocessmodel.property.bpm_context.title=Task Context bpm_businessprocessmodel.property.bpm_context.description=The context within which this task has been assigned -bpm_businessprocessmodel.property.bpm_outcome.title=Task Outcome +bpm_businessprocessmodel.property.bpm_description.title=Description +bpm_businessprocessmodel.property.bpm_description.description=Description of what needs to be achieved +bpm_businessprocessmodel.property.bpm_outcome.title=Outcome bpm_businessprocessmodel.property.bpm_outcome.description=Decision made on completing Task bpm_businessprocessmodel.property.bpm_completedItems.title=Completed Items bpm_businessprocessmodel.property.bpm_completedItems.description=Package items marked as complete @@ -48,3 +50,15 @@ bpm_businessprocessmodel.association.bpm_package.title=Content Package bpm_businessprocessmodel.association.bpm_package.description=The collection of content routed through the workflow bpm_businessprocessmodel.aspect.bpm_workflowPackage.title=Workflow Package bpm_businessprocessmodel.aspect.bpm_workflowPackage.description=The collection of content routed through the workflow + +# Workflow Start Task +bpm_businessprocessmodel.type.bpm_startTask.title=Workflow Start Task +bpm_businessprocessmodel.type.bpm_startTask.description=Task used to collect information required for initiating Workflow +bpm_businessprocessmodel.property.bpm_workflowDescription.title=Description +bpm_businessprocessmodel.property.bpm_workflowDescription.description=Description +bpm_businessprocessmodel.property.bpm_workflowDueDate.title=Workflow Due Date +bpm_businessprocessmodel.property.bpm_workflowDueDate.description=Workflow Due Date +bpm_businessprocessmodel.property.bpm_workflowPriority.title=Workflow Priority +bpm_businessprocessmodel.property.bpm_workflowPriority.description=Workflow Priority +bpm_businessprocessmodel.association.bpm_assignee.title=Workflow Assignee +bpm_businessprocessmodel.association.bpm_assignee.description=Workflow Assignee diff --git a/config/alfresco/messages/content-service.properties b/config/alfresco/messages/content-service.properties index f7031ec3bd..ed894d3a73 100644 --- a/config/alfresco/messages/content-service.properties +++ b/config/alfresco/messages/content-service.properties @@ -1,4 +1,10 @@ # Content-related messages content.content_missing=The node''s content is missing: \n node: {0} \n reader: {1} \n Please contact your system administrator. -content.runtime_exec.property_moved=The property ''errorCodes'' has moved down onto the RuntimeExec class \ No newline at end of file +content.runtime_exec.property_moved=The property ''errorCodes'' has moved down onto the RuntimeExec class + +index.recovery.store_not_up_to_date=The indexes for store ''{0}'' are not synchronized with the database. +index.recovery.starting=Index recovery started: {0} transactions. +index.recovery.complete=Index recovery completed. +index.recovery.progress=\t{0} % complete. +index.recovery.terminated=Index recovery terminated. \ No newline at end of file diff --git a/config/alfresco/mimetype/openoffice-document-formats.xml b/config/alfresco/mimetype/openoffice-document-formats.xml index 1c18b17845..9579d1ba0d 100644 --- a/config/alfresco/mimetype/openoffice-document-formats.xml +++ b/config/alfresco/mimetype/openoffice-document-formats.xml @@ -10,6 +10,7 @@ Presentationimpress_pdf_Export Spreadsheetcalc_pdf_Export Textwriter_pdf_Export + Htmlwriter_web_pdf_Export @@ -26,7 +27,8 @@ - 1. additional files may be generated for images and this would require extra care in a servlet environment - 2. output quality does not seem to be very good in many cases --> - HTML + Html + Html text/html html @@ -44,6 +46,7 @@ odt Textwriter8 + Htmlwriterweb8_writer diff --git a/config/alfresco/model/contentModel.xml b/config/alfresco/model/contentModel.xml index 4c18eda728..e6523fb8d9 100644 --- a/config/alfresco/model/contentModel.xml +++ b/config/alfresco/model/contentModel.xml @@ -1,705 +1,711 @@ - - - Alfresco Content Domain Model - Alfresco - 2005-09-29 - 1.0 - - - - - - - - - - - - - \<\?\/\:\|\xA3\xAC\%\&\+\;]+.*]]> - false - - - - - - - Object - sys:base - - - Name - d:text - true - - - - - - - cm:auditable - - - - - Folder - cm:cmobject - true - - - - false - false - - - sys:base - false - true - - false - - - - - - Content - cm:cmobject - true - - - d:content - false - - - true - false - true - - - - - - - Dictionary Model - cm:content - - - Model name - d:qname - true - - - Description - d:text - true - - - Author - d:text - true - - - Published Date - d:date - true - - - Version - d:text - true - - - Model Active - d:boolean - false - - - - - - Link Object - cm:cmobject - - - Link Destination - d:noderef - true - - - - - - Saved Query - cm:content - - - - System Folder - cm:folder - - - - Person - sys:base - - - d:text - true - - - d:noderef - true - - - d:text - true - - - d:text - true - - - d:text - - - d:text - - - d:text - - - - - - - - Category Root - cm:cmobject - - - - false - true - - - cm:category - false - true - - - - - sys:aspect_root - - - - - Category - cm:cmobject - - - - false - true - - - cm:category - false - true - - - - - - - - - - - - Titled - - - Title - d:text - - - Description - d:text - - - - - - Auditable - - - Created - d:datetime - true - true - - - Creator - d:text - true - true - - - Modified - d:datetime - true - true - - - Modifier - d:text - true - true - - - Accessed - d:datetime - true - - - - - - Localizable - - - Locale - - d:category - - - - - - Translatable - cm:localizable - - - - Translations - - cm:translationOf - false - false - - - cm:content - cm:hasTranslation - false - true - - - - - - - Transformable - - - Formats - - cm:formatOf - false - false - - - cm:content - cm:hasFormat - false - true - - - - - - - Templatable - - - Template - d:noderef - false - - - - - - Complianceable - cm:auditable - - - - Remove After - d:datetime - - - - - - Ownable - - - Owner - d:text - - - - - - Author - - - Author - d:text - - - - - - Dublin Core - cm:titled - - - Publisher - d:text - true - - - Contributor - d:text - true - - - Type - d:text - true - - - Identifier - d:text - true - - - Source - d:text - true - - - Coverage - d:text - true - - - Rights - d:text - true - - - Subject - d:text - true - - - - cm:auditable - cm:author - - - - - Basable - - - - cm:basedOn - false - true - - - cm:content - cm:hasBasis - false - true - - - - - - - Partable - - - - cm:partOf - false - true - - - cm:content - cm:hasPart - false - true - - - - - - - Referencing - - - - cm:referencedBy - false - true - - - cm:content - cm:references - false - true - - - - - - - Replacable - - - - cm:replacedBy - false - true - - - cm:content - cm:replaces - false - true - - - - - - - Effectivity - - - Effective From - d:datetime - - - Effective To - d:datetime - - - - - - Summarizable - - - Summary - d:text - - - - - - Countable - - - d:int - - - d:int - - - - - - Copied From - - - d:noderef - true - true - false - - true - false - true - - - - - - - Working Copy - - - d:text - true - true - - - - - - Versionable - - - Version Label - d:text - true - - - Initial Version - d:boolean - true - - - Auto Version - d:boolean - true - - - - - - Lockable - - - d:text - true - - - d:text - true - - - d:date - true - false - - - d:boolean - true - - - - - - - - - false - true - - - cm:person - false - true - - - - - - - Classifiable - - - - General Classifiable - cm:classifiable - - - Categories - d:category - false - true - - true - true - true - - - - - - - Attachable - - - - false - true - - - cm:cmobject - false - true - - - - - - - Emailed - - - Originator - d:text - - - Addressee - d:text - - - Addressees - d:text - true - - - Subject - d:text - - - Sent Date - d:datetime - - - - - - - References Node - - - Node Reference - d:noderef - true - - - - - - - + + + Alfresco Content Domain Model + Alfresco + 2005-09-29 + 1.0 + + + + + + + + + + + + + \<\?\/\:\|\xA3\xAC\%\&\+\;]+.*]]> + false + + + + + + + Object + sys:base + + + Name + d:text + true + + + + + + + cm:auditable + + + + + Folder + cm:cmobject + true + + + + false + true + + + sys:base + false + true + + false + + + + + + Content + cm:cmobject + true + + + d:content + false + + + true + false + true + + + + + + + Dictionary Model + cm:content + + + Model name + d:qname + true + + + Description + d:text + true + + + Author + d:text + true + + + Published Date + d:date + true + + + Version + d:text + true + + + Model Active + d:boolean + false + + + + + + Link Object + cm:cmobject + + + Link Destination + d:noderef + true + + + + + + Saved Query + cm:content + + + + System Folder + cm:folder + + + + Person + sys:base + + + d:text + true + + + d:noderef + true + + + d:text + true + + + d:text + true + + + d:text + + + d:text + + + d:text + + + d:text + + + d:text + + + + + + + + Category Root + cm:cmobject + + + + false + true + + + cm:category + false + true + + + + + sys:aspect_root + + + + + Category + cm:cmobject + + + + false + true + + + cm:category + false + true + + + + + + + + + + + + Titled + + + Title + d:text + + + Description + d:text + + + + + + Auditable + + + Created + d:datetime + true + true + + + Creator + d:text + true + true + + + Modified + d:datetime + true + true + + + Modifier + d:text + true + true + + + Accessed + d:datetime + true + + + + + + Localizable + + + Locale + + d:category + + + + + + Translatable + cm:localizable + + + + Translations + + cm:translationOf + false + false + + + cm:content + cm:hasTranslation + false + true + + + + + + + Transformable + + + Formats + + cm:formatOf + false + false + + + cm:content + cm:hasFormat + false + true + + + + + + + Templatable + + + Template + d:noderef + false + + + + + + Complianceable + cm:auditable + + + + Remove After + d:datetime + + + + + + Ownable + + + Owner + d:text + + + + + + Author + + + Author + d:text + + + + + + Dublin Core + cm:titled + + + Publisher + d:text + true + + + Contributor + d:text + true + + + Type + d:text + true + + + Identifier + d:text + true + + + Source + d:text + true + + + Coverage + d:text + true + + + Rights + d:text + true + + + Subject + d:text + true + + + + cm:auditable + cm:author + + + + + Basable + + + + cm:basedOn + false + true + + + cm:content + cm:hasBasis + false + true + + + + + + + Partable + + + + cm:partOf + false + true + + + cm:content + cm:hasPart + false + true + + + + + + + Referencing + + + + cm:referencedBy + false + true + + + cm:content + cm:references + false + true + + + + + + + Replacable + + + + cm:replacedBy + false + true + + + cm:content + cm:replaces + false + true + + + + + + + Effectivity + + + Effective From + d:datetime + + + Effective To + d:datetime + + + + + + Summarizable + + + Summary + d:text + + + + + + Countable + + + d:int + + + d:int + + + + + + Copied From + + + d:noderef + true + true + false + + true + false + true + + + + + + + Working Copy + + + d:text + true + true + + + + + + Versionable + + + Version Label + d:text + true + + + Initial Version + d:boolean + true + + + Auto Version + d:boolean + true + + + + + + Lockable + + + d:text + true + + + d:text + true + + + d:date + true + false + + + d:boolean + true + + + + + + + + + false + true + + + cm:person + false + true + + + + + + + Classifiable + + + + General Classifiable + cm:classifiable + + + Categories + d:category + false + true + + true + true + true + + + + + + + Attachable + + + + false + true + + + cm:cmobject + false + true + + + + + + + Emailed + + + Originator + d:text + + + Addressee + d:text + + + Addressees + d:text + true + + + Subject + d:text + + + Sent Date + d:datetime + + + + + + + References Node + + + Node Reference + d:noderef + true + + + + + + + diff --git a/config/alfresco/model/dataTypeAnalyzers.properties b/config/alfresco/model/dataTypeAnalyzers.properties index 75b6672692..7529f289d2 100644 --- a/config/alfresco/model/dataTypeAnalyzers.properties +++ b/config/alfresco/model/dataTypeAnalyzers.properties @@ -1,17 +1,17 @@ # Data Type Index Analyzers -d_dictionary.datatype.d_any.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer -d_dictionary.datatype.d_text.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer -d_dictionary.datatype.d_content.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer +d_dictionary.datatype.d_any.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser +d_dictionary.datatype.d_text.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser +d_dictionary.datatype.d_content.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser d_dictionary.datatype.d_int.analyzer=org.alfresco.repo.search.impl.lucene.analysis.IntegerAnalyser d_dictionary.datatype.d_long.analyzer=org.alfresco.repo.search.impl.lucene.analysis.LongAnalyser d_dictionary.datatype.d_float.analyzer=org.alfresco.repo.search.impl.lucene.analysis.FloatAnalyser d_dictionary.datatype.d_double.analyzer=org.alfresco.repo.search.impl.lucene.analysis.DoubleAnalyser d_dictionary.datatype.d_date.analyzer=org.alfresco.repo.search.impl.lucene.analysis.DateAnalyser d_dictionary.datatype.d_datetime.analyzer=org.alfresco.repo.search.impl.lucene.analysis.DateAnalyser -d_dictionary.datatype.d_boolean.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer -d_dictionary.datatype.d_qname.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer -d_dictionary.datatype.d_guid.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer -d_dictionary.datatype.d_category.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer -d_dictionary.datatype.d_noderef.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer -d_dictionary.datatype.d_path.analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer +d_dictionary.datatype.d_boolean.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser +d_dictionary.datatype.d_qname.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser +d_dictionary.datatype.d_guid.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser +d_dictionary.datatype.d_category.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser +d_dictionary.datatype.d_noderef.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser +d_dictionary.datatype.d_path.analyzer=org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser diff --git a/config/alfresco/model/dictionaryModel.xml b/config/alfresco/model/dictionaryModel.xml index 95fa5e2b69..2c57afdd57 100644 --- a/config/alfresco/model/dictionaryModel.xml +++ b/config/alfresco/model/dictionaryModel.xml @@ -19,17 +19,17 @@ - org.apache.lucene.analysis.standard.StandardAnalyzer + org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser java.lang.Object - org.apache.lucene.analysis.standard.StandardAnalyzer + org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser java.lang.String - org.apache.lucene.analysis.standard.StandardAnalyzer + org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser org.alfresco.service.cmr.repository.ContentData @@ -64,37 +64,37 @@ - org.apache.lucene.analysis.standard.StandardAnalyzer + org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser java.lang.Boolean - org.apache.lucene.analysis.standard.StandardAnalyzer + org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser org.alfresco.service.namespace.QName - org.apache.lucene.analysis.standard.StandardAnalyzer + org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser org.alfresco.service.cmr.repository.NodeRef - org.apache.lucene.analysis.standard.StandardAnalyzer + org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser org.alfresco.service.cmr.repository.ChildAssociationRef - org.apache.lucene.analysis.standard.StandardAnalyzer + org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser org.alfresco.service.cmr.repository.AssociationRef - org.apache.lucene.analysis.standard.StandardAnalyzer + org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser org.alfresco.service.cmr.repository.Path - org.apache.lucene.analysis.standard.StandardAnalyzer + org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser org.alfresco.service.cmr.repository.NodeRef diff --git a/config/alfresco/model/permissionDefinitions.xml b/config/alfresco/model/permissionDefinitions.xml index 76453c7e46..baeef6d286 100644 --- a/config/alfresco/model/permissionDefinitions.xml +++ b/config/alfresco/model/permissionDefinitions.xml @@ -63,11 +63,48 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -78,13 +115,13 @@ - + - - + + @@ -94,10 +131,10 @@ - - + + @@ -107,10 +144,10 @@ - - + + @@ -125,42 +162,42 @@ - - + + - - + + - - + + - - + + - + @@ -168,52 +205,55 @@ - - + + - - + + - - + + - + + - + + - + + @@ -223,17 +263,19 @@ - + + - + + @@ -285,6 +327,21 @@ + + + + + + + + + + + + + + + @@ -300,6 +357,7 @@ + @@ -333,16 +391,20 @@ - + + + + + - - + + - + @@ -357,24 +419,34 @@ - + + + - + + + - + + + + + + + + - - + + - - - + + diff --git a/config/alfresco/network-protocol-context.xml b/config/alfresco/network-protocol-context.xml index 6e615800a0..10fa179cfe 100644 --- a/config/alfresco/network-protocol-context.xml +++ b/config/alfresco/network-protocol-context.xml @@ -57,7 +57,7 @@ - + diff --git a/config/alfresco/node-services-context.xml b/config/alfresco/node-services-context.xml index 1f4cf52b9f..03226f4871 100644 --- a/config/alfresco/node-services-context.xml +++ b/config/alfresco/node-services-context.xml @@ -103,7 +103,7 @@ false - false + true 5 diff --git a/config/alfresco/policy-context.xml b/config/alfresco/policy-context.xml index ee10002be9..0ca2261111 100644 --- a/config/alfresco/policy-context.xml +++ b/config/alfresco/policy-context.xml @@ -18,6 +18,12 @@ + + + + + + diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties index 731c6143bc..bfa073e697 100644 --- a/config/alfresco/repository.properties +++ b/config/alfresco/repository.properties @@ -1,135 +1,138 @@ -# Directory configuration - -dir.root=./alf_data - -dir.contentstore=${dir.root}/contentstore -dir.contentstore.deleted=${dir.root}/contentstore.deleted - -dir.auditcontentstore=${dir.root}/audit.contentstore - -# The location for lucene index files - -dir.indexes=${dir.root}/lucene-indexes - -# The location for lucene index locks - -dir.indexes.lock=${dir.indexes}/locks - -# #################### # -# Lucene configuration # -# #################### # -# -# Millisecond threshold for text transformations -# Slower transformers will force the text extraction to be asynchronous -# -lucene.maxAtomicTransformationTime=20 -# -# The maximum number of clauses that are allowed in a lucene query -# -lucene.query.maxClauses=10000 -# -# The size of the queue of nodes waiting for index -# Events are generated as nodes are changed, this is the maximum size of the queue used to coalesce event -# When this size is reached the lists of nodes will be indexed -# -lucene.indexer.batchSize=1000 -# -# Lucene index min merge docs - the in memory size of the index -# -lucene.indexer.minMergeDocs=1000 -# -# When lucene index files are merged together - it will try to keep this number of segments/files in -# -lucene.indexer.mergeFactor=10 -# -# Roughly the maximum number of nodes indexed in one file/segment -# -lucene.indexer.maxMergeDocs=100000 -# -# The number of terms from a document that will be indexed -# -lucene.indexer.maxFieldLength=10000 - -lucene.write.lock.timeout=10000 -lucene.commit.lock.timeout=100000 -lucene.lock.poll.interval=100 - -# Database configuration - -db.schema.update=true -db.driver=org.gjt.mm.mysql.Driver -db.name=alfresco -db.url=jdbc:mysql:///${db.name} -db.username=alfresco -db.password=alfresco -db.pool.initial=10 -db.pool.max=20 -db.pool.maxIdleTime=120 - -# Email configuration - -mail.host= -mail.port=25 -mail.username=anonymous -mail.password= -# Set this value to UTF-8 or similar for encoding of email messages as required -mail.encoding=UTF-8 - -# System Configuration - -system.store=system://system -system.descriptor.childname=sys:descriptor -system.descriptor.current.childname=sys:descriptor-current - -# User config - -alfresco_user_store.store=user://alfrescoUserStore -alfresco_user_store.system_container.childname=sys:system -alfresco_user_store.user_container.childname=sys:people -alfresco_user_store.authorities_container.childname=sys:authorities - -# Spaces Archive Configuration -spaces.archive.store=archive://SpacesStore - -# Spaces Configuration - -spaces.store=workspace://SpacesStore -spaces.company_home.childname=app:company_home -spaces.guest_home.childname=app:guest_home -spaces.dictionary.childname=app:dictionary -spaces.templates.childname=app:space_templates -spaces.templates.content.childname=app:content_templates -spaces.templates.email.childname=app:email_templates -spaces.templates.rss.childname=app:rss_templates -spaces.savedsearches.childname=app:saved_searches -spaces.scripts.childname=app:scripts -spaces.wcm.childname=app:wcm -spaces.content_forms.childname=app:wcm_forms - -# Folders for storing people - -system.system_container.childname=sys:system -system.people_container.childname=sys:people - -# Folders for storing workflow related info - -system.workflow_container.childname=sys:workflow - -# Are user names case sensitive? -# ============================== -# -# NOTE: If you are using mysql you must have case sensitive collation -# -# You can do this when creating the alfresco database at the start -# CREATE DATABASE alfresco CHARACTER SET utf8 COLLATION utf8_bin; -# If you want to do this later this is a dump and load fix as it is done when the database, tables and columns are created. -# -# Must other databases are case sensitive by default. -# - -user.name.caseSensitive=false - -# AVM Specific properties. -avm.remote.idlestream.timeout=30000 -avm.remote.port=1313 - +# Directory configuration + +dir.root=./alf_data + +dir.contentstore=${dir.root}/contentstore +dir.contentstore.deleted=${dir.root}/contentstore.deleted + +dir.auditcontentstore=${dir.root}/audit.contentstore + +# The location for lucene index files +dir.indexes=${dir.root}/lucene-indexes + +# The location for lucene index locks +dir.indexes.lock=${dir.indexes}/locks + +# The index recovery mode (NONE, VALIDATE, AUTO, FULL) +index.recovery.mode=VALIDATE + +# #################### # +# Lucene configuration # +# #################### # +# +# Millisecond threshold for text transformations +# Slower transformers will force the text extraction to be asynchronous +# +lucene.maxAtomicTransformationTime=20 +# +# The maximum number of clauses that are allowed in a lucene query +# +lucene.query.maxClauses=10000 +# +# The size of the queue of nodes waiting for index +# Events are generated as nodes are changed, this is the maximum size of the queue used to coalesce event +# When this size is reached the lists of nodes will be indexed +# +lucene.indexer.batchSize=1000 +# +# Lucene index min merge docs - the in memory size of the index +# +lucene.indexer.minMergeDocs=1000 +# +# When lucene index files are merged together - it will try to keep this number of segments/files in +# +lucene.indexer.mergeFactor=10 +# +# Roughly the maximum number of nodes indexed in one file/segment +# +lucene.indexer.maxMergeDocs=100000 +# +# The number of terms from a document that will be indexed +# +lucene.indexer.maxFieldLength=10000 + +lucene.write.lock.timeout=10000 +lucene.commit.lock.timeout=100000 +lucene.lock.poll.interval=100 + +# Database configuration + +db.schema.update=true +db.driver=org.gjt.mm.mysql.Driver +db.name=alfresco +db.url=jdbc:mysql:///${db.name} +db.username=alfresco +db.password=alfresco +db.pool.initial=10 +db.pool.max=20 +db.pool.maxIdleTime=120 + +# Email configuration + +mail.host= +mail.port=25 +mail.username=anonymous +mail.password= +# Set this value to UTF-8 or similar for encoding of email messages as required +mail.encoding=UTF-8 +# Set this value to 7bit or similar for Asian encoding of email headers as required +mail.header= + +# System Configuration + +system.store=system://system +system.descriptor.childname=sys:descriptor +system.descriptor.current.childname=sys:descriptor-current + +# User config + +alfresco_user_store.store=user://alfrescoUserStore +alfresco_user_store.system_container.childname=sys:system +alfresco_user_store.user_container.childname=sys:people +alfresco_user_store.authorities_container.childname=sys:authorities + +# Spaces Archive Configuration +spaces.archive.store=archive://SpacesStore + +# Spaces Configuration + +spaces.store=workspace://SpacesStore +spaces.company_home.childname=app:company_home +spaces.guest_home.childname=app:guest_home +spaces.dictionary.childname=app:dictionary +spaces.templates.childname=app:space_templates +spaces.templates.content.childname=app:content_templates +spaces.templates.email.childname=app:email_templates +spaces.templates.rss.childname=app:rss_templates +spaces.savedsearches.childname=app:saved_searches +spaces.scripts.childname=app:scripts +spaces.wcm.childname=app:wcm +spaces.content_forms.childname=app:wcm_forms + +# Folders for storing people + +system.system_container.childname=sys:system +system.people_container.childname=sys:people + +# Folders for storing workflow related info + +system.workflow_container.childname=sys:workflow + +# Are user names case sensitive? +# ============================== +# +# NOTE: If you are using mysql you must have case sensitive collation +# +# You can do this when creating the alfresco database at the start +# CREATE DATABASE alfresco CHARACTER SET utf8 COLLATION utf8_bin; +# If you want to do this later this is a dump and load fix as it is done when the database, tables and columns are created. +# +# Must other databases are case sensitive by default. +# + +user.name.caseSensitive=false + +# AVM Specific properties. +avm.remote.idlestream.timeout=30000 +avm.remote.port=1313 + diff --git a/config/alfresco/scheduled-jobs-context.xml b/config/alfresco/scheduled-jobs-context.xml index f0acdafbbb..294215a324 100644 --- a/config/alfresco/scheduled-jobs-context.xml +++ b/config/alfresco/scheduled-jobs-context.xml @@ -2,9 +2,25 @@ - - - + + + + + + + true + + + classpath:alfresco/domain/quartz.properties + + + DefaultScheduler + + + + + + @@ -21,16 +37,74 @@ - - - 60000 + + - - 60000 + + + 1 + + + 1 + + + + + + + + + + org.alfresco.repo.node.index.IndexRecoveryJob + + + + + + + + + + + + 5 + + + 0 + + + + + + + + org.alfresco.repo.node.index.IndexRecoveryJob + + + + + + + + + + + + + + + 1 + + + 0 + @@ -48,15 +122,16 @@ - - 1800000 - - - 3600000 - + + + 30 + + + 60 + @@ -84,33 +159,6 @@ - - - - - - org.alfresco.repo.node.index.IndexRecoveryJob - - - - - - - - - - - - 60000 - - - 0 - - - - - - org.alfresco.repo.search.impl.lucene.LuceneIndexerAndSearcherFactory2$LuceneIndexBackupJob @@ -150,26 +198,12 @@ --> - - 3600000 + + + 60 - - 3600000 - - - - - - - - - true - - - classpath:alfresco/domain/quartz.properties - - - DefaultScheduler + + 60 diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties index 87530803c5..681bec09e2 100644 --- a/config/alfresco/version.properties +++ b/config/alfresco/version.properties @@ -7,7 +7,7 @@ version.major=1 version.minor=4 version.revision=0 -version.label=Preview +version.label=RC1 # Edition label diff --git a/config/alfresco/workflow-context.xml b/config/alfresco/workflow-context.xml index 1c61ca621e..468f5d350a 100644 --- a/config/alfresco/workflow-context.xml +++ b/config/alfresco/workflow-context.xml @@ -3,50 +3,6 @@ - - - - - - - - - jbpm - org/alfresco/repo/workflow/jbpm/review_and_approve_processdefinition.xml - text/xml - false - - - jbpm - org/alfresco/repo/workflow/jbpm/adhoc_task_processdefinition.xml - text/xml - false - - - jbpm - alfresco/workflow/wcmSubmit.xml - text/xml - false - - - - - - - - - alfresco/model/bpmModel.xml - alfresco/model/workflowModel.xml - - - - - alfresco/messages/bpm-messages - alfresco/messages/workflow-messages - - - - @@ -55,6 +11,7 @@ + @@ -64,7 +21,6 @@ - @@ -76,7 +32,7 @@ - false + true @@ -109,7 +65,7 @@ - + diff --git a/config/alfresco/workflow/adhoc_processdefinition.xml b/config/alfresco/workflow/adhoc_processdefinition.xml new file mode 100644 index 0000000000..54db1cd748 --- /dev/null +++ b/config/alfresco/workflow/adhoc_processdefinition.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/workflow/review_processdefinition.xml b/config/alfresco/workflow/review_processdefinition.xml new file mode 100644 index 0000000000..a3a9403ccf --- /dev/null +++ b/config/alfresco/workflow/review_processdefinition.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/workflow/workflow-messages.properties b/config/alfresco/workflow/workflow-messages.properties new file mode 100644 index 0000000000..c21271e212 --- /dev/null +++ b/config/alfresco/workflow/workflow-messages.properties @@ -0,0 +1,54 @@ +# Display labels for out-of-the-box Content-oriented Workflows + +# +# Review & Approve Workflow +# + +wf_review.workflow.title=Review & Approve +wf_review.workflow.description=Review & approval of content + +# Review & Approve Task Definitions + +wf_workflowmodel.type.wf_submitReviewTask.title=Start Review +wf_workflowmodel.type.wf_submitReviewTask.description=Submit documents for review & approval +wf_workflowmodel.type.wf_reviewTask.title=Review +wf_workflowmodel.type.wf_reviewTask.description=Review Documents to Approve or Reject them + +# Review & Approve Process Definitions + +wf_review.node.start.title=Start +wf_review.node.start.description=Start +wf_review.node.review.title=Review +wf_review.node.review.description=Review +wf_review.node.review.transition.reject.title=Reject +wf_review.node.review.transition.reject.description=Reject +wf_review.node.review.transition.approve.title=Approve +wf_review.node.review.transition.approve.description=Approve +wf_review.node.rejected.title=Rejected +wf_review.node.rejected.description=Rejected +wf_review.task.wf_rejectedTask.title=Rejected +wf_review.task.wf_rejectedTask.description=Rejected +wf_review.node.approved.title=Approved +wf_review.node.approved.description=Approved +wf_review.task.wf_approvedTask.title=Approved +wf_review.task.wf_approvedTask.description=Approved +wf_review.node.end.title=End +wf_review.node.end.description=End + +# +# Adhoc Task Workflow +# + +wf_adhoc.workflow.title=Adhoc Task +wf_adhoc.workflow.description=Assign task to colleague + +# Adhoc Task Definitions + +wf_workflowmodel.type.wf_submitAdhocTask.title=Start Adhoc Task +wf_workflowmodel.type.wf_submitAdhocTask.description=Allocate task to colleague +wf_workflowmodel.property.wf_notifyMe.title=Notify Me +wf_workflowmodel.property.wf_notifyMe.description=Notify me when task is complete +wf_workflowmodel.type.wf_adhocTask.title=Adhoc Task +wf_workflowmodel.type.wf_adhocTask.description=Adhoc Task allocated by colleague +wf_workflowmodel.type.wf_completedAdhocTask.title=Adhoc Task Completed +wf_workflowmodel.type.wf_completedAdhocTask.description=Adhoc Task Completed diff --git a/config/alfresco/workflow/workflowModel.xml b/config/alfresco/workflow/workflowModel.xml new file mode 100644 index 0000000000..73fdd9e553 --- /dev/null +++ b/config/alfresco/workflow/workflowModel.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + bpm:startTask + + + + bpm:workflowTask + + + + + workflow_item_edit_actions + + + + + + + + + + + + + + bpm:startTask + + + + d:boolean + false + + + + + + + bpm:workflowTask + + + + bpm:workflowTask + + + + + \ No newline at end of file diff --git a/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java index 0b973efc20..c5647faff4 100644 --- a/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java +++ b/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java @@ -608,10 +608,28 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticator implements Ca // Process the security blob byte[] respBlob = null; - + boolean isNTLMSSP = false; + try { - if ( useRawNTLMSSP()) + + // Check if the blob has the NTLMSSP signature + + if ( secBlobLen >= NTLM.Signature.length) { + + // Check for the NTLMSSP signature + + int idx = 0; + while ( idx < NTLM.Signature.length && buf[secBlobPos + idx] == NTLM.Signature[ idx]) + idx++; + + if ( idx == NTLM.Signature.length) + isNTLMSSP = true; + } + + // Process the security blob + + if ( isNTLMSSP == true) { // Process an NTLMSSP security blob @@ -657,7 +675,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticator implements Ca // Check if there is/was a session setup object stored in the session, this indicates a multi-stage session // setup so set the status code accordingly - if ( useRawNTLMSSP() || sess.hasSetupObject() || setupObj != null) + if ( useRawNTLMSSP() || isNTLMSSP == true || sess.hasSetupObject() || setupObj != null) { // NTLMSSP has two stages, if there is a stored setup object then indicate more processing // required diff --git a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java index 6895b50b97..46c7e16839 100644 --- a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java +++ b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java @@ -1774,7 +1774,7 @@ public class ServerConfiguration implements ApplicationListener // Check if the appropriate authentication component type is configured if ( ntlmMode != NTLMMode.NONE) - throw new AlfrescoRuntimeException("Wrong authentication setup for passthru authenticator"); + throw new AlfrescoRuntimeException("Wrong authentication setup for passthru authenticator (can only be used with LDAP/JAAS auth component)"); // Load the passthru authenticator dynamically diff --git a/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java b/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java index d01bee8699..049e5d4e7d 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java @@ -57,6 +57,7 @@ import org.alfresco.filesys.util.DataBuffer; import org.alfresco.filesys.util.WildCard; import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.lock.NodeLockedException; import org.alfresco.service.cmr.repository.ContentService; @@ -99,10 +100,13 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface private SearchService searchService; private ContentService contentService; private PermissionService permissionService; - private CheckOutCheckInService checkOutInService; private AuthenticationComponent authComponent; + // Service registry for desktop actions + + private ServiceRegistry serviceRegistry; + /** * Class constructor * @@ -173,13 +177,13 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface } /** - * Return the check in/out service + * Return the service registry * - * @return CheckOutInService + * @return ServiceRegistry */ - public final CheckOutCheckInService getCheckInOutService() + public final ServiceRegistry getServiceRegistry() { - return this.checkOutInService; + return this.serviceRegistry; } /** @@ -233,13 +237,13 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface } /** - * Set the check in/out service + * Set the service registry * - * @param checkInService CheckOutInService + * @param serviceRegistry */ - public void setCheckInOutService(CheckOutCheckInService checkInService) + public void setServiceRegistry(ServiceRegistry serviceRegistry) { - this.checkOutInService = checkInService; + this.serviceRegistry = serviceRegistry; } /** @@ -831,20 +835,108 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface } else { - // Create the transaction - - sess.beginTransaction(transactionService, true); - - // Get the file information to check if the file/folder exists - - FileInfo info = getFileInformation(sess, tree, name); - if (info.isDirectory()) + // Check if pseudo files are enabled + + if ( hasPseudoFileInterface(ctx)) { - status = FileStatus.DirectoryExists; + // Check if the file name is a pseudo file name + + if ( getPseudoFileInterface( ctx).isPseudoFile(sess, tree, name)) { + // Make sure the parent folder has a file state, and the path exists + + String[] paths = FileName.splitPath( name); + fstate = ctx.getStateTable().findFileState( paths[0]); + + if ( fstate == null) { + + // Check if the path exists + + if ( fileExists( sess, tree, paths[0]) == FileStatus.DirectoryExists) + { + // Create the file state + + fstate = ctx.getStateTable().findFileState( paths[0], true, true); + + fstate.setFileStatus( FileStatus.DirectoryExists); + + // Get the node for the folder path + + sess.beginTransaction(transactionService, true); + fstate.setNodeRef( getNodeForPath( tree, paths[0])); + + // Add pseudo files to the folder + + getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]); + + // Debug + + if ( logger.isInfoEnabled()) + logger.info( "Added file state for pseudo files folder (exists) - " + paths[0]); + } + } + else if ( fstate.hasPseudoFiles() == false) + { + // Make sure the file state has the node ref + + if ( fstate.hasNodeRef() == false) + { + // Create the transaction + + sess.beginTransaction(transactionService, true); + + // Get the node for the folder path + + fstate.setNodeRef( getNodeForPath( tree, paths[0])); + } + + // Add pseudo files for the parent folder + + getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]); + + // Debug + + if ( logger.isInfoEnabled()) + logger.info( "Added pseudo files for folder (exists) - " + paths[0]); + } + + // Check if the path is to a pseudo file + + PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, name); + if ( pfile != null) + { + // Indicate that the file exists + + status = FileStatus.FileExists; + } + else + { + // Failed to find pseudo file + + if ( logger.isInfoEnabled()) + logger.info( "Failed to find pseudo file (exists) - " + name); + } + } } - else + + // If the file is not a pseudo file then search for the file + + if ( status == FileStatus.Unknown) { - status = FileStatus.FileExists; + // Create the transaction + + sess.beginTransaction(transactionService, true); + + // Get the file information to check if the file/folder exists + + FileInfo info = getFileInformation(sess, tree, name); + if (info.isDirectory()) + { + status = FileStatus.DirectoryExists; + } + else + { + status = FileStatus.FileExists; + } } } } @@ -861,13 +953,17 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface status = FileStatus.NotExist; } - // done + // Debug + if (logger.isDebugEnabled()) { logger.debug("File status determined: \n" + " name: " + name + "\n" + " status: " + status); } + + // Return the file/folder status + return status; } @@ -896,15 +992,65 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface if ( hasPseudoFileInterface(ctx)) { - // Check if the path is to a pseudo file - - PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, params.getPath()); - if ( pfile != null) - { - // Create a network file to access the pseudo file data - - return pfile.getFile( params.getPath()); - } + // Check if the file name is a pseudo file name + + String path = params.getPath(); + + if ( getPseudoFileInterface( ctx).isPseudoFile(sess, tree, path)) { + + // Make sure the parent folder has a file state, and the path exists + + String[] paths = FileName.splitPath( path); + FileState fstate = ctx.getStateTable().findFileState( paths[0]); + + if ( fstate == null) { + + // Check if the path exists + + if ( fileExists( sess, tree, paths[0]) == FileStatus.DirectoryExists) + { + // Create the file state and add any pseudo files + + fstate = ctx.getStateTable().findFileState( paths[0], true, true); + + fstate.setFileStatus( FileStatus.DirectoryExists); + getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]); + + // Debug + + if ( logger.isInfoEnabled()) + logger.info( "Added file state for pseudo files folder (open) - " + paths[0]); + } + } + else if ( fstate.hasPseudoFiles() == false) + { + // Add pseudo files for the parent folder + + getPseudoFileInterface( ctx).addPseudoFilesToFolder( sess, tree, paths[0]); + + // Debug + + if ( logger.isInfoEnabled()) + logger.info( "Added pseudo files for folder (open) - " + paths[0]); + } + + // Check if the path is to a pseudo file + + PseudoFile pfile = getPseudoFileInterface(ctx).getPseudoFile( sess, tree, params.getPath()); + if ( pfile != null) + { + // Create a network file to access the pseudo file data + + return pfile.getFile( params.getPath()); + } + else + { + // Failed to find pseudo file + + if ( logger.isInfoEnabled()) + logger.info( "Failed to find pseudo file (open) - " + params.getPath()); + } + } } // Not a pseudo file, try and open a normal file/folder node @@ -1045,7 +1191,7 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface try { - // get the device root + // Get the device root ContentContext ctx = (ContentContext) tree.getContext(); NodeRef deviceRootNodeRef = ctx.getRootNode(); @@ -1888,7 +2034,8 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface FileState fstate = ctx.getStateTable().findFileState(path); if ( fstate != null && fstate.hasNodeRef() && fstate.exists() ) { - // check that the node exists + // Check that the node exists + if (nodeService.exists(fstate.getNodeRef())) { // Bump the file states expiry time diff --git a/source/java/org/alfresco/filesys/smb/server/repo/DesktopAction.java b/source/java/org/alfresco/filesys/smb/server/repo/DesktopAction.java index d17fca8b31..1bcc759564 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/DesktopAction.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/DesktopAction.java @@ -27,7 +27,6 @@ import org.alfresco.filesys.server.filesys.DiskSharedDevice; import org.alfresco.filesys.smb.server.repo.pseudo.LocalPseudoFile; import org.alfresco.filesys.smb.server.repo.pseudo.PseudoFile; import org.alfresco.service.ServiceRegistry; -import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.search.SearchService; @@ -35,8 +34,6 @@ import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.support.WebApplicationContextUtils; /** * Desktop Action Class @@ -455,13 +452,13 @@ public abstract class DesktopAction { } /** - * Return the check in/out service + * Return the service registry * - * @return CheckOutInService + * @return ServiceRegistry */ - public final CheckOutCheckInService getCheckInOutService() + public final ServiceRegistry getServiceRegistry() { - return m_contentDriver.getCheckInOutService(); + return m_contentDriver.getServiceRegistry(); } /** diff --git a/source/java/org/alfresco/filesys/smb/server/repo/DesktopResponse.java b/source/java/org/alfresco/filesys/smb/server/repo/DesktopResponse.java index cf69283a7c..11ae1b9c94 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/DesktopResponse.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/DesktopResponse.java @@ -19,6 +19,8 @@ package org.alfresco.filesys.smb.server.repo; import java.util.ArrayList; import java.util.List; +import org.mozilla.javascript.ScriptableObject; + /** * Desktop Response Class * @@ -26,8 +28,12 @@ import java.util.List; * * @author gkspencer */ -public class DesktopResponse { +public class DesktopResponse extends ScriptableObject { + // Version id + + private static final long serialVersionUID = 6421278986221629296L; + // Desktop action status and optional status message private int m_status; @@ -58,7 +64,29 @@ public class DesktopResponse { m_status = sts; m_statusMsg = msg; } + + /** + * Javascript constructor + * + * @param sts int + * @param msg String + */ + public void jsConstructor(int sts, String msg) + { + m_status = sts; + m_statusMsg = msg; + } + /** + * Return the class name + * + * @return String + */ + @Override + public String getClassName() { + return "DesktopResponse"; + } + /** * Return the status code * @@ -69,6 +97,16 @@ public class DesktopResponse { return m_status; } + /** + * Return the status property + * + * @return int + */ + public int jsGet_status() + { + return m_status; + } + /** * Determine if there is an optional status message * @@ -89,6 +127,16 @@ public class DesktopResponse { return m_statusMsg; } + /** + * Return the status message property + * + * @return String + */ + public String jsGet_message() + { + return m_statusMsg != null ? m_statusMsg : ""; + } + /** * Determine if there are optional response values * @@ -144,6 +192,26 @@ public class DesktopResponse { m_statusMsg = msg; } + /** + * Set the status property + * + * @param sts int + */ + public void jsSet_status(int sts) + { + m_status = sts; + } + + /** + * Set the status message property + * + * @param msg String + */ + public void jsSet_message(String msg) + { + m_statusMsg = msg; + } + /** * Return the desktop response as a string * diff --git a/source/java/org/alfresco/filesys/smb/server/repo/desk/CheckInOutDesktopAction.java b/source/java/org/alfresco/filesys/smb/server/repo/desk/CheckInOutDesktopAction.java index fe39a6b277..45f535f229 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/desk/CheckInOutDesktopAction.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/desk/CheckInOutDesktopAction.java @@ -16,6 +16,10 @@ */ package org.alfresco.filesys.smb.server.repo.desk; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + import org.alfresco.filesys.server.filesys.FileName; import org.alfresco.filesys.server.filesys.NotifyChange; import org.alfresco.filesys.smb.server.repo.DesktopAction; @@ -23,6 +27,7 @@ import org.alfresco.filesys.smb.server.repo.DesktopParams; import org.alfresco.filesys.smb.server.repo.DesktopResponse; import org.alfresco.filesys.smb.server.repo.DesktopTarget; import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.coci.CheckOutCheckInService; import org.alfresco.service.cmr.repository.NodeRef; /** @@ -34,6 +39,10 @@ import org.alfresco.service.cmr.repository.NodeRef; */ public class CheckInOutDesktopAction extends DesktopAction { + // Check in/out service + + private CheckOutCheckInService m_checkInOutService; + /** * Class constructor */ @@ -42,6 +51,11 @@ public class CheckInOutDesktopAction extends DesktopAction { super( DesktopAction.AttrAnyFiles, DesktopAction.PreConfirmAction + DesktopAction.PreCopyToTarget + DesktopAction.PreLocalToWorkingCopy); } + /** + * Return the confirmation string to be displayed by the client + * + * @return String + */ @Override public String getConfirmationString() { return "Run check in/out action"; @@ -56,7 +70,7 @@ public class CheckInOutDesktopAction extends DesktopAction { @Override public DesktopResponse runAction(DesktopParams params) { - // check if there are any files/folders to process + // Check if there are any files/folders to process if ( params.numberOfTargetNodes() == 0) return new DesktopResponse(StsSuccess); @@ -81,9 +95,10 @@ public class CheckInOutDesktopAction extends DesktopAction { { try { - // Check in the file + // Check in the file, pass an empty version properties so that veriosnable nodes create a new version - getCheckInOutService().checkin( target.getNode(), null, null, false); + Map versionProperties = new HashMap(); + getCheckInOutService().checkin( target.getNode(), versionProperties, null, false); // Check if there are any file/directory change notify requests active @@ -183,4 +198,23 @@ public class CheckInOutDesktopAction extends DesktopAction { return response; } + + /** + * Get the check in/out service + * + * @return CheckOutCheckInService + */ + protected final CheckOutCheckInService getCheckInOutService() + { + // Check if the service has been cached + + if ( m_checkInOutService == null) + { + m_checkInOutService = getServiceRegistry().getCheckOutCheckInService(); + } + + // Return the check in/out service + + return m_checkInOutService; + } } diff --git a/source/java/org/alfresco/filesys/smb/server/repo/desk/JavaScriptDesktopAction.java b/source/java/org/alfresco/filesys/smb/server/repo/desk/JavaScriptDesktopAction.java new file mode 100644 index 0000000000..303ff36272 --- /dev/null +++ b/source/java/org/alfresco/filesys/smb/server/repo/desk/JavaScriptDesktopAction.java @@ -0,0 +1,448 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ + +package org.alfresco.filesys.smb.server.repo.desk; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.HashMap; +import java.util.Map; +import java.util.StringTokenizer; + +import org.alfresco.config.ConfigElement; +import org.alfresco.filesys.server.filesys.DiskSharedDevice; +import org.alfresco.filesys.smb.server.repo.DesktopAction; +import org.alfresco.filesys.smb.server.repo.DesktopActionException; +import org.alfresco.filesys.smb.server.repo.DesktopParams; +import org.alfresco.filesys.smb.server.repo.DesktopResponse; +import org.alfresco.service.cmr.repository.ScriptException; +import org.alfresco.service.cmr.repository.ScriptService; + +/** + * Javascript Desktop Action Class + * + *

Run a server-side script against the target node(s). + * + * @author gkspencer + */ +public class JavaScriptDesktopAction extends DesktopAction { + + // Script service + + private ScriptService m_scriptService; + + // Script name + + private String m_scriptName; + + // Script file details + + private String m_scriptPath; + private long m_lastModified; + + // Script string + + private String m_script; + + /** + * Class constructor + */ + public JavaScriptDesktopAction() + { + super( DesktopAction.AttrAnyFiles, DesktopAction.PreConfirmAction + DesktopAction.PreCopyToTarget); + } + + /** + * Return the confirmation string to be displayed by the client + * + * @return String + */ + @Override + public String getConfirmationString() + { + return "Run Javascript action"; + } + + /** + * Initialize the action + * + * @param global ConfigElement + * @param config ConfigElement + * @param fileSys DiskSharedDevice + * @exception DesktopActionException + */ + @Override + public void initializeAction(ConfigElement global, ConfigElement config, DiskSharedDevice fileSys) + throws DesktopActionException + { + + // Perform standard initialization + + super.initializeAction(global, config, fileSys); + + // Get the script file name and check that it exists + + ConfigElement elem = config.getChild("script"); + if ( elem != null && elem.getValue().length() > 0) + { + // Set the script name + + setScriptName(elem.getValue()); + + // Check if the script exists on the classpath + + URL scriptURL = this.getClass().getClassLoader().getResource(getScriptName()); + if ( scriptURL == null) + throw new DesktopActionException("Failed to find script on classpath, " + getScriptName()); + + // Decode the URL path, it might contain escaped characters + + String scriptURLPath = null; + try + { + scriptURLPath = URLDecoder.decode( scriptURL.getFile(), "UTF-8"); + } + catch ( UnsupportedEncodingException ex) + { + throw new DesktopActionException("Failed to decode script path, " + ex.getMessage()); + } + + // Check that the script file exists + + File scriptFile = new File(scriptURLPath); + if ( scriptFile.exists() == false) + throw new DesktopActionException("Script file not found, " + elem.getValue()); + + m_scriptPath = scriptFile.getAbsolutePath(); + m_lastModified =scriptFile.lastModified(); + + // Load the script + + try + { + loadScript( scriptFile); + } + catch ( IOException ex) + { + throw new DesktopActionException( "Failed to load script, " + ex.getMessage()); + } + } + else + throw new DesktopActionException("Script name not specified"); + + // check if the desktop action attributes have been specified + + elem = config.getChild("attributes"); + if ( elem != null) + { + // Check if the attribute string is empty + + if ( elem.getValue().length() == 0) + throw new DesktopActionException("Empty desktop action attributes"); + + // Parse the attribute string + + int attr = 0; + StringTokenizer tokens = new StringTokenizer( elem.getValue(), ","); + + while ( tokens.hasMoreTokens()) + { + // Get the current attribute token and validate + + String token = tokens.nextToken().trim(); + + if ( token.equalsIgnoreCase( "targetFiles")) + attr |= AttrTargetFiles; + else if ( token.equalsIgnoreCase( "targetFolders")) + attr |= AttrTargetFolders; + else if ( token.equalsIgnoreCase( "clientFiles")) + attr |= AttrClientFiles; + else if ( token.equalsIgnoreCase( "clientFolders")) + attr |= AttrClientFolders; + else if ( token.equalsIgnoreCase( "alfrescoFiles")) + attr |= AttrAlfrescoFiles; + else if ( token.equalsIgnoreCase( "alfrescoFolders")) + attr |= AttrAlfrescoFolders; + else if ( token.equalsIgnoreCase( "multiplePaths")) + attr |= AttrMultiplePaths; + else if ( token.equalsIgnoreCase( "allowNoParams")) + attr |= AttrAllowNoParams; + else if ( token.equalsIgnoreCase( "anyFiles")) + attr |= AttrAnyFiles; + else if ( token.equalsIgnoreCase( "anyFolders")) + attr |= AttrAnyFolders; + else if ( token.equalsIgnoreCase( "anyFilesFolders")) + attr |= AttrAnyFilesFolders; + else + throw new DesktopActionException("Unknown attribute, " + token); + } + + // Set the action attributes + + setAttributes( attr); + } + + // Check if the desktop action pre-processing options have been specified + + elem = config.getChild("preprocess"); + if ( elem != null) + { + // Check if the pre-process string is empty + + if ( elem.getValue().length() == 0) + throw new DesktopActionException("Empty desktop action pre-processing flags"); + + // Parse the pre-process string + + int pre = 0; + StringTokenizer tokens = new StringTokenizer( elem.getValue(), ","); + + while ( tokens.hasMoreTokens()) + { + // Get the current pre-process token and validate + + String token = tokens.nextToken().trim(); + + if ( token.equalsIgnoreCase( "copyToTarget")) + pre |= PreCopyToTarget; + else if ( token.equalsIgnoreCase( "confirm")) + pre |= PreConfirmAction; + else if ( token.equalsIgnoreCase( "localToWorkingCopy")) + pre |= PreLocalToWorkingCopy; + else + throw new DesktopActionException("Unknown pre-processing flag, " + token); + } + + // Set the action pre-processing flags + + setPreProcessActions( pre); + } + } + + /** + * Run the desktop action + * + * @param params DesktopParams + * @return DesktopResponse + */ + @Override + public DesktopResponse runAction(DesktopParams params) + throws DesktopActionException + { + // Check if the script file has been changed + + DesktopResponse response = new DesktopResponse(StsSuccess); + + File scriptFile = new File(m_scriptPath); + if ( scriptFile.lastModified() != m_lastModified) + { + // Reload the script + + m_lastModified = scriptFile.lastModified(); + + try + { + loadScript( scriptFile); + } + catch ( IOException ex) + { + response.setStatus(StsError, "Failed to reload script file, " + getScriptName()); + return response; + } + } + + // Start a transaction + + params.getSession().beginTransaction(getTransactionService(), false); + + // Access the script service + + if ( getScriptService() != null) + { + // Create the objects to be passed to the script + + Map model = new HashMap(); + model.put("deskParams", params); + model.put("out", System.out); + + // Start a transaction + + params.getSession().beginTransaction(getTransactionService(), false); + + // Run the script + + Object result = null; + + try + { + // Run the script + + result = getScriptService().executeScriptString( getScript(), model); + + // Check the result + + if ( result != null) + { + // Check for a full response object + + if ( result instanceof DesktopResponse) + { + response = (DesktopResponse) result; + } + + // Status code only response + + else if ( result instanceof Double) + { + Double jsSts = (Double) result; + response.setStatus( jsSts.intValue(), ""); + } + + // Encoded response in the format ',' + + else if ( result instanceof String) + { + String responseMsg = (String) result; + + // Parse the status message + + StringTokenizer token = new StringTokenizer( responseMsg, ","); + String stsToken = token.nextToken(); + String msgToken = token.nextToken(); + + int sts = -1; + try + { + sts = Integer.parseInt( stsToken); + } + catch ( NumberFormatException ex) + { + response.setStatus( StsError, "Bad response from script"); + } + + // Set the response + + response.setStatus( sts, msgToken != null ? msgToken : ""); + } + } + } + catch (ScriptException ex) + { + // Set the error response for the client + + response.setStatus( StsError, ex.getMessage()); + } + } + else + { + // Return an error response, script service not available + + response.setStatus( StsError, "Script service not available"); + } + + // Return the response + + return response; + } + + /** + * Get the script service + * + * @return ScriptService + */ + protected final ScriptService getScriptService() + { + // Check if the script service has been initialized + + if ( m_scriptService == null) + { + // Get the script service + + m_scriptService = getServiceRegistry().getScriptService(); + } + + // Return the script service + + return m_scriptService; + } + + /** + * Get the script name + * + * @return String + */ + public final String getScriptName() + { + return m_scriptName; + } + + /** + * Return the script data + * + * @return String + */ + public final String getScript() + { + return m_script; + } + + /** + * Set the script name + * + * @param name String + */ + protected final void setScriptName(String name) + { + m_scriptName = name; + } + + /** + * Load, or reload, the script + * + * @param scriptFile File + */ + private final void loadScript(File scriptFile) + throws IOException + { + // Open the script file + + BufferedReader scriptIn = new BufferedReader(new FileReader( scriptFile)); + StringBuilder scriptStr = new StringBuilder((int) scriptFile.length() + 256); + + String inRec = scriptIn.readLine(); + + while ( inRec != null) + { + scriptStr.append( inRec); + scriptStr.append( "\n"); + inRec = scriptIn.readLine(); + } + + // Close the script file + + scriptIn.close(); + + // Update the script string + + m_script = scriptStr.toString(); + } +} diff --git a/source/java/org/alfresco/filesys/smb/server/repo/pseudo/ContentPseudoFileImpl.java b/source/java/org/alfresco/filesys/smb/server/repo/pseudo/ContentPseudoFileImpl.java index 24f8e08896..ab38534a88 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/pseudo/ContentPseudoFileImpl.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/pseudo/ContentPseudoFileImpl.java @@ -68,6 +68,27 @@ public class ContentPseudoFileImpl implements PseudoFileInterface if ( pfile != null) isPseudo = true; } + else + { + // Check if the file name matches a pseudo-file name in the desktop actions list + + if ( ctx.hasDesktopActions()) + { + DesktopActionTable actions = ctx.getDesktopActions(); + if ( actions.getActionViaPseudoName( paths[1]) != null) + isPseudo = true; + } + + // Check if the URL file is enabled + + if ( isPseudo == false && ctx.hasURLFile()) + { + // Check if it is the URL file name + + if ( ctx.getURLFileName().equals( paths[1])) + isPseudo = true; + } + } // Return the pseudo file status diff --git a/source/java/org/alfresco/filesys/util/DataBuffer.java b/source/java/org/alfresco/filesys/util/DataBuffer.java index 8f1b8b5963..d016ea4830 100644 --- a/source/java/org/alfresco/filesys/util/DataBuffer.java +++ b/source/java/org/alfresco/filesys/util/DataBuffer.java @@ -570,7 +570,9 @@ public class DataBuffer // Check if there is enough space in the buffer int bytLen = str.length() * 2; - if (m_data.length - m_pos < bytLen) + if ( nulTerm) + bytLen += 2; + if ((m_data.length - m_pos) < (bytLen + 4)) extendBuffer(bytLen + 4); // Word align the buffer position, pack the Unicode string diff --git a/source/java/org/alfresco/jcr/repository/RepositoryImpl.java b/source/java/org/alfresco/jcr/repository/RepositoryImpl.java index 5b09ad4a9b..9777322502 100644 --- a/source/java/org/alfresco/jcr/repository/RepositoryImpl.java +++ b/source/java/org/alfresco/jcr/repository/RepositoryImpl.java @@ -201,7 +201,6 @@ public class RepositoryImpl implements Repository { // construct the session SessionImpl sessionImpl = new SessionImpl(this); - registerSession(sessionImpl); // authenticate user AuthenticationService authenticationService = getServiceRegistry().getAuthenticationService(); @@ -211,7 +210,6 @@ public class RepositoryImpl implements Repository } catch(AuthenticationException e) { - deregisterSession(); throw new LoginException("Alfresco Repository failed to authenticate credentials", e); } @@ -222,11 +220,11 @@ public class RepositoryImpl implements Repository // session is now ready Session session = sessionImpl.getProxy(); + registerSession(sessionImpl); return session; } catch(AlfrescoRuntimeException e) { - deregisterSession(); throw new RepositoryException(e); } } diff --git a/source/java/org/alfresco/model/ContentModel.java b/source/java/org/alfresco/model/ContentModel.java index c3cd5e5397..7873190322 100644 --- a/source/java/org/alfresco/model/ContentModel.java +++ b/source/java/org/alfresco/model/ContentModel.java @@ -58,16 +58,16 @@ public interface ContentModel // referenceable aspect constants static final QName TYPE_REFERENCE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "reference"); static final QName PROP_REFERENCE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "reference"); - + // container type constants static final QName TYPE_CONTAINER = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "container"); /** child association type supported by {@link #TYPE_CONTAINER} */ static final QName ASSOC_CHILDREN =QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "children"); - + // roots static final QName ASPECT_ROOT = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "aspect_root"); static final QName TYPE_STOREROOT = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "store_root"); - + // descriptor properties static final QName PROP_SYS_VERSION_MAJOR = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionMajor"); static final QName PROP_SYS_VERSION_MINOR = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionMinor"); @@ -76,7 +76,7 @@ public interface ContentModel static final QName PROP_SYS_VERSION_BUILD = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionBuild"); static final QName PROP_SYS_VERSION_SCHEMA = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionSchema"); static final QName PROP_SYS_VERSION_EDITION = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionEdition"); - + // // Content Model Definitions @@ -89,7 +89,7 @@ public interface ContentModel // copy aspect constants static final QName ASPECT_COPIEDFROM = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "copiedfrom"); static final QName PROP_COPY_REFERENCE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "source"); - + // working copy aspect contants static final QName ASPECT_WORKING_COPY = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "workingcopy"); static final QName PROP_WORKING_COPY_OWNER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "workingCopyOwner"); @@ -124,19 +124,19 @@ public interface ContentModel static final QName PROP_CATEGORIES = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "categories"); static final QName ASSOC_CATEGORIES = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "categories"); static final QName ASSOC_SUBCATEGORIES = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "subcategories"); - + // lock aspect public final static QName ASPECT_LOCKABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "lockable"); public final static QName PROP_LOCK_OWNER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "lockOwner"); public final static QName PROP_LOCK_TYPE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "lockType"); public final static QName PROP_EXPIRY_DATE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "expiryDate"); - + // version aspect static final QName ASPECT_VERSIONABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "versionable"); static final QName PROP_VERSION_LABEL = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "versionLabel"); static final QName PROP_INITIAL_VERSION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "initialVersion"); static final QName PROP_AUTO_VERSION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "autoVersion"); - + // folders static final QName TYPE_SYSTEM_FOLDER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "systemfolder"); static final QName TYPE_FOLDER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "folder"); @@ -151,6 +151,10 @@ public interface ContentModel static final QName PROP_LASTNAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "lastName"); static final QName PROP_EMAIL = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "email"); static final QName PROP_ORGID = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "organizationId"); + static final QName PROP_HOME_FOLDER_PROVIDER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "homeFolderProvider"); + static final QName PROP_DEFAULT_HOME_FOLDER_PATH = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "defaultHomeFolderPath"); + + // Ownable aspect static final QName ASPECT_OWNABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "ownable"); @@ -190,7 +194,7 @@ public interface ContentModel public static final QName PROP_HITS = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "hits"); public static final QName PROP_COUNTER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "counter"); - // referencesnode aspect + // References Node Aspect. public static final QName ASPECT_REFERENCES_NODE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "referencesnode"); public static final QName PROP_NODE_REF = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "noderef"); @@ -206,15 +210,15 @@ public interface ContentModel static final QName PROP_REJECT_STEP = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "rejectStep"); static final QName PROP_REJECT_FOLDER = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "rejectFolder"); static final QName PROP_REJECT_MOVE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "rejectMove"); - + // ui facets aspect static final QName ASPECT_UIFACETS = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "uifacets"); static final QName PROP_ICON = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "icon"); - + // inlineeditable aspect static final QName ASPECT_INLINEEDITABLE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "inlineeditable"); static final QName PROP_EDITINLINE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "editInline"); - + // configurable aspect static final QName ASPECT_CONFIGURABLE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "configurable"); static final QName TYPE_CONFIGURATIONS = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "configurations"); @@ -254,7 +258,7 @@ public interface ContentModel static final QName PROP_CREDENTIALS_EXPIRY_DATE = QName.createQName(USER_MODEL_URI, "credentialsExpiryDate"); static final QName PROP_ACCOUNT_LOCKED = QName.createQName(USER_MODEL_URI, "accountLocked"); static final QName PROP_SALT = QName.createQName(USER_MODEL_URI, "salt"); - + static final QName TYPE_AUTHORITY = QName.createQName(USER_MODEL_URI, "authority"); static final QName TYPE_AUTHORITY_CONTAINER = QName.createQName(USER_MODEL_URI, "authorityContainer"); diff --git a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java index c256f07916..61a592c240 100644 --- a/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/MailActionExecuter.java @@ -109,6 +109,11 @@ public class MailActionExecuter extends ActionExecuterAbstractBase */ private ServiceRegistry serviceRegistry; + /** + * Mail header encoding scheme + */ + private String headerEncoding = null; + /** * @param javaMailSender the java mail sender */ @@ -164,6 +169,14 @@ public class MailActionExecuter extends ActionExecuterAbstractBase { this.nodeService = nodeService; } + + /** + * @param headerEncoding The mail header encoding to set. + */ + public void setHeaderEncoding(String headerEncoding) + { + this.headerEncoding = headerEncoding; + } /** * Execute the rule action @@ -180,6 +193,12 @@ public class MailActionExecuter extends ActionExecuterAbstractBase { MimeMessageHelper message = new MimeMessageHelper(mimeMessage); + // set header encoding if one has been supplied + if (headerEncoding != null && headerEncoding.length() != 0) + { + mimeMessage.setHeader("Content-Transfer-Encoding", headerEncoding); + } + // set recipient String to = (String)ruleAction.getParameterValue(PARAM_TO); if (to != null && to.length() != 0) diff --git a/source/java/org/alfresco/repo/action/executer/ScriptActionExecuter.java b/source/java/org/alfresco/repo/action/executer/ScriptActionExecuter.java index 2a49156dee..1505941515 100644 --- a/source/java/org/alfresco/repo/action/executer/ScriptActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/ScriptActionExecuter.java @@ -84,6 +84,10 @@ public class ScriptActionExecuter extends ActionExecuterAbstractBase { NodeRef scriptRef = (NodeRef)action.getParameterValue(PARAM_SCRIPTREF); NodeRef spaceRef = this.serviceRegistry.getRuleService().getOwningNodeRef(action); + if (spaceRef == null) + { + spaceRef = nodeService.getPrimaryParent(actionedUponNodeRef).getParentRef(); + } if (nodeService.exists(scriptRef)) { diff --git a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java index 89c040ca15..28fafbcc91 100644 --- a/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/TransformActionExecuter.java @@ -240,7 +240,10 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase contentWriter.setMimetype(mimeType); // new mimetype contentWriter.setEncoding(contentReader.getEncoding()); // original encoding - // Try and transform the content + // Try and transform the content - failures are caught and allowed to fail silently. + // This is unique to this action, and is essentially a broken pattern. + // Clients should rather get the exception and then decide to replay with rules/actions turned off or not. + // TODO: Check failure patterns for actions. try { doTransform(ruleAction, contentReader, contentWriter); @@ -258,8 +261,16 @@ public class TransformActionExecuter extends ActionExecuterAbstractBase } } + /** + * Executed in a new transaction so that failures don't cause the entire transaction to rollback. + */ protected void doTransform(Action ruleAction, ContentReader contentReader, ContentWriter contentWriter) { + // try to pre-empt the lack of a transformer + if (!this.contentService.isTransformable(contentReader, contentWriter)) + { + throw new NoTransformerException(contentReader.getMimetype(), contentWriter.getMimetype()); + } this.contentService.transform(contentReader, contentWriter); } diff --git a/source/java/org/alfresco/repo/audit/AuditComponentImpl.java b/source/java/org/alfresco/repo/audit/AuditComponentImpl.java index 6ee47e0c6d..240bebf881 100644 --- a/source/java/org/alfresco/repo/audit/AuditComponentImpl.java +++ b/source/java/org/alfresco/repo/audit/AuditComponentImpl.java @@ -23,6 +23,7 @@ import java.net.UnknownHostException; import java.util.Date; import java.util.List; +import org.alfresco.repo.audit.model.TrueFalseUnset; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.service.Auditable; @@ -123,13 +124,26 @@ public class AuditComponentImpl implements AuditComponent { if ((auditFlag.get() == null) || (!auditFlag.get().booleanValue())) { + boolean auditInternal = (auditModel.getAuditInternalServiceMethods(mi) == TrueFalseUnset.TRUE); try { - auditFlag.set(Boolean.TRUE); - Method method = mi.getMethod(); String methodName = method.getName(); String serviceName = publicServiceIdentifier.getPublicServiceName(mi); + + if (!auditInternal) + { + auditFlag.set(Boolean.TRUE); + } + else + { + if (s_logger.isDebugEnabled()) + { + s_logger.debug("Auditing internal service use for - " + serviceName + "." + methodName); + } + } + + if (method.isAnnotationPresent(Auditable.class)) { @@ -170,7 +184,10 @@ public class AuditComponentImpl implements AuditComponent } finally { - auditFlag.set(Boolean.FALSE); + if (!auditInternal) + { + auditFlag.set(Boolean.FALSE); + } } } else @@ -272,7 +289,7 @@ public class AuditComponentImpl implements AuditComponent } else if (returnObject instanceof StoreRef) { - auditInfo.setKeyStore((StoreRef)returnObject); + auditInfo.setKeyStore((StoreRef) returnObject); } } } diff --git a/source/java/org/alfresco/repo/audit/AuditableAspect.java b/source/java/org/alfresco/repo/audit/AuditableAspect.java index 19b63ab727..88effcedca 100644 --- a/source/java/org/alfresco/repo/audit/AuditableAspect.java +++ b/source/java/org/alfresco/repo/audit/AuditableAspect.java @@ -35,6 +35,7 @@ import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import org.alfresco.util.PropertyMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -126,7 +127,7 @@ public class AuditableAspect public void onAddAudit(NodeRef nodeRef, QName aspect) { // Get the current properties - Map properties = this.nodeService.getProperties(nodeRef); + PropertyMap properties = new PropertyMap(); // Set created / updated date Date now = new Date(System.currentTimeMillis()); @@ -167,7 +168,7 @@ public class AuditableAspect // Get the current properties try { - Map properties = this.nodeService.getProperties(nodeRef); + PropertyMap properties = new PropertyMap(); // Set updated date Date now = new Date(System.currentTimeMillis()); @@ -249,7 +250,11 @@ public class AuditableAspect */ public Boolean doWork() throws Exception { - nodeService.setProperties(nodeRef, properties); + for (QName propertyQName : properties.keySet()) + { + Serializable property = properties.get(propertyQName); + nodeService.setProperty(nodeRef, propertyQName, property); + } return Boolean.TRUE; } } diff --git a/source/java/org/alfresco/repo/audit/MethodAuditModel.java b/source/java/org/alfresco/repo/audit/MethodAuditModel.java index 37b1200173..62791ca5e6 100644 --- a/source/java/org/alfresco/repo/audit/MethodAuditModel.java +++ b/source/java/org/alfresco/repo/audit/MethodAuditModel.java @@ -16,6 +16,7 @@ */ package org.alfresco.repo.audit; +import org.alfresco.repo.audit.model.TrueFalseUnset; import org.aopalliance.intercept.MethodInvocation; public interface MethodAuditModel @@ -54,4 +55,11 @@ public interface MethodAuditModel * @return */ public RecordOptions getAuditRecordOptions(MethodInvocation mi); + + /** + * Should internal service class be logged. + * + * @return + */ + public TrueFalseUnset getAuditInternalServiceMethods(MethodInvocation mi); } diff --git a/source/java/org/alfresco/repo/audit/hibernate/Audit.hbm.xml b/source/java/org/alfresco/repo/audit/hibernate/Audit.hbm.xml index 9e40c7a787..843a9637b7 100644 --- a/source/java/org/alfresco/repo/audit/hibernate/Audit.hbm.xml +++ b/source/java/org/alfresco/repo/audit/hibernate/Audit.hbm.xml @@ -42,10 +42,10 @@ - + - + @@ -67,7 +67,7 @@ - + @@ -135,24 +135,34 @@ select - audit_store + audit_store_byid + from + org.alfresco.repo.audit.hibernate.AuditSourceImpl as audit_store_byid + where + audit_store_byid = + (select max(audit_store.id) from org.alfresco.repo.audit.hibernate.AuditSourceImpl as audit_store where audit_store.application = :application and audit_store.service is null and - audit_store.method is null + audit_store.method is null) select - audit_store + audit_store_byid + from + org.alfresco.repo.audit.hibernate.AuditSourceImpl as audit_store_byid + where + audit_store_byid = + (select max(audit_store.id) from org.alfresco.repo.audit.hibernate.AuditSourceImpl as audit_store where audit_store.application = :application and audit_store.service = :service and - audit_store.method = :method + audit_store.method = :method) diff --git a/source/java/org/alfresco/repo/audit/model/AbstractAuditEntry.java b/source/java/org/alfresco/repo/audit/model/AbstractAuditEntry.java index c99fd0bb7c..d747a482d3 100644 --- a/source/java/org/alfresco/repo/audit/model/AbstractAuditEntry.java +++ b/source/java/org/alfresco/repo/audit/model/AbstractAuditEntry.java @@ -136,6 +136,49 @@ public abstract class AbstractAuditEntry { return recordOptions; } + + + protected TrueFalseUnset getEffectiveAuditInternal() + { + TrueFalseUnset auditInternal; + if (checkEnabled() == TrueFalseUnset.TRUE) + { + auditInternal = getAuditInternalOrParentAuditInternal(); + } + else + { + auditInternal = TrueFalseUnset.FALSE; + } + if(s_logger.isDebugEnabled()) + { + s_logger.debug("... Effective audit internal is = "+auditInternal); + } + return auditInternal; + } + + private TrueFalseUnset getAuditInternalOrParentAuditInternal() + { + TrueFalseUnset auditInternal = getAuditInternal(); + if(s_logger.isDebugEnabled()) + { + s_logger.debug("... ... audit internal is = "+auditInternal); + } + if (auditInternal == TrueFalseUnset.UNSET) + { + if (getParent() == null) + { + return TrueFalseUnset.UNSET; + } + else + { + return getParent().getAuditInternalOrParentAuditInternal(); + } + } + else + { + return auditInternal; + } + } protected AuditMode getEffectiveAuditMode() { diff --git a/source/java/org/alfresco/repo/audit/model/AuditEntry.java b/source/java/org/alfresco/repo/audit/model/AuditEntry.java index 68678d200c..613da6578d 100644 --- a/source/java/org/alfresco/repo/audit/model/AuditEntry.java +++ b/source/java/org/alfresco/repo/audit/model/AuditEntry.java @@ -217,4 +217,23 @@ public class AuditEntry extends AbstractAuditEntry implements InitializingBean, throw new UnsupportedOperationException(); } + public TrueFalseUnset getAuditInternalServiceMethods( MethodInvocation mi) + { + String serviceName = getPublicServiceIdentifier().getPublicServiceName(mi); + ServiceAuditEntry service = services.get(serviceName); + if(service != null) + { + return service.getAuditInternalServiceMethods( mi); + } + else + { + if(s_logger.isDebugEnabled()) + { + s_logger.debug("No specific audit entry for service "+serviceName); + } + return getEffectiveAuditInternal(); + + } + } + } diff --git a/source/java/org/alfresco/repo/audit/model/MethodAuditEntry.java b/source/java/org/alfresco/repo/audit/model/MethodAuditEntry.java index a59d6b7a72..c38d36e5db 100644 --- a/source/java/org/alfresco/repo/audit/model/MethodAuditEntry.java +++ b/source/java/org/alfresco/repo/audit/model/MethodAuditEntry.java @@ -56,4 +56,13 @@ public class MethodAuditEntry extends AbstractNamedAuditEntry implements MethodA throw new UnsupportedOperationException(); } + public TrueFalseUnset getAuditInternalServiceMethods(MethodInvocation mi) + { + if(s_logger.isDebugEnabled()) + { + s_logger.debug("Evaluating if method is internally audited ..."+((ServiceAuditEntry)getParent()).getName()+"."+getName()); + } + return getEffectiveAuditInternal(); + } + } diff --git a/source/java/org/alfresco/repo/audit/model/ServiceAuditEntry.java b/source/java/org/alfresco/repo/audit/model/ServiceAuditEntry.java index 764f004044..e4458bb5ff 100644 --- a/source/java/org/alfresco/repo/audit/model/ServiceAuditEntry.java +++ b/source/java/org/alfresco/repo/audit/model/ServiceAuditEntry.java @@ -97,4 +97,22 @@ public class ServiceAuditEntry extends AbstractNamedAuditEntry implements Method throw new UnsupportedOperationException(); } + public TrueFalseUnset getAuditInternalServiceMethods(MethodInvocation mi) + { + String methodName = mi.getMethod().getName(); + MethodAuditEntry method = methods.get(methodName); + if (method != null) + { + return method.getAuditInternalServiceMethods(mi); + } + else + { + if(s_logger.isDebugEnabled()) + { + s_logger.debug("Evaluating if service is internally audited (no specific setting) for "+getName()+"."+methodName); + } + return getEffectiveAuditInternal(); + } + } + } diff --git a/source/java/org/alfresco/repo/cache/InternalEhCacheManagerFactoryBean.java b/source/java/org/alfresco/repo/cache/InternalEhCacheManagerFactoryBean.java index 3830803457..cf87c94d1f 100644 --- a/source/java/org/alfresco/repo/cache/InternalEhCacheManagerFactoryBean.java +++ b/source/java/org/alfresco/repo/cache/InternalEhCacheManagerFactoryBean.java @@ -44,7 +44,7 @@ import org.springframework.util.ResourceUtils; * For Alfresco purposes, there are two files that are looked for: *

    *
  • classpath:alfresco/extension/ehcache-custom.xml, which will take precedence
  • - *
  • classpath:alfresco/ehcache.xml, which is the default shipped with Alfresco
  • + *
  • classpath:alfresco/ehcache-default.xml, which is the default shipped with Alfresco
  • *
*

* The EHCache static singleton instance is used but ensuring that all access to the diff --git a/source/java/org/alfresco/repo/content/AbstractContentStore.java b/source/java/org/alfresco/repo/content/AbstractContentStore.java index 76ff24e12b..db7336a57c 100644 --- a/source/java/org/alfresco/repo/content/AbstractContentStore.java +++ b/source/java/org/alfresco/repo/content/AbstractContentStore.java @@ -109,7 +109,7 @@ public abstract class AbstractContentStore implements ContentStore // extract the relative part of the URL String path = contentUrl.substring(index); // more extensive checks can be added in, but it seems overkill - if (path.length() < 10) + if (path.length() < 8) { throw new AlfrescoRuntimeException( "The content URL is invalid: \n" + diff --git a/source/java/org/alfresco/repo/content/MimetypeMap.java b/source/java/org/alfresco/repo/content/MimetypeMap.java index 272c1cb89d..473dea5253 100644 --- a/source/java/org/alfresco/repo/content/MimetypeMap.java +++ b/source/java/org/alfresco/repo/content/MimetypeMap.java @@ -56,6 +56,7 @@ public class MimetypeMap implements MimetypeService public static final String MIMETYPE_IMAGE_GIF = "image/gif"; public static final String MIMETYPE_IMAGE_JPEG = "image/jpeg"; public static final String MIMETYPE_IMAGE_RGB = "image/x-rgb"; + public static final String MIMETYPE_IMAGE_SVG = "image/svg"; public static final String MIMETYPE_JAVASCRIPT = "application/x-javascript"; public static final String MIMETYPE_ZIP = "application/zip"; // Open Document diff --git a/source/java/org/alfresco/repo/content/RoutingContentService.java b/source/java/org/alfresco/repo/content/RoutingContentService.java index 61f9eefd2c..3821025eca 100644 --- a/source/java/org/alfresco/repo/content/RoutingContentService.java +++ b/source/java/org/alfresco/repo/content/RoutingContentService.java @@ -323,7 +323,6 @@ public class RoutingContentService implements ContentService public ContentWriter getWriter(NodeRef nodeRef, QName propertyQName, boolean update) { - // check for an existing URL - the get of the reader will perform type checking ContentReader existingContentReader = getReader(nodeRef, propertyQName, false); diff --git a/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java b/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java index 91ec5e9e57..33ebf84479 100644 --- a/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java +++ b/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java @@ -1,262 +1,249 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.content.cleanup; - -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.repo.avm.AVMNodeDAO; -import org.alfresco.repo.content.ContentStore; -import org.alfresco.repo.node.db.NodeDaoService; -import org.alfresco.repo.transaction.TransactionUtil; -import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.repository.ContentData; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.transaction.TransactionService; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This component is responsible for finding orphaned content in a given - * content store or stores. Deletion handlers can be provided to ensure - * that the content is moved to another location prior to being removed - * from the store(s) being cleaned. - * - * @author Derek Hulley - */ -public class ContentStoreCleaner -{ - private static Log logger = LogFactory.getLog(ContentStoreCleaner.class); - - private DictionaryService dictionaryService; - private NodeDaoService nodeDaoService; - private TransactionService transactionService; - private AVMNodeDAO avmNodeDAO; - private List stores; - private List listeners; - private int protectDays; - - public ContentStoreCleaner() - { - this.stores = new ArrayList(0); - this.listeners = new ArrayList(0); - this.protectDays = 7; - } - - /** - * @param dictionaryService used to determine which properties are content properties - */ - public void setDictionaryService(DictionaryService dictionaryService) - { - this.dictionaryService = dictionaryService; - } - - /** - * @param nodeDaoService used to get the property values - */ - public void setNodeDaoService(NodeDaoService nodeDaoService) - { - this.nodeDaoService = nodeDaoService; - } - - /** - * Setter for Spring. - * @param avmNodeDAO The AVM Node DAO to get urls with. - */ - public void setAvmNodeDAO(AVMNodeDAO avmNodeDAO) - { - this.avmNodeDAO = avmNodeDAO; - } - - /** - * @param transactionService the component to ensure proper transactional wrapping - */ - public void setTransactionService(TransactionService transactionService) - { - this.transactionService = transactionService; - } - - /** - * @param stores the content stores to clean - */ - public void setStores(List stores) - { - this.stores = stores; - } - - /** - * @param listeners the listeners that can react to deletions - */ - public void setListeners(List listeners) - { - this.listeners = listeners; - } - - /** - * Set the minimum number of days old that orphaned content must be - * before deletion is possible. The default is 7 days. - * - * @param protectDays minimum age (in days) of deleted content - */ - public void setProtectDays(int protectDays) - { - this.protectDays = protectDays; - } - - /** - * Perform basic checks to ensure that the necessary dependencies were injected. - */ - private void checkProperties() - { - if (dictionaryService == null) - { - throw new AlfrescoRuntimeException("Property 'dictionaryService' not set"); - } - if (nodeDaoService == null) - { - throw new AlfrescoRuntimeException("Property 'nodeDaoService' not set"); - } - if (transactionService == null) - { - throw new AlfrescoRuntimeException("Property 'transactionService' not set"); - } - if (stores == null || stores.size() == 0) - { - throw new AlfrescoRuntimeException("Property 'stores' not set"); - } - if (listeners == null) - { - throw new AlfrescoRuntimeException("Property 'listeners' not set"); - } - - // check the protect days - if (protectDays < 0) - { - throw new AlfrescoRuntimeException("Property 'protectDays' must be 0 or greater (0 is not recommended)"); - } - else if (protectDays == 0) - { - logger.warn( - "Property 'protectDays' is set to 0. " + - "It is possible that in-transaction content will be deleted."); - } - } - - private Set getValidUrls() - { - // This does the work for the regular Alfresco repository. - // wrap to make the request in a transaction - TransactionWork> getUrlsWork = new TransactionWork>() - { - public List doWork() throws Exception - { - return nodeDaoService.getContentDataStrings(); - }; - }; - // execute in READ-ONLY txn - List contentDataStrings = TransactionUtil.executeInUserTransaction( - transactionService, - getUrlsWork, - true); - - // Do the same for the AVM repository. - TransactionWork> getAVMUrlsWork = new TransactionWork>() - { - public List doWork() throws Exception - { - return avmNodeDAO.getContentUrls(); - } - }; - - List avmContentUrls = TransactionUtil.executeInUserTransaction( - transactionService, - getAVMUrlsWork, - true); - - // get all valid URLs - Set validUrls = new HashSet(contentDataStrings.size()); - // convert the strings to objects and extract the URL - for (String contentDataString : contentDataStrings) - { - ContentData contentData = ContentData.createContentProperty(contentDataString); - if (contentData.getContentUrl() != null) - { - // a URL was present - validUrls.add(contentData.getContentUrl()); - } - } - // put all the avm urls into validUrls. - for (String url : avmContentUrls) - { - validUrls.add(url); - } - - // done - if (logger.isDebugEnabled()) - { - logger.debug("Found " + validUrls.size() + " valid URLs in metadata"); - } - return validUrls; - } - - public void execute() - { - checkProperties(); - Set validUrls = getValidUrls(); - // now clean each store in turn - for (ContentStore store : stores) - { - clean(validUrls, store); - } - } - - private void clean(Set validUrls, ContentStore store) - { - Date checkAllBeforeDate = new Date(System.currentTimeMillis() - (long) protectDays * 3600L * 1000L * 24L); - // get the store's URLs - Set storeUrls = store.getUrls(null, checkAllBeforeDate); - // remove all URLs that occur in the validUrls - storeUrls.removeAll(validUrls); - // now clean the store - for (String url : storeUrls) - { - ContentReader sourceReader = store.getReader(url); - // announce this to the listeners - for (ContentStoreCleanerListener listener : listeners) - { - // get a fresh reader - ContentReader listenerReader = sourceReader.getReader(); - // call it - listener.beforeDelete(listenerReader); - } - // delete it - store.delete(url); - - if (logger.isDebugEnabled()) - { - logger.debug("Removed URL from store: \n" + - " Store: " + store + "\n" + - " URL: " + url); - } - } - } -} +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.content.cleanup; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.avm.AVMNodeDAO; +import org.alfresco.repo.content.ContentStore; +import org.alfresco.repo.node.db.NodeDaoService; +import org.alfresco.repo.transaction.TransactionUtil; +import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.PropertyCheck; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This component is responsible for finding orphaned content in a given + * content store or stores. Deletion handlers can be provided to ensure + * that the content is moved to another location prior to being removed + * from the store(s) being cleaned. + * + * @author Derek Hulley + */ +public class ContentStoreCleaner +{ + private static Log logger = LogFactory.getLog(ContentStoreCleaner.class); + + private DictionaryService dictionaryService; + private NodeDaoService nodeDaoService; + private TransactionService transactionService; + private AVMNodeDAO avmNodeDAO; + private List stores; + private List listeners; + private int protectDays; + + public ContentStoreCleaner() + { + this.stores = new ArrayList(0); + this.listeners = new ArrayList(0); + this.protectDays = 7; + } + + /** + * @param dictionaryService used to determine which properties are content properties + */ + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + + /** + * @param nodeDaoService used to get the property values + */ + public void setNodeDaoService(NodeDaoService nodeDaoService) + { + this.nodeDaoService = nodeDaoService; + } + + /** + * Setter for Spring. + * @param avmNodeDAO The AVM Node DAO to get urls with. + */ + public void setAvmNodeDAO(AVMNodeDAO avmNodeDAO) + { + this.avmNodeDAO = avmNodeDAO; + } + + /** + * @param transactionService the component to ensure proper transactional wrapping + */ + public void setTransactionService(TransactionService transactionService) + { + this.transactionService = transactionService; + } + + /** + * @param stores the content stores to clean + */ + public void setStores(List stores) + { + this.stores = stores; + } + + /** + * @param listeners the listeners that can react to deletions + */ + public void setListeners(List listeners) + { + this.listeners = listeners; + } + + /** + * Set the minimum number of days old that orphaned content must be + * before deletion is possible. The default is 7 days. + * + * @param protectDays minimum age (in days) of deleted content + */ + public void setProtectDays(int protectDays) + { + this.protectDays = protectDays; + } + + /** + * Perform basic checks to ensure that the necessary dependencies were injected. + */ + private void checkProperties() + { + PropertyCheck.mandatory(this, "dictionaryService", dictionaryService); + PropertyCheck.mandatory(this, "nodeDaoService", nodeDaoService); + PropertyCheck.mandatory(this, "transactionService", transactionService); + PropertyCheck.mandatory(this, "listeners", listeners); + + // check the protect days + if (protectDays < 0) + { + throw new AlfrescoRuntimeException("Property 'protectDays' must be 0 or greater (0 is not recommended)"); + } + else if (protectDays == 0) + { + logger.warn( + "Property 'protectDays' is set to 0. " + + "It is possible that in-transaction content will be deleted."); + } + } + + private Set getValidUrls() + { + final DataTypeDefinition contentDataType = dictionaryService.getDataType(DataTypeDefinition.CONTENT); + // wrap to make the request in a transaction + TransactionWork> getUrlsWork = new TransactionWork>() + { + public List doWork() throws Exception + { + return nodeDaoService.getPropertyValuesByActualType(contentDataType); + }; + }; + // execute in READ-ONLY txn + List values = TransactionUtil.executeInUserTransaction( + transactionService, + getUrlsWork, + true); + + // Do the same for the AVM repository. + TransactionWork> getAVMUrlsWork = new TransactionWork>() + { + public List doWork() throws Exception + { + return avmNodeDAO.getContentUrls(); + } + }; + + List avmContentUrls = TransactionUtil.executeInUserTransaction( + transactionService, + getAVMUrlsWork, + true); + + // get all valid URLs + Set validUrls = new HashSet(values.size()); + // convert the strings to objects and extract the URL + for (Serializable value : values) + { + ContentData contentData = (ContentData) value; + if (contentData.getContentUrl() != null) + { + // a URL was present + validUrls.add(contentData.getContentUrl()); + } + } + // put all the avm urls into validUrls. + for (String url : avmContentUrls) + { + validUrls.add(url); + } + + // done + if (logger.isDebugEnabled()) + { + logger.debug("Found " + validUrls.size() + " valid URLs in metadata"); + } + return validUrls; + } + + public void execute() + { + checkProperties(); + Set validUrls = getValidUrls(); + // now clean each store in turn + for (ContentStore store : stores) + { + clean(validUrls, store); + } + } + + private void clean(Set validUrls, ContentStore store) + { + Date checkAllBeforeDate = new Date(System.currentTimeMillis() - (long) protectDays * 3600L * 1000L * 24L); + // get the store's URLs + Set storeUrls = store.getUrls(null, checkAllBeforeDate); + // remove all URLs that occur in the validUrls + storeUrls.removeAll(validUrls); + // now clean the store + for (String url : storeUrls) + { + ContentReader sourceReader = store.getReader(url); + // announce this to the listeners + for (ContentStoreCleanerListener listener : listeners) + { + // get a fresh reader + ContentReader listenerReader = sourceReader.getReader(); + // call it + listener.beforeDelete(listenerReader); + } + // delete it + store.delete(url); + + if (logger.isDebugEnabled()) + { + logger.debug("Removed URL from store: \n" + + " Store: " + store + "\n" + + " URL: " + url); + } + } + } +} diff --git a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java index 468ba3e5f0..42ba8f27d3 100644 --- a/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/AbstractContentTransformerTest.java @@ -19,7 +19,10 @@ package org.alfresco.repo.content.transform; import java.io.File; import java.io.IOException; import java.net.URL; -import java.util.List; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.TreeSet; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.filestore.FileContentReader; @@ -120,45 +123,71 @@ public abstract class AbstractContentTransformerTest extends BaseSpringTest * case where optimizations are being done around the selection of the most * appropriate transformer, different transformers could be used during the iteration * process. + *

+ * Results for the transformations are dumped to a temporary file named + * AbstractContentTransformerTest-results-1234.txt. */ public void testAllConversions() throws Exception { + StringBuilder sb = new StringBuilder(2048); + sb.append("Mimetype Conversion Tests \n") + .append("========================= \n") + .append(" Date: ").append(new Date()).append("\n") + .append("\n"); + // get all mimetypes - List mimetypes = mimetypeMap.getMimetypes(); + Set mimetypes = new TreeSet(mimetypeMap.getMimetypes()); for (String sourceMimetype : mimetypes) { // attempt to get a source file for each mimetype String sourceExtension = mimetypeMap.getExtension(sourceMimetype); - File sourceFile = AbstractContentTransformerTest.loadQuickTestFile(sourceExtension); - if (sourceFile == null) - { - continue; // no test file available for that extension - } + + sb.append(" Source Extension: ").append(sourceExtension).append("\n"); // attempt to convert to every other mimetype for (String targetMimetype : mimetypes) { ContentWriter targetWriter = null; // construct a reader onto the source file + String targetExtension = mimetypeMap.getExtension(targetMimetype); + + // must we test the transformation? + ContentTransformer transformer = getTransformer(sourceMimetype, targetMimetype); + if (transformer == null || transformer.getReliability(sourceMimetype, targetMimetype) <= 0.0) + { + // no transformer + continue; + } + + // dump + sb.append(" Target Extension: ").append(targetExtension); + sb.append(" <").append(transformer.getClass().getSimpleName()).append(">"); + + // is there a test file for this conversion? + File sourceFile = AbstractContentTransformerTest.loadQuickTestFile(sourceExtension); + if (sourceFile == null) + { + sb.append(" \n"); + continue; // no test file available for that extension + } ContentReader sourceReader = new FileContentReader(sourceFile); // perform the transformation several times so that we get a good idea of performance int count = 0; + long before = System.currentTimeMillis(); + Set transformerClasses = new HashSet(2); for (int i = 0; i < 5; i++) { - // must we test the transformation? - ContentTransformer transformer = getTransformer(sourceMimetype, targetMimetype); - if (transformer == null) + // get the transformer repeatedly as it might be different each time around + transformer = getTransformer(sourceMimetype, targetMimetype); + // must we report on this class? + if (!transformerClasses.contains(transformer.getClass().getName())) { - break; // test is not required + transformerClasses.add(transformer.getClass().getName()); + sb.append(" <").append(transformer.getClass().getSimpleName()).append(">"); } - else if (transformer.getReliability(sourceMimetype, targetMimetype) <= 0.0) - { - break; // not reliable for this transformation - } - + // make a writer for the target file - String targetExtension = mimetypeMap.getExtension(targetMimetype); File targetFile = TempFileProvider.createTempFile( getClass().getSimpleName() + "_" + getName() + "_" + sourceExtension + "_", "." + targetExtension); @@ -198,6 +227,11 @@ public abstract class AbstractContentTransformerTest extends BaseSpringTest // increment count count++; } + long after = System.currentTimeMillis(); + double average = (double) (after - before) / (double) count; + + // dump + sb.append(String.format(" average %10.0f ms", average)).append("\n"); if (logger.isDebugEnabled()) { @@ -209,5 +243,11 @@ public abstract class AbstractContentTransformerTest extends BaseSpringTest } } } + + // dump to file + File outputFile = TempFileProvider.createTempFile("AbstractContentTransformerTest-results-", ".txt"); + ContentWriter outputWriter = new FileContentWriter(outputFile); + outputWriter.setEncoding("UTF8"); + outputWriter.putContent(sb.toString()); } } diff --git a/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java b/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java index 12d016db23..a70d31d106 100644 --- a/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java +++ b/source/java/org/alfresco/repo/content/transform/OpenOfficeContentTransformerTest.java @@ -16,9 +16,16 @@ */ package org.alfresco.repo.content.transform; +import java.io.File; + import net.sf.jooreports.openoffice.connection.OpenOfficeConnection; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.content.filestore.FileContentReader; +import org.alfresco.repo.content.filestore.FileContentWriter; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.util.TempFileProvider; /** * @see org.alfresco.repo.content.transform.OpenOfficeContentTransformer @@ -75,4 +82,24 @@ public class OpenOfficeContentTransformerTest extends AbstractContentTransformer reliability = transformer.getReliability(MimetypeMap.MIMETYPE_WORD, MimetypeMap.MIMETYPE_TEXT_PLAIN); assertEquals("Mimetype should be supported", 1.0, reliability); } + + /** + * Test what is up with HTML to PDF + */ + public void testHtmlToPdf() throws Exception + { + if (!transformer.isConnected()) + { + // no connection + return; + } + File htmlSourceFile = loadQuickTestFile("html"); + File pdfTargetFile = TempFileProvider.createTempFile(getName() + "-target-", ".pdf"); + ContentReader reader = new FileContentReader(htmlSourceFile); + reader.setMimetype(MimetypeMap.MIMETYPE_HTML); + ContentWriter writer = new FileContentWriter(pdfTargetFile); + writer.setMimetype(MimetypeMap.MIMETYPE_PDF); + + transformer.transform(reader, writer); + } } diff --git a/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformer.java b/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformer.java index 852f9194b0..bb11c7d662 100644 --- a/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformer.java +++ b/source/java/org/alfresco/repo/content/transform/magick/AbstractImageMagickContentTransformer.java @@ -145,6 +145,10 @@ public abstract class AbstractImageMagickContentTransformer extends AbstractCont { return false; // rgb extension doesn't work } + else if (mimetype.equals(MimetypeMap.MIMETYPE_IMAGE_SVG)) + { + return false; // svg extension doesn't work + } else { return true; diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryComponent.java b/source/java/org/alfresco/repo/dictionary/DictionaryComponent.java index 2b9722b49e..f9cd844d6c 100644 --- a/source/java/org/alfresco/repo/dictionary/DictionaryComponent.java +++ b/source/java/org/alfresco/repo/dictionary/DictionaryComponent.java @@ -81,7 +81,7 @@ public class DictionaryComponent implements DictionaryService Collection propertyTypes = new ArrayList(); for (QName model : getAllModels()) { - propertyTypes.addAll(getAspects(model)); + propertyTypes.addAll(getDataTypes(model)); } return propertyTypes; } diff --git a/source/java/org/alfresco/repo/dictionary/M2Model.java b/source/java/org/alfresco/repo/dictionary/M2Model.java index 4dad74222a..c4c8752aa4 100644 --- a/source/java/org/alfresco/repo/dictionary/M2Model.java +++ b/source/java/org/alfresco/repo/dictionary/M2Model.java @@ -202,7 +202,7 @@ public class M2Model M2Type type = getType(name); if (type != null) { - types.remove(types); + types.remove(type); } } diff --git a/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml b/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml index fc8748f662..ba51937ef7 100644 --- a/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml +++ b/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml @@ -16,7 +16,7 @@ - org.apache.lucene.analysis.standard.StandardAnalyzer + org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser java.lang.Object diff --git a/source/java/org/alfresco/repo/domain/DbAccessControlList.java b/source/java/org/alfresco/repo/domain/DbAccessControlList.java index da378dd6c0..327ed47347 100644 --- a/source/java/org/alfresco/repo/domain/DbAccessControlList.java +++ b/source/java/org/alfresco/repo/domain/DbAccessControlList.java @@ -1,83 +1,83 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.domain; - -import java.util.Set; - -import org.alfresco.repo.domain.hibernate.DbAccessControlEntryImpl; - - -/** - * The interface to support persistence of node access control entries in hibernate - * - * @author andyh - */ -public interface DbAccessControlList -{ - public long getId(); - - /** - * - * @return Returns the access control entries for this access control list - */ - public Set getEntries(); - - /** - * Get inheritance behaviour - * @return Returns the inheritance status of this list - */ - public boolean getInherits(); - - /** - * Set inheritance behaviour - * @param inherits true to set the permissions to inherit - */ - public void setInherits(boolean inherits); - - public int deleteEntriesForAuthority(String authorityKey); - - public int deleteEntriesForPermission(DbPermissionKey permissionKey); - - public int deleteEntry(String authorityKey, DbPermissionKey permissionKey); - - /** - * Delete the entries related to this access control list - * - * @return Returns the number of entries deleted - */ - public int deleteEntries(); - - public DbAccessControlEntry getEntry(String authorityKey, DbPermissionKey permissionKey); - - /** - * Factory method to create an entry and wire it up. - * Note that the returned value may still be transient. Saving it should be fine, but - * is not required. - * - * @param permission the mandatory permission association with this entry - * @param authority the mandatory authority. Must not be transient. - * @param allowed allowed or disallowed. Must not be transient. - * @return Returns the new entry - */ - public DbAccessControlEntryImpl newEntry(DbPermission permission, DbAuthority authority, boolean allowed); - - /** - * Make a copy of this ACL (persistently) - * @return The copy. - */ - public DbAccessControlList getCopy(); -} +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.domain; + +import java.util.Set; + +import org.alfresco.repo.domain.hibernate.DbAccessControlEntryImpl; + + +/** + * The interface to support persistence of node access control entries in hibernate + * + * @author andyh + */ +public interface DbAccessControlList +{ + public long getId(); + + /** + * + * @return Returns the access control entries for this access control list + */ + public Set getEntries(); + + /** + * Get inheritance behaviour + * @return Returns the inheritance status of this list + */ + public boolean getInherits(); + + /** + * Set inheritance behaviour + * @param inherits true to set the permissions to inherit + */ + public void setInherits(boolean inherits); + + public int deleteEntriesForAuthority(String authorityKey); + + public int deleteEntriesForPermission(DbPermissionKey permissionKey); + + public int deleteEntry(String authorityKey, DbPermissionKey permissionKey); + + /** + * Delete the entries related to this access control list + * + * @return Returns the number of entries deleted + */ + public int deleteEntries(); + + public DbAccessControlEntry getEntry(String authorityKey, DbPermissionKey permissionKey); + + /** + * Factory method to create an entry and wire it up. + * Note that the returned value may still be transient. Saving it should be fine, but + * is not required. + * + * @param permission the mandatory permission association with this entry + * @param authority the mandatory authority. Must not be transient. + * @param allowed allowed or disallowed. Must not be transient. + * @return Returns the new entry + */ + public DbAccessControlEntryImpl newEntry(DbPermission permission, DbAuthority authority, boolean allowed); + + /** + * Make a copy of this ACL (persistently) + * @return The copy. + */ + public DbAccessControlList getCopy(); +} diff --git a/source/java/org/alfresco/repo/domain/PropertyValue.java b/source/java/org/alfresco/repo/domain/PropertyValue.java index f4fad1fa2a..bd1803d20f 100644 --- a/source/java/org/alfresco/repo/domain/PropertyValue.java +++ b/source/java/org/alfresco/repo/domain/PropertyValue.java @@ -19,6 +19,7 @@ package org.alfresco.repo.domain; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -438,19 +439,32 @@ public class PropertyValue implements Cloneable, Serializable * * @return Returns the ValueType - never null */ - private ValueType makeValueType(QName typeQName) + private static ValueType makeValueType(QName typeQName) { ValueType valueType = valueTypesByPropertyType.get(typeQName); if (valueType == null) { throw new AlfrescoRuntimeException( "Property type not recognised: \n" + - " type: " + typeQName + "\n" + - " property: " + this); + " type: " + typeQName); } return valueType; } + /** + * Given an actual type qualified name, returns the String that represents it in + * the database. + * + * @param typeQName the type qualified name + * @return Returns the String representation of the type, + * e.g. CONTENT for type d:content. + */ + public static String getActualTypeString(QName typeQName) + { + ValueType valueType = makeValueType(typeQName); + return valueType.toString(); + } + @Override public boolean equals(Object obj) { @@ -632,15 +646,16 @@ public class PropertyValue implements Cloneable, Serializable * @return Returns the value of this property as the desired type, or a Collection * of values of the required type * - * @throws java.lang.UnsupportedOperationException if the value cannot be converted to the - * type given + * @throws AlfrescoRuntimeException + * if the type given is not recognized + * @throws org.alfresco.service.cmr.repository.datatype.TypeConversionException + * if the conversion to the required type fails * * @see DataTypeDefinition#ANY The static qualified names for the types */ public Serializable getValue(QName typeQName) { // first check for null - ValueType requiredType = makeValueType(typeQName); if (requiredType == ValueType.SERIALIZABLE) { @@ -680,6 +695,24 @@ public class PropertyValue implements Cloneable, Serializable return ret; } + /** + * Gets the value or values as a guaranteed collection. + * + * @see #getValue(QName) + */ + public Collection getCollection(QName typeQName) + { + Serializable value = getValue(typeQName); + if (value instanceof Collection) + { + return (Collection) value; + } + else + { + return Collections.singletonList(value); + } + } + public boolean getBooleanValue() { if (booleanValue == null) diff --git a/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java b/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java index 8df8f271a2..4a830a42f1 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java @@ -133,29 +133,6 @@ public class ChildAssocImpl implements ChildAssoc, Serializable return sb.toString(); } - public boolean equals(Object obj) - { - if (obj == null) - { - return false; - } - else if (obj == this) - { - return true; - } - else if (!(obj instanceof ChildAssoc)) - { - return false; - } - ChildAssoc that = (ChildAssoc) obj; - return EqualsHelper.nullSafeEquals(id, that.getId()); - } - - public int hashCode() - { - return (id == null ? 0 : id.hashCode()); - } - /** * Orders the child associations by ID. A smaller ID has a higher priority. * This may change once we introduce a changeable index against which to order. diff --git a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListImpl.java b/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListImpl.java index 6576a88117..7139d6a8bc 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListImpl.java @@ -1,250 +1,250 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.alfresco.repo.domain.DbAccessControlEntry; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.DbAuthority; -import org.alfresco.repo.domain.DbPermission; -import org.alfresco.repo.domain.DbPermissionKey; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.Session; - -/** - * The hibernate persisted class for node permission entries. - * - * @author andyh - */ -public class DbAccessControlListImpl extends LifecycleAdapter - implements DbAccessControlList, Serializable -{ - private static final long serialVersionUID = 3123277428227075648L; - - private static Log logger = LogFactory.getLog(DbAccessControlListImpl.class); - - private long id; - private Set entries; - private boolean inherits; - - public DbAccessControlListImpl() - { - entries = new HashSet(5); - } - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(128); - sb.append("DbAccessControlListImpl") - .append("[ id=").append(id) - .append(", entries=").append(entries.size()) - .append(", inherits=").append(inherits) - .append("]"); - return sb.toString(); - } - - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (!(o instanceof DbAccessControlList)) - { - return false; - } - DbAccessControlList other = (DbAccessControlList) o; - - return (this.inherits == other.getInherits()); - } - - @Override - public int hashCode() - { - return (inherits == false ? 0 : 17); - } - - public long getId() - { - return id; - } - - /** - * Hibernate use - */ - @SuppressWarnings("unused") - private void setId(long id) - { - this.id = id; - } - - public Set getEntries() - { - return entries; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setEntries(Set entries) - { - this.entries = entries; - } - - public boolean getInherits() - { - return inherits; - } - - public void setInherits(boolean inherits) - { - this.inherits = inherits; - } - - /** - * @see #deleteEntry(String, DbPermissionKey) - */ - public int deleteEntriesForAuthority(String authority) - { - return deleteEntry(authority, null); - } - - /** - * @see #deleteEntry(String, DbPermissionKey) - */ - public int deleteEntriesForPermission(DbPermissionKey permissionKey) - { - return deleteEntry(null, permissionKey); - } - - public int deleteEntry(String authority, DbPermissionKey permissionKey) - { - List toDelete = new ArrayList(2); - for (DbAccessControlEntry entry : entries) - { - if (authority != null && !authority.equals(entry.getAuthority().getRecipient())) - { - // authority is not a match - continue; - } - else if (permissionKey != null && !permissionKey.equals(entry.getPermission().getKey())) - { - // permission is not a match - continue; - } - toDelete.add(entry); - } - // delete them - for (DbAccessControlEntry entry : toDelete) - { - // remove from the entry list - entry.delete(); - } - // done - if (logger.isDebugEnabled()) - { - logger.debug("Deleted " + toDelete.size() + " access entries: \n" + - " access control list: " + id + "\n" + - " authority: " + authority + "\n" + - " permission: " + permissionKey); - } - return toDelete.size(); - } - - public int deleteEntries() - { - /* - * We don't do the full delete-remove-from-set thing here. Just delete each child entity - * and then clear the entry set. - */ - - Session session = getSession(); - List toDelete = new ArrayList(entries); - // delete each entry - for (DbAccessControlEntry entry : toDelete) - { - session.delete(entry); - } - // clear the list - int count = entries.size(); - entries.clear(); - // done - if (logger.isDebugEnabled()) - { - logger.debug("Deleted " + count + " access entries for access control list " + this.id); - } - return count; - } - - public DbAccessControlEntry getEntry(String authority, DbPermissionKey permissionKey) - { - for (DbAccessControlEntry entry : entries) - { - DbAuthority authorityEntity = entry.getAuthority(); - DbPermission permissionEntity = entry.getPermission(); - // check for a match - if (authorityEntity.getRecipient().equals(authority) - && permissionEntity.getKey().equals(permissionKey)) - { - // found it - return entry; - } - } - return null; - } - - public DbAccessControlEntryImpl newEntry(DbPermission permission, DbAuthority authority, boolean allowed) - { - DbAccessControlEntryImpl accessControlEntry = new DbAccessControlEntryImpl(); - // fill - accessControlEntry.setAccessControlList(this); - accessControlEntry.setPermission(permission); - accessControlEntry.setAuthority(authority); - accessControlEntry.setAllowed(allowed); - // save it - getSession().save(accessControlEntry); - // maintain inverse set on the acl - getEntries().add(accessControlEntry); - // done - return accessControlEntry; - } - - /** - * Make a copy of this ACL. - * @return The copy. - */ - public DbAccessControlList getCopy() - { - DbAccessControlList newAcl = - new DbAccessControlListImpl(); - getSession().save(newAcl); - for (DbAccessControlEntry entry : entries) - { - newAcl.newEntry(entry.getPermission(), entry.getAuthority(), entry.isAllowed()); - } - return newAcl; - } -} +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.domain.hibernate; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.alfresco.repo.domain.DbAccessControlEntry; +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.domain.DbAuthority; +import org.alfresco.repo.domain.DbPermission; +import org.alfresco.repo.domain.DbPermissionKey; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.Session; + +/** + * The hibernate persisted class for node permission entries. + * + * @author andyh + */ +public class DbAccessControlListImpl extends LifecycleAdapter + implements DbAccessControlList, Serializable +{ + private static final long serialVersionUID = 3123277428227075648L; + + private static Log logger = LogFactory.getLog(DbAccessControlListImpl.class); + + private long id; + private Set entries; + private boolean inherits; + + public DbAccessControlListImpl() + { + entries = new HashSet(5); + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(128); + sb.append("DbAccessControlListImpl") + .append("[ id=").append(id) + .append(", entries=").append(entries.size()) + .append(", inherits=").append(inherits) + .append("]"); + return sb.toString(); + } + + @Override + public boolean equals(Object o) + { + if (this == o) + { + return true; + } + if (!(o instanceof DbAccessControlList)) + { + return false; + } + DbAccessControlList other = (DbAccessControlList) o; + + return (this.inherits == other.getInherits()); + } + + @Override + public int hashCode() + { + return (inherits == false ? 0 : 17); + } + + public long getId() + { + return id; + } + + /** + * Hibernate use + */ + @SuppressWarnings("unused") + private void setId(long id) + { + this.id = id; + } + + public Set getEntries() + { + return entries; + } + + /** + * For Hibernate use + */ + @SuppressWarnings("unused") + private void setEntries(Set entries) + { + this.entries = entries; + } + + public boolean getInherits() + { + return inherits; + } + + public void setInherits(boolean inherits) + { + this.inherits = inherits; + } + + /** + * @see #deleteEntry(String, DbPermissionKey) + */ + public int deleteEntriesForAuthority(String authority) + { + return deleteEntry(authority, null); + } + + /** + * @see #deleteEntry(String, DbPermissionKey) + */ + public int deleteEntriesForPermission(DbPermissionKey permissionKey) + { + return deleteEntry(null, permissionKey); + } + + public int deleteEntry(String authority, DbPermissionKey permissionKey) + { + List toDelete = new ArrayList(2); + for (DbAccessControlEntry entry : entries) + { + if (authority != null && !authority.equals(entry.getAuthority().getRecipient())) + { + // authority is not a match + continue; + } + else if (permissionKey != null && !permissionKey.equals(entry.getPermission().getKey())) + { + // permission is not a match + continue; + } + toDelete.add(entry); + } + // delete them + for (DbAccessControlEntry entry : toDelete) + { + // remove from the entry list + entry.delete(); + } + // done + if (logger.isDebugEnabled()) + { + logger.debug("Deleted " + toDelete.size() + " access entries: \n" + + " access control list: " + id + "\n" + + " authority: " + authority + "\n" + + " permission: " + permissionKey); + } + return toDelete.size(); + } + + public int deleteEntries() + { + /* + * We don't do the full delete-remove-from-set thing here. Just delete each child entity + * and then clear the entry set. + */ + + Session session = getSession(); + List toDelete = new ArrayList(entries); + // delete each entry + for (DbAccessControlEntry entry : toDelete) + { + session.delete(entry); + } + // clear the list + int count = entries.size(); + entries.clear(); + // done + if (logger.isDebugEnabled()) + { + logger.debug("Deleted " + count + " access entries for access control list " + this.id); + } + return count; + } + + public DbAccessControlEntry getEntry(String authority, DbPermissionKey permissionKey) + { + for (DbAccessControlEntry entry : entries) + { + DbAuthority authorityEntity = entry.getAuthority(); + DbPermission permissionEntity = entry.getPermission(); + // check for a match + if (authorityEntity.getRecipient().equals(authority) + && permissionEntity.getKey().equals(permissionKey)) + { + // found it + return entry; + } + } + return null; + } + + public DbAccessControlEntryImpl newEntry(DbPermission permission, DbAuthority authority, boolean allowed) + { + DbAccessControlEntryImpl accessControlEntry = new DbAccessControlEntryImpl(); + // fill + accessControlEntry.setAccessControlList(this); + accessControlEntry.setPermission(permission); + accessControlEntry.setAuthority(authority); + accessControlEntry.setAllowed(allowed); + // save it + getSession().save(accessControlEntry); + // maintain inverse set on the acl + getEntries().add(accessControlEntry); + // done + return accessControlEntry; + } + + /** + * Make a copy of this ACL. + * @return The copy. + */ + public DbAccessControlList getCopy() + { + DbAccessControlList newAcl = + new DbAccessControlListImpl(); + getSession().save(newAcl); + for (DbAccessControlEntry entry : entries) + { + newAcl.newEntry(entry.getPermission(), entry.getAuthority(), entry.isAllowed()); + } + return newAcl; + } +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateNodeTest.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateNodeTest.java index 1419a3c413..2eb1b7d4e7 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/HibernateNodeTest.java +++ b/source/java/org/alfresco/repo/domain/hibernate/HibernateNodeTest.java @@ -1,456 +1,462 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import javax.transaction.UserTransaction; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.domain.ChildAssoc; -import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.NodeKey; -import org.alfresco.repo.domain.NodeStatus; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.Server; -import org.alfresco.repo.domain.Store; -import org.alfresco.repo.domain.StoreKey; -import org.alfresco.repo.domain.Transaction; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.namespace.QName; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.BaseSpringTest; -import org.alfresco.util.GUID; -import org.hibernate.CacheMode; -import org.hibernate.exception.ConstraintViolationException; - -/** - * Test persistence and retrieval of Hibernate-specific implementations of the - * {@link org.alfresco.repo.domain.Node} interface - * - * @author Derek Hulley - */ -@SuppressWarnings("unused") -public class HibernateNodeTest extends BaseSpringTest -{ - private static final String TEST_NAMESPACE = "http://www.alfresco.org/test/HibernateNodeTest"; - private static int i = 0; - - private Store store; - private Server server; - private Transaction transaction; - - public HibernateNodeTest() - { - } - - protected void onSetUpInTransaction() throws Exception - { - store = new StoreImpl(); - StoreKey storeKey = new StoreKey(StoreRef.PROTOCOL_WORKSPACE, - "TestWorkspace@" + System.currentTimeMillis() + " - " + System.nanoTime()); - store.setKey(storeKey); - // persist so that it is present in the hibernate cache - getSession().save(store); - - server = (Server) getSession().get(ServerImpl.class, new Long(1)); - if (server == null) - { - server = new ServerImpl(); - server.setIpAddress("" + "i_" + System.currentTimeMillis()); - getSession().save(server); - } - transaction = new TransactionImpl(); - transaction.setServer(server); - transaction.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); - getSession().save(transaction); - } - - protected void onTearDownInTransaction() - { - // force a flush to ensure that the database updates succeed - getSession().flush(); - getSession().clear(); - } - - public void testSetUp() throws Exception - { - assertNotNull("Workspace not initialised", store); - } - - public void testGetStore() throws Exception - { - // create a new Node - Node node = new NodeImpl(); - node.setStore(store); - node.setUuid(GUID.generate()); - node.setTypeQName(ContentModel.TYPE_CONTAINER); - - // now it should work - Serializable id = getSession().save(node); - - // throw the reference away and get the a new one for the id - node = (Node) getSession().load(NodeImpl.class, id); - assertNotNull("Node not found", node); - // check that the store has been loaded - Store loadedStore = node.getStore(); - assertNotNull("Store not present on node", loadedStore); - assertEquals("Incorrect store key", store, loadedStore); - } - - public void testNodeStatus() - { - NodeKey key = new NodeKey(store.getKey(), "AAA"); - // create the node status - NodeStatus nodeStatus = new NodeStatusImpl(); - nodeStatus.setKey(key); - nodeStatus.setTransaction(transaction); - getSession().save(nodeStatus); - - // create a new Node - Node node = new NodeImpl(); - node.setStore(store); - node.setUuid(GUID.generate()); - node.setTypeQName(ContentModel.TYPE_CONTAINER); - Serializable nodeId = getSession().save(node); - - // This should all be fine. The node does not HAVE to have a status. - flushAndClear(); - - // set the node - nodeStatus = (NodeStatus) getSession().get(NodeStatusImpl.class, key); - nodeStatus.setNode(node); - flushAndClear(); - - // is the node retrievable? - nodeStatus = (NodeStatus) getSession().get(NodeStatusImpl.class, key); - node = nodeStatus.getNode(); - assertNotNull("Node was not attached to status", node); - // change the values - transaction.setChangeTxnId("txn:456"); - // delete the node - getSession().delete(node); - - try - { - flushAndClear(); - fail("Node status may not refer to non-existent node"); - } - catch(ConstraintViolationException e) - { - // expected - } - } - - /** - * Check that properties can be persisted and retrieved - */ - public void testProperties() throws Exception - { - // create a new Node - Node node = new NodeImpl(); - node.setStore(store); - node.setUuid(GUID.generate()); - node.setTypeQName(ContentModel.TYPE_CONTAINER); - // give it a property map - Map propertyMap = new HashMap(5); - QName propertyQName = QName.createQName("{}A"); - PropertyValue propertyValue = new PropertyValue(DataTypeDefinition.TEXT, "AAA"); - propertyMap.put(propertyQName, propertyValue); - node.getProperties().putAll(propertyMap); - // persist it - Serializable id = getSession().save(node); - - // throw the reference away and get the a new one for the id - node = (Node) getSession().load(NodeImpl.class, id); - assertNotNull("Node not found", node); - // extract the Map - propertyMap = node.getProperties(); - assertNotNull("Map not persisted", propertyMap); - // ensure that the value is present - assertNotNull("Property value not present in map", QName.createQName("{}A")); - } - - /** - * Check that aspect qnames can be added and removed from a node and that they - * are persisted correctly - */ - public void testAspects() throws Exception - { - // make a real node - Node node = new NodeImpl(); - node.setStore(store); - node.setUuid(GUID.generate()); - node.setTypeQName(ContentModel.TYPE_CMOBJECT); - - // add some aspects - QName aspect1 = QName.createQName(TEST_NAMESPACE, "1"); - QName aspect2 = QName.createQName(TEST_NAMESPACE, "2"); - QName aspect3 = QName.createQName(TEST_NAMESPACE, "3"); - QName aspect4 = QName.createQName(TEST_NAMESPACE, "4"); - Set aspects = node.getAspects(); - aspects.add(aspect1); - aspects.add(aspect2); - aspects.add(aspect3); - aspects.add(aspect4); - assertFalse("Set did not eliminate duplicate aspect qname", aspects.add(aspect4)); - - // persist - Serializable id = getSession().save(node); - - // flush and clear - flushAndClear(); - - // get node and check aspects - node = (Node) getSession().get(NodeImpl.class, id); - assertNotNull("Node not persisted", node); - aspects = node.getAspects(); - assertEquals("Not all aspects persisted", 4, aspects.size()); - } - - public void testChildAssoc() throws Exception - { - // make a content node - Node contentNode = new NodeImpl(); - contentNode.setStore(store); - contentNode.setUuid(GUID.generate()); - contentNode.setTypeQName(ContentModel.TYPE_CONTENT); - Serializable contentNodeId = getSession().save(contentNode); - - // make a container node - Node containerNode = new NodeImpl(); - containerNode.setStore(store); - containerNode.setUuid(GUID.generate()); - containerNode.setTypeQName(ContentModel.TYPE_CONTAINER); - Serializable containerNodeId = getSession().save(containerNode); - // create an association to the content - ChildAssoc assoc1 = new ChildAssocImpl(); - assoc1.setIsPrimary(true); - assoc1.setTypeQName(QName.createQName(null, "type1")); - assoc1.setQname(QName.createQName(null, "number1")); - assoc1.setChildNodeName("number1"); - assoc1.setChildNodeNameCrc(1); - getSession().save(assoc1); - assoc1.buildAssociation(containerNode, contentNode); - - // make another association between the same two parent and child nodes - ChildAssoc assoc2 = new ChildAssocImpl(); - assoc2.setIsPrimary(true); - assoc2.setTypeQName(QName.createQName(null, "type2")); - assoc2.setQname(QName.createQName(null, "number2")); - assoc2.setChildNodeName("number2"); - assoc2.setChildNodeNameCrc(2); - getSession().save(assoc2); - assoc2.buildAssociation(containerNode, contentNode); - - assertFalse("Hashcode incorrent", assoc2.hashCode() == 0); - assertNotSame("Assoc equals failure", assoc1, assoc2); - - // reload the container - containerNode = (Node) getSession().get(NodeImpl.class, containerNodeId); - assertNotNull("Node not found", containerNode); - - // check that we can traverse the association from the child - Collection parentAssocs = contentNode.getParentAssocs(); - assertEquals("Expected exactly 2 parent assocs", 2, parentAssocs.size()); - parentAssocs = new HashSet(parentAssocs); - for (ChildAssoc assoc : parentAssocs) - { - // maintain inverse assoc sets - assoc.removeAssociation(); - // remove the assoc - getSession().delete(assoc); - } - - // check that the child now has zero parents - parentAssocs = contentNode.getParentAssocs(); - assertEquals("Expected exactly 0 parent assocs", 0, parentAssocs.size()); - } - - /** - * Allows tracing of L2 cache - */ - public void testCaching() throws Exception - { - // make a node - Node node = new NodeImpl(); - node.setStore(store); - node.setUuid(GUID.generate()); - node.setTypeQName(ContentModel.TYPE_CONTENT); - Serializable nodeId = getSession().save(node); - - // add some aspects to the node - Set aspects = node.getAspects(); - aspects.add(ContentModel.ASPECT_AUDITABLE); - - // add some properties - Map properties = node.getProperties(); - properties.put(ContentModel.PROP_NAME, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); - - // check that the session hands back the same instance - Node checkNode = (Node) getSession().get(NodeImpl.class, nodeId); - assertNotNull(checkNode); - assertTrue("Node retrieved was not same instance", checkNode == node); - - Set checkAspects = checkNode.getAspects(); - assertTrue("Aspect set retrieved was not the same instance", checkAspects == aspects); - assertEquals("Incorrect number of aspects", 1, checkAspects.size()); - QName checkQName = (QName) checkAspects.toArray()[0]; - assertTrue("QName retrieved was not the same instance", checkQName == ContentModel.ASPECT_AUDITABLE); - - Map checkProperties = checkNode.getProperties(); - assertTrue("Propery map retrieved was not the same instance", checkProperties == properties); - assertTrue("Property not found", checkProperties.containsKey(ContentModel.PROP_NAME)); - - flushAndClear(); - // commit the transaction - setComplete(); - endTransaction(); - - TransactionService transactionService = (TransactionService) applicationContext.getBean("transactionComponent"); - UserTransaction txn = transactionService.getUserTransaction(); - try - { - txn.begin(); - - // check that the L2 cache hands back the same instance - checkNode = (Node) getSession().get(NodeImpl.class, nodeId); - assertNotNull(checkNode); - checkAspects = checkNode.getAspects(); - - txn.commit(); - } - catch (Throwable e) - { - txn.rollback(); - } - } - - /** - * Create some simple parent-child relationships and flush them. Then read them back in without - * using the L2 cache. - */ - public void testQueryJoins() throws Exception - { - getSession().setCacheMode(CacheMode.IGNORE); - - // make a container node - Node containerNode = new NodeImpl(); - containerNode.setStore(store); - containerNode.setUuid(GUID.generate()); - containerNode.setTypeQName(ContentModel.TYPE_CONTAINER); - containerNode.getProperties().put(ContentModel.PROP_AUTHOR, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); - containerNode.getProperties().put(ContentModel.PROP_ARCHIVED_BY, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); - containerNode.getAspects().add(ContentModel.ASPECT_AUDITABLE); - Serializable containerNodeId = getSession().save(containerNode); - NodeKey containerNodeKey = new NodeKey(containerNode.getNodeRef()); - NodeStatus containerNodeStatus = new NodeStatusImpl(); - containerNodeStatus.setKey(containerNodeKey); - containerNodeStatus.setNode(containerNode); - containerNodeStatus.setTransaction(transaction); - getSession().save(containerNodeStatus); - // make content node 1 - Node contentNode1 = new NodeImpl(); - contentNode1.setStore(store); - contentNode1.setUuid(GUID.generate()); - contentNode1.setTypeQName(ContentModel.TYPE_CONTENT); - contentNode1.getProperties().put(ContentModel.PROP_AUTHOR, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); - contentNode1.getProperties().put(ContentModel.PROP_ARCHIVED_BY, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); - contentNode1.getAspects().add(ContentModel.ASPECT_AUDITABLE); - Serializable contentNode1Id = getSession().save(contentNode1); - NodeKey contentNodeKey1 = new NodeKey(contentNode1.getNodeRef()); - NodeStatus contentNodeStatus1 = new NodeStatusImpl(); - contentNodeStatus1.setKey(contentNodeKey1); - contentNodeStatus1.setNode(contentNode1); - contentNodeStatus1.setTransaction(transaction); - getSession().save(contentNodeStatus1); - // make content node 2 - Node contentNode2 = new NodeImpl(); - contentNode2.setStore(store); - contentNode2.setUuid(GUID.generate()); - contentNode2.setTypeQName(ContentModel.TYPE_CONTENT); - Serializable contentNode2Id = getSession().save(contentNode2); - contentNode2.getProperties().put(ContentModel.PROP_AUTHOR, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); - contentNode2.getProperties().put(ContentModel.PROP_ARCHIVED_BY, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); - contentNode2.getAspects().add(ContentModel.ASPECT_AUDITABLE); - NodeKey contentNodeKey2 = new NodeKey(contentNode2.getNodeRef()); - NodeStatus contentNodeStatus2 = new NodeStatusImpl(); - contentNodeStatus2.setKey(contentNodeKey2); - contentNodeStatus2.setNode(contentNode2); - contentNodeStatus2.setTransaction(transaction); - getSession().save(contentNodeStatus2); - // create an association to content 1 - ChildAssoc assoc1 = new ChildAssocImpl(); - assoc1.setIsPrimary(true); - assoc1.setTypeQName(QName.createQName(null, "type1")); - assoc1.setQname(QName.createQName(null, "number1")); - assoc1.setChildNodeName("number1"); - assoc1.setChildNodeNameCrc(1); - assoc1.buildAssociation(containerNode, contentNode1); - getSession().save(assoc1); - // create an association to content 2 - ChildAssoc assoc2 = new ChildAssocImpl(); - assoc2.setIsPrimary(true); - assoc2.setTypeQName(QName.createQName(null, "type2")); - assoc2.setQname(QName.createQName(null, "number2")); - assoc2.setChildNodeName("number2"); - assoc2.setChildNodeNameCrc(2); - assoc2.buildAssociation(containerNode, contentNode2); - getSession().save(assoc2); - - // make sure that there are no entities cached in either L1 or L2 - getSession().flush(); - getSession().clear(); - - // now read the structure back in from the container down - containerNodeStatus = (NodeStatus) getSession().get(NodeStatusImpl.class, containerNodeKey); - containerNode = containerNodeStatus.getNode(); - - // clear out again - getSession().clear(); - - // expect that just the specific property gets removed in the delete statement - getSession().flush(); - getSession().clear(); - - // Create a second association to content 2 - // create an association to content 2 - containerNodeStatus = (NodeStatus) getSession().get(NodeStatusImpl.class, containerNodeKey); - containerNode = containerNodeStatus.getNode(); - contentNodeStatus2 = (NodeStatus) getSession().get(NodeStatusImpl.class, contentNodeKey2); - contentNode2 = contentNodeStatus2.getNode(); - ChildAssoc assoc3 = new ChildAssocImpl(); - assoc3.setIsPrimary(false); - assoc3.setTypeQName(QName.createQName(null, "type3")); - assoc3.setQname(QName.createQName(null, "number3")); - assoc3.setChildNodeName("number3"); - assoc3.setChildNodeNameCrc(2); - assoc3.buildAssociation(containerNode, contentNode2); // check whether the children are pulled in for this - getSession().save(assoc3); - - // flush it - getSession().flush(); - getSession().clear(); - } -} +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.domain.hibernate; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.transaction.UserTransaction; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.ChildAssoc; +import org.alfresco.repo.domain.Node; +import org.alfresco.repo.domain.NodeKey; +import org.alfresco.repo.domain.NodeStatus; +import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.domain.Server; +import org.alfresco.repo.domain.Store; +import org.alfresco.repo.domain.StoreKey; +import org.alfresco.repo.domain.Transaction; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.BaseSpringTest; +import org.alfresco.util.GUID; +import org.hibernate.CacheMode; +import org.hibernate.exception.ConstraintViolationException; +import org.hibernate.exception.GenericJDBCException; + +/** + * Test persistence and retrieval of Hibernate-specific implementations of the + * {@link org.alfresco.repo.domain.Node} interface + * + * @author Derek Hulley + */ +@SuppressWarnings("unused") +public class HibernateNodeTest extends BaseSpringTest +{ + private static final String TEST_NAMESPACE = "http://www.alfresco.org/test/HibernateNodeTest"; + private static int i = 0; + + private Store store; + private Server server; + private Transaction transaction; + + public HibernateNodeTest() + { + } + + protected void onSetUpInTransaction() throws Exception + { + store = new StoreImpl(); + StoreKey storeKey = new StoreKey(StoreRef.PROTOCOL_WORKSPACE, + "TestWorkspace@" + System.currentTimeMillis() + " - " + System.nanoTime()); + store.setKey(storeKey); + // persist so that it is present in the hibernate cache + getSession().save(store); + + server = (Server) getSession().get(ServerImpl.class, new Long(1)); + if (server == null) + { + server = new ServerImpl(); + server.setIpAddress("" + "i_" + System.currentTimeMillis()); + getSession().save(server); + } + transaction = new TransactionImpl(); + transaction.setServer(server); + transaction.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); + getSession().save(transaction); + } + + protected void onTearDownInTransaction() + { + // force a flush to ensure that the database updates succeed + getSession().flush(); + getSession().clear(); + } + + public void testSetUp() throws Exception + { + assertNotNull("Workspace not initialised", store); + } + + public void testGetStore() throws Exception + { + // create a new Node + Node node = new NodeImpl(); + node.setStore(store); + node.setUuid(GUID.generate()); + node.setTypeQName(ContentModel.TYPE_CONTAINER); + + // now it should work + Serializable id = getSession().save(node); + + // throw the reference away and get the a new one for the id + node = (Node) getSession().load(NodeImpl.class, id); + assertNotNull("Node not found", node); + // check that the store has been loaded + Store loadedStore = node.getStore(); + assertNotNull("Store not present on node", loadedStore); + assertEquals("Incorrect store key", store, loadedStore); + } + + public void testNodeStatus() + { + NodeKey key = new NodeKey(store.getKey(), "AAA"); + // create the node status + NodeStatus nodeStatus = new NodeStatusImpl(); + nodeStatus.setKey(key); + nodeStatus.setTransaction(transaction); + getSession().save(nodeStatus); + + // create a new Node + Node node = new NodeImpl(); + node.setStore(store); + node.setUuid(GUID.generate()); + node.setTypeQName(ContentModel.TYPE_CONTAINER); + Serializable nodeId = getSession().save(node); + + // This should all be fine. The node does not HAVE to have a status. + flushAndClear(); + + // set the node + nodeStatus = (NodeStatus) getSession().get(NodeStatusImpl.class, key); + nodeStatus.setNode(node); + flushAndClear(); + + // is the node retrievable? + nodeStatus = (NodeStatus) getSession().get(NodeStatusImpl.class, key); + node = nodeStatus.getNode(); + assertNotNull("Node was not attached to status", node); + // change the values + transaction.setChangeTxnId("txn:456"); + // delete the node + getSession().delete(node); + + try + { + flushAndClear(); + fail("Node status may not refer to non-existent node"); + } + catch(ConstraintViolationException e) + { + // expected + } + catch(GenericJDBCException e) + { + // Sybase + // expected + } + } + + /** + * Check that properties can be persisted and retrieved + */ + public void testProperties() throws Exception + { + // create a new Node + Node node = new NodeImpl(); + node.setStore(store); + node.setUuid(GUID.generate()); + node.setTypeQName(ContentModel.TYPE_CONTAINER); + // give it a property map + Map propertyMap = new HashMap(5); + QName propertyQName = QName.createQName("{}A"); + PropertyValue propertyValue = new PropertyValue(DataTypeDefinition.TEXT, "AAA"); + propertyMap.put(propertyQName, propertyValue); + node.getProperties().putAll(propertyMap); + // persist it + Serializable id = getSession().save(node); + + // throw the reference away and get the a new one for the id + node = (Node) getSession().load(NodeImpl.class, id); + assertNotNull("Node not found", node); + // extract the Map + propertyMap = node.getProperties(); + assertNotNull("Map not persisted", propertyMap); + // ensure that the value is present + assertNotNull("Property value not present in map", QName.createQName("{}A")); + } + + /** + * Check that aspect qnames can be added and removed from a node and that they + * are persisted correctly + */ + public void testAspects() throws Exception + { + // make a real node + Node node = new NodeImpl(); + node.setStore(store); + node.setUuid(GUID.generate()); + node.setTypeQName(ContentModel.TYPE_CMOBJECT); + + // add some aspects + QName aspect1 = QName.createQName(TEST_NAMESPACE, "1"); + QName aspect2 = QName.createQName(TEST_NAMESPACE, "2"); + QName aspect3 = QName.createQName(TEST_NAMESPACE, "3"); + QName aspect4 = QName.createQName(TEST_NAMESPACE, "4"); + Set aspects = node.getAspects(); + aspects.add(aspect1); + aspects.add(aspect2); + aspects.add(aspect3); + aspects.add(aspect4); + assertFalse("Set did not eliminate duplicate aspect qname", aspects.add(aspect4)); + + // persist + Serializable id = getSession().save(node); + + // flush and clear + flushAndClear(); + + // get node and check aspects + node = (Node) getSession().get(NodeImpl.class, id); + assertNotNull("Node not persisted", node); + aspects = node.getAspects(); + assertEquals("Not all aspects persisted", 4, aspects.size()); + } + + public void testChildAssoc() throws Exception + { + // make a content node + Node contentNode = new NodeImpl(); + contentNode.setStore(store); + contentNode.setUuid(GUID.generate()); + contentNode.setTypeQName(ContentModel.TYPE_CONTENT); + Serializable contentNodeId = getSession().save(contentNode); + + // make a container node + Node containerNode = new NodeImpl(); + containerNode.setStore(store); + containerNode.setUuid(GUID.generate()); + containerNode.setTypeQName(ContentModel.TYPE_CONTAINER); + Serializable containerNodeId = getSession().save(containerNode); + // create an association to the content + ChildAssoc assoc1 = new ChildAssocImpl(); + assoc1.setIsPrimary(true); + assoc1.setTypeQName(QName.createQName(null, "type1")); + assoc1.setQname(QName.createQName(null, "number1")); + assoc1.setChildNodeName("number1"); + assoc1.setChildNodeNameCrc(1); + assoc1.buildAssociation(containerNode, contentNode); + getSession().save(assoc1); + + // make another association between the same two parent and child nodes + ChildAssoc assoc2 = new ChildAssocImpl(); + assoc2.setIsPrimary(true); + assoc2.setTypeQName(QName.createQName(null, "type2")); + assoc2.setQname(QName.createQName(null, "number2")); + assoc2.setChildNodeName("number2"); + assoc2.setChildNodeNameCrc(2); + assoc2.buildAssociation(containerNode, contentNode); + getSession().save(assoc2); + + assertFalse("Hashcode incorrent", assoc2.hashCode() == 0); + assertNotSame("Assoc equals failure", assoc1, assoc2); + + // reload the container + containerNode = (Node) getSession().get(NodeImpl.class, containerNodeId); + assertNotNull("Node not found", containerNode); + + // check that we can traverse the association from the child + Collection parentAssocs = contentNode.getParentAssocs(); + assertEquals("Expected exactly 2 parent assocs", 2, parentAssocs.size()); + parentAssocs = new HashSet(parentAssocs); + for (ChildAssoc assoc : parentAssocs) + { + // maintain inverse assoc sets + assoc.removeAssociation(); + // remove the assoc + getSession().delete(assoc); + } + + // check that the child now has zero parents + parentAssocs = contentNode.getParentAssocs(); + assertEquals("Expected exactly 0 parent assocs", 0, parentAssocs.size()); + } + + /** + * Allows tracing of L2 cache + */ + public void testCaching() throws Exception + { + // make a node + Node node = new NodeImpl(); + node.setStore(store); + node.setUuid(GUID.generate()); + node.setTypeQName(ContentModel.TYPE_CONTENT); + Serializable nodeId = getSession().save(node); + + // add some aspects to the node + Set aspects = node.getAspects(); + aspects.add(ContentModel.ASPECT_AUDITABLE); + + // add some properties + Map properties = node.getProperties(); + properties.put(ContentModel.PROP_NAME, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); + + // check that the session hands back the same instance + Node checkNode = (Node) getSession().get(NodeImpl.class, nodeId); + assertNotNull(checkNode); + assertTrue("Node retrieved was not same instance", checkNode == node); + + Set checkAspects = checkNode.getAspects(); + assertTrue("Aspect set retrieved was not the same instance", checkAspects == aspects); + assertEquals("Incorrect number of aspects", 1, checkAspects.size()); + QName checkQName = (QName) checkAspects.toArray()[0]; + assertTrue("QName retrieved was not the same instance", checkQName == ContentModel.ASPECT_AUDITABLE); + + Map checkProperties = checkNode.getProperties(); + assertTrue("Propery map retrieved was not the same instance", checkProperties == properties); + assertTrue("Property not found", checkProperties.containsKey(ContentModel.PROP_NAME)); + + flushAndClear(); + // commit the transaction + setComplete(); + endTransaction(); + + TransactionService transactionService = (TransactionService) applicationContext.getBean("transactionComponent"); + UserTransaction txn = transactionService.getUserTransaction(); + try + { + txn.begin(); + + // check that the L2 cache hands back the same instance + checkNode = (Node) getSession().get(NodeImpl.class, nodeId); + assertNotNull(checkNode); + checkAspects = checkNode.getAspects(); + + txn.commit(); + } + catch (Throwable e) + { + txn.rollback(); + } + } + + /** + * Create some simple parent-child relationships and flush them. Then read them back in without + * using the L2 cache. + */ + public void testQueryJoins() throws Exception + { + getSession().setCacheMode(CacheMode.IGNORE); + + // make a container node + Node containerNode = new NodeImpl(); + containerNode.setStore(store); + containerNode.setUuid(GUID.generate()); + containerNode.setTypeQName(ContentModel.TYPE_CONTAINER); + containerNode.getProperties().put(ContentModel.PROP_AUTHOR, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); + containerNode.getProperties().put(ContentModel.PROP_ARCHIVED_BY, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); + containerNode.getAspects().add(ContentModel.ASPECT_AUDITABLE); + Serializable containerNodeId = getSession().save(containerNode); + NodeKey containerNodeKey = new NodeKey(containerNode.getNodeRef()); + NodeStatus containerNodeStatus = new NodeStatusImpl(); + containerNodeStatus.setKey(containerNodeKey); + containerNodeStatus.setNode(containerNode); + containerNodeStatus.setTransaction(transaction); + getSession().save(containerNodeStatus); + // make content node 1 + Node contentNode1 = new NodeImpl(); + contentNode1.setStore(store); + contentNode1.setUuid(GUID.generate()); + contentNode1.setTypeQName(ContentModel.TYPE_CONTENT); + contentNode1.getProperties().put(ContentModel.PROP_AUTHOR, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); + contentNode1.getProperties().put(ContentModel.PROP_ARCHIVED_BY, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); + contentNode1.getAspects().add(ContentModel.ASPECT_AUDITABLE); + Serializable contentNode1Id = getSession().save(contentNode1); + NodeKey contentNodeKey1 = new NodeKey(contentNode1.getNodeRef()); + NodeStatus contentNodeStatus1 = new NodeStatusImpl(); + contentNodeStatus1.setKey(contentNodeKey1); + contentNodeStatus1.setNode(contentNode1); + contentNodeStatus1.setTransaction(transaction); + getSession().save(contentNodeStatus1); + // make content node 2 + Node contentNode2 = new NodeImpl(); + contentNode2.setStore(store); + contentNode2.setUuid(GUID.generate()); + contentNode2.setTypeQName(ContentModel.TYPE_CONTENT); + Serializable contentNode2Id = getSession().save(contentNode2); + contentNode2.getProperties().put(ContentModel.PROP_AUTHOR, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); + contentNode2.getProperties().put(ContentModel.PROP_ARCHIVED_BY, new PropertyValue(DataTypeDefinition.TEXT, "ABC")); + contentNode2.getAspects().add(ContentModel.ASPECT_AUDITABLE); + NodeKey contentNodeKey2 = new NodeKey(contentNode2.getNodeRef()); + NodeStatus contentNodeStatus2 = new NodeStatusImpl(); + contentNodeStatus2.setKey(contentNodeKey2); + contentNodeStatus2.setNode(contentNode2); + contentNodeStatus2.setTransaction(transaction); + getSession().save(contentNodeStatus2); + // create an association to content 1 + ChildAssoc assoc1 = new ChildAssocImpl(); + assoc1.setIsPrimary(true); + assoc1.setTypeQName(QName.createQName(null, "type1")); + assoc1.setQname(QName.createQName(null, "number1")); + assoc1.setChildNodeName("number1"); + assoc1.setChildNodeNameCrc(1); + assoc1.buildAssociation(containerNode, contentNode1); + getSession().save(assoc1); + // create an association to content 2 + ChildAssoc assoc2 = new ChildAssocImpl(); + assoc2.setIsPrimary(true); + assoc2.setTypeQName(QName.createQName(null, "type2")); + assoc2.setQname(QName.createQName(null, "number2")); + assoc2.setChildNodeName("number2"); + assoc2.setChildNodeNameCrc(2); + assoc2.buildAssociation(containerNode, contentNode2); + getSession().save(assoc2); + + // make sure that there are no entities cached in either L1 or L2 + getSession().flush(); + getSession().clear(); + + // now read the structure back in from the container down + containerNodeStatus = (NodeStatus) getSession().get(NodeStatusImpl.class, containerNodeKey); + containerNode = containerNodeStatus.getNode(); + + // clear out again + getSession().clear(); + + // expect that just the specific property gets removed in the delete statement + getSession().flush(); + getSession().clear(); + + // Create a second association to content 2 + // create an association to content 2 + containerNodeStatus = (NodeStatus) getSession().get(NodeStatusImpl.class, containerNodeKey); + containerNode = containerNodeStatus.getNode(); + contentNodeStatus2 = (NodeStatus) getSession().get(NodeStatusImpl.class, contentNodeKey2); + contentNode2 = contentNodeStatus2.getNode(); + ChildAssoc assoc3 = new ChildAssocImpl(); + assoc3.setIsPrimary(false); + assoc3.setTypeQName(QName.createQName(null, "type3")); + assoc3.setQname(QName.createQName(null, "number3")); + assoc3.setChildNodeName("number3"); + assoc3.setChildNodeNameCrc(2); + assoc3.buildAssociation(containerNode, contentNode2); // check whether the children are pulled in for this + getSession().save(assoc3); + + // flush it + getSession().flush(); + getSession().clear(); + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml index 15fe0ed614..0309f85558 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml @@ -314,65 +314,19 @@ assoc.target.id = :targetId - - select distinct - transaction.changeTxnId - from - org.alfresco.repo.domain.hibernate.TransactionImpl as transaction - where - transaction.changeTxnId > :currentTxnId - order by - transaction.changeTxnId - - - + select - count(transaction.changeTxnId) - from - org.alfresco.repo.domain.hibernate.NodeStatusImpl as status - join status.transaction as transaction - where - status.key.protocol = :storeProtocol and - status.key.identifier = :storeIdentifier and - status.node.id is not null and - transaction.changeTxnId = :changeTxnId - - - - select - status - from - org.alfresco.repo.domain.hibernate.NodeStatusImpl as status - join status.transaction as transaction - where - status.key.protocol = :storeProtocol and - status.key.identifier = :storeIdentifier and - status.node.id is not null and - transaction.changeTxnId = :changeTxnId - - - - select - status - from - org.alfresco.repo.domain.hibernate.NodeStatusImpl as status - join status.transaction as transaction - where - status.key.protocol = :storeProtocol and - status.key.identifier = :storeIdentifier and - status.node.id is null and - transaction.changeTxnId = :changeTxnId - - - - select distinct - props.stringValue + node from org.alfresco.repo.domain.hibernate.NodeImpl as node join - node.properties props + node.properties prop where - props.stringValue like 'contentUrl%' + ( + prop.actualType = :actualTypeString or + prop.actualType = 'SERIALIZABLE' + ) and + prop.persistedType != 'NULL' diff --git a/source/java/org/alfresco/repo/domain/hibernate/Transaction.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/Transaction.hbm.xml index e770f3f26c..61d3314746 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/Transaction.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/Transaction.hbm.xml @@ -59,4 +59,81 @@ server.ipAddress = :ipAddress + + select + max(txn.id) + from + org.alfresco.repo.domain.hibernate.NodeStatusImpl as status + join status.transaction as txn + where + status.key.protocol = :protocol and + status.key.identifier = :identifier + + + + select + count(txn.id) + from + org.alfresco.repo.domain.hibernate.TransactionImpl as txn + + + + :lastTxnId + order by + txn.id + ]]> + + + + select + count(status.key.guid) + from + org.alfresco.repo.domain.hibernate.NodeStatusImpl as status + join status.transaction as txn + where + txn.id = :txnId and + status.node is not null and + status.key.protocol = :protocol and + status.key.identifier = :identifier + + + + select + count(status.key.guid) + from + org.alfresco.repo.domain.hibernate.NodeStatusImpl as status + join status.transaction as txn + where + txn.id = :txnId and + status.node is null and + status.key.protocol = :protocol and + status.key.identifier = :identifier + + + + select + status + from + org.alfresco.repo.domain.hibernate.NodeStatusImpl as status + where + status.transaction.id = :txnId and + status.key.protocol = :protocol and + status.key.identifier = :identifier + + + + select + status + from + org.alfresco.repo.domain.hibernate.NodeStatusImpl as status + where + status.transaction.id = :txnId + + diff --git a/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java b/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java index c3822a51bc..6ab41fa9ff 100644 --- a/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java +++ b/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java @@ -1,535 +1,539 @@ -/* - * Copyright (C) 2006 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.domain.schema; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileWriter; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Writer; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.List; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.i18n.I18NUtil; -import org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch; -import org.alfresco.util.TempFileProvider; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; -import org.hibernate.cfg.Configuration; -import org.hibernate.dialect.Dialect; -import org.hibernate.tool.hbm2ddl.DatabaseMetadata; -import org.hibernate.tool.hbm2ddl.SchemaExport; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.orm.hibernate3.LocalSessionFactoryBean; - -/** - * Bootstraps the schema and schema update. The schema is considered missing if the applied patch table - * is not present, and the schema is considered empty if the applied patch table is empty. - * - * @author Derek Hulley - */ -public class SchemaBootstrap implements ApplicationListener -{ - /** The placeholder for the configured Dialect class name: ${db.script.dialect} */ - private static final String PLACEHOLDER_SCRIPT_DIALECT = "\\$\\{db\\.script\\.dialect\\}"; - - private static final String MSG_EXECUTING_SCRIPT = "schema.update.msg.executing_script"; - private static final String ERR_UPDATE_FAILED = "schema.update.err.update_failed"; - private static final String ERR_VALIDATION_FAILED = "schema.update.err.validation_failed"; - private static final String ERR_SCRIPT_NOT_RUN = "schema.update.err.update_script_not_run"; - private static final String ERR_SCRIPT_NOT_FOUND = "schema.update.err.script_not_found"; - private static final String ERR_STATEMENT_TERMINATOR = "schema.update.err.statement_terminator"; - - private static Log logger = LogFactory.getLog(SchemaBootstrap.class); - - private LocalSessionFactoryBean localSessionFactory; - private String schemaOuputFilename; - private boolean updateSchema; - private List postCreateScriptUrls; - private List validateUpdateScriptPatches; - private List applyUpdateScriptPatches; - - public SchemaBootstrap() - { - postCreateScriptUrls = new ArrayList(1); - validateUpdateScriptPatches = new ArrayList(4); - applyUpdateScriptPatches = new ArrayList(4); - } - - public void setLocalSessionFactory(LocalSessionFactoryBean localSessionFactory) throws BeansException - { - this.localSessionFactory = localSessionFactory; - } - - /** - * Set this to output the full database creation script - * - * @param schemaOuputFilename the name of a file to dump the schema to, or null to ignore - */ - public void setSchemaOuputFilename(String schemaOuputFilename) - { - this.schemaOuputFilename = schemaOuputFilename; - } - - /** - * Set whether to modify the schema or not. Either way, the schema will be validated. - * - * @param updateSchema true to update and validate the schema, otherwise false to just - * validate the schema. Default is true. - */ - public void setUpdateSchema(boolean updateSchema) - { - this.updateSchema = updateSchema; - } - - /** - * Set the scripts that must be executed after the schema has been created. - * - * @param postCreateScriptUrls file URLs - * - * @see #PLACEHOLDER_SCRIPT_DIALECT - */ - public void setPostCreateScriptUrls(List postUpdateScriptUrls) - { - this.postCreateScriptUrls = postUpdateScriptUrls; - } - - /** - * Set the schema script patches that must have been applied. These will not be - * applied to the database. These can be used where the script cannot be - * applied automatically or where a particular upgrade path is no longer supported. - * For example, at version 3.0, the upgrade scripts for version 1.4 may be considered - * unsupported - this doesn't prevent the manual application of the scripts, though. - * - * @param applyUpdateScriptPatches a list of schema patches to check - */ - public void setValidateUpdateScriptPatches(List scriptPatches) - { - this.validateUpdateScriptPatches = scriptPatches; - } - - /** - * Set the schema script patches that may be executed during an update. - * - * @param applyUpdateScriptPatches a list of schema patches to check - */ - public void setApplyUpdateScriptPatches(List scriptPatches) - { - this.applyUpdateScriptPatches = scriptPatches; - } - - public void onApplicationEvent(ApplicationEvent event) - { - if (!(event instanceof ContextRefreshedEvent)) - { - // only work on startup - return; - } - - // do everything in a transaction - Session session = getLocalSessionFactory().openSession(); - Transaction transaction = session.beginTransaction(); - try - { - // make sure that we don't autocommit - Connection connection = session.connection(); - connection.setAutoCommit(false); - - Configuration cfg = localSessionFactory.getConfiguration(); - // dump the schema, if required - if (schemaOuputFilename != null) - { - File schemaOutputFile = new File(schemaOuputFilename); - dumpSchemaCreate(cfg, schemaOutputFile); - } - - // update the schema, if required - if (updateSchema) - { - updateSchema(cfg, session, connection); - } - - // verify that all patches have been applied correctly - checkSchemaPatchScripts(cfg, session, connection, validateUpdateScriptPatches, false); // check scripts - checkSchemaPatchScripts(cfg, session, connection, applyUpdateScriptPatches, false); // check scripts - - // all done successfully - transaction.commit(); - } - catch (Throwable e) - { - try { transaction.rollback(); } catch (Throwable ee) {} - if (updateSchema) - { - throw new AlfrescoRuntimeException(ERR_UPDATE_FAILED, e); - } - else - { - throw new AlfrescoRuntimeException(ERR_VALIDATION_FAILED, e); - } - } - } - - private void dumpSchemaCreate(Configuration cfg, File schemaOutputFile) - { - // if the file exists, delete it - if (schemaOutputFile.exists()) - { - schemaOutputFile.delete(); - } - SchemaExport schemaExport = new SchemaExport(cfg) - .setFormat(true) - .setHaltOnError(true) - .setOutputFile(schemaOutputFile.getAbsolutePath()) - .setDelimiter(";"); - schemaExport.execute(false, false, false, true); - } - - private SessionFactory getLocalSessionFactory() - { - return (SessionFactory) localSessionFactory.getObject(); - } - - /** - * @return Returns the number of applied patches - */ - private int countAppliedPatches(Connection connection) throws Exception - { - Statement stmt = connection.createStatement(); - try - { - ResultSet rs = stmt.executeQuery("select count(id) from alf_applied_patch"); - rs.next(); - int count = rs.getInt(1); - return count; - } - catch (Throwable e) - { - // we'll try another table name - } - finally - { - try { stmt.close(); } catch (Throwable e) {} - } - // for pre-1.4 databases, the table was named differently - stmt = connection.createStatement(); - try - { - ResultSet rs = stmt.executeQuery("select count(id) from applied_patch"); - rs.next(); - int count = rs.getInt(1); - return count; - } - finally - { - try { stmt.close(); } catch (Throwable e) {} - } - } - - /** - * @return Returns the number of applied patches - */ - private boolean didPatchSucceed(Connection connection, String patchId) throws Exception - { - Statement stmt = connection.createStatement(); - try - { - ResultSet rs = stmt.executeQuery("select succeeded from alf_applied_patch where id = '" + patchId + "'"); - if (!rs.next()) - { - return false; - } - boolean succeeded = rs.getBoolean(1); - return succeeded; - } - catch (Throwable e) - { - // we'll try another table name - } - finally - { - try { stmt.close(); } catch (Throwable e) {} - } - // for pre-1.4 databases, the table was named differently - stmt = connection.createStatement(); - try - { - ResultSet rs = stmt.executeQuery("select succeeded from applied_patch where id = '" + patchId + "'"); - if (!rs.next()) - { - return false; - } - boolean succeeded = rs.getBoolean(1); - return succeeded; - } - finally - { - try { stmt.close(); } catch (Throwable e) {} - } - } - - /** - * Builds the schema from scratch or applies the necessary patches to the schema. - */ - private void updateSchema(Configuration cfg, Session session, Connection connection) throws Exception - { - boolean create = false; - try - { - countAppliedPatches(connection); - } - catch (Throwable e) - { - create = true; - } - if (create) - { - // the applied patch table is missing - we assume that all other tables are missing - // perform a full update using Hibernate-generated statements - File tempFile = TempFileProvider.createTempFile("AlfrescoSchemaCreate", ".sql"); - dumpSchemaCreate(cfg, tempFile); - FileInputStream tempInputStream = new FileInputStream(tempFile); - executeScriptFile(cfg, connection, tempInputStream, tempFile.getPath()); - // execute post-create scripts (not patches) - for (String scriptUrl : this.postCreateScriptUrls) - { - executeScriptUrl(cfg, connection, scriptUrl); - } - } - else - { - // we have a database, so just run the update scripts - checkSchemaPatchScripts(cfg, session, connection, validateUpdateScriptPatches, false); // check for scripts that must have been run - checkSchemaPatchScripts(cfg, session, connection, applyUpdateScriptPatches, true); // execute scripts as required - // let Hibernate do any required updates - File tempFile = null; - Writer writer = null; - try - { - final Dialect dialect = Dialect.getDialect(cfg.getProperties()); - DatabaseMetadata metadata = new DatabaseMetadata(connection, dialect); - String[] sqls = cfg.generateSchemaUpdateScript(dialect, metadata); - if (sqls.length > 0) - { - tempFile = TempFileProvider.createTempFile("AlfrescoSchemaUpdate", ".sql"); - writer = new BufferedWriter(new FileWriter(tempFile)); - for (String sql : sqls) - { - writer.append(sql); - writer.append(";\n"); - } - } - } - finally - { - if (writer != null) - { - try {writer.close();} catch (Throwable e) {} - } - } - // execute if there were changes raised by Hibernate - if (tempFile != null) - { - InputStream tempInputStream = new FileInputStream(tempFile); - executeScriptFile(cfg, connection, tempInputStream, tempFile.getPath()); - } - } - } - - /** - * Check that the necessary scripts have been executed against the database - */ - private void checkSchemaPatchScripts( - Configuration cfg, - Session session, - Connection connection, - List scriptPatches, - boolean apply) throws Exception - { - // first check if there have been any applied patches - int appliedPatchCount = countAppliedPatches(connection); - if (appliedPatchCount == 0) - { - // This is a new schema, so upgrade scripts are irrelevant - // and patches will not have been applied yet - return; - } - - for (SchemaUpgradeScriptPatch patch : scriptPatches) - { - final String patchId = patch.getId(); - final String scriptUrl = patch.getScriptUrl(); - - // check if the script was successfully executed - boolean wasSuccessfullyApplied = didPatchSucceed(connection, patchId); - if (wasSuccessfullyApplied) - { - // nothing to do - it has been done before - continue; - } - else if (!apply) - { - // the script was not run and may not be run automatically - throw AlfrescoRuntimeException.create(ERR_SCRIPT_NOT_RUN, scriptUrl); - } - // it wasn't run and it can be run now - executeScriptUrl(cfg, connection, scriptUrl); - } - } - - private void executeScriptUrl(Configuration cfg, Connection connection, String scriptUrl) throws Exception - { - Dialect dialect = Dialect.getDialect(cfg.getProperties()); - InputStream scriptInputStream = getScriptInputStream(dialect.getClass(), scriptUrl); - // check that it exists - if (scriptInputStream == null) - { - throw AlfrescoRuntimeException.create(ERR_SCRIPT_NOT_FOUND, scriptUrl); - } - // now execute it - executeScriptFile(cfg, connection, scriptInputStream, scriptUrl); - } - - /** - * Replaces the dialect placeholder in the script URL and attempts to find a file for - * it. If not found, the dialect hierarchy will be walked until a compatible script is - * found. This makes it possible to have scripts that are generic to all dialects. - * - * @return Returns an input stream onto the script, otherwise null - */ - private InputStream getScriptInputStream(Class dialectClazz, String scriptUrl) throws Exception - { - // replace the dialect placeholder - String dialectScriptUrl = scriptUrl.replaceAll(PLACEHOLDER_SCRIPT_DIALECT, dialectClazz.getName()); - // get a handle on the resource - ResourcePatternResolver rpr = new PathMatchingResourcePatternResolver(this.getClass().getClassLoader()); - Resource resource = rpr.getResource(dialectScriptUrl); - if (!resource.exists()) - { - // it wasn't found. Get the superclass of the dialect and try again - Class superClazz = dialectClazz.getSuperclass(); - if (Dialect.class.isAssignableFrom(superClazz)) - { - // we still have a Dialect - try again - return getScriptInputStream(superClazz, scriptUrl); - } - else - { - // we have exhausted all options - return null; - } - } - else - { - // we have a handle to it - return resource.getInputStream(); - } - } - - private void executeScriptFile( - Configuration cfg, - Connection connection, - InputStream scriptInputStream, - String scriptUrl) throws Exception - { - logger.info(I18NUtil.getMessage(MSG_EXECUTING_SCRIPT, scriptUrl)); - - BufferedReader reader = new BufferedReader(new InputStreamReader(scriptInputStream, "UTF8")); - try - { - int line = 0; - // loop through all statements - StringBuilder sb = new StringBuilder(1024); - while(true) - { - String sql = reader.readLine(); - line++; - - if (sql == null) - { - // nothing left in the file - break; - } - - // trim it - sql = sql.trim(); - if (sql.length() == 0 || - sql.startsWith( "--" ) || - sql.startsWith( "//" ) || - sql.startsWith( "/*" ) ) - { - if (sb.length() > 0) - { - // we have an unterminated statement - throw AlfrescoRuntimeException.create(ERR_STATEMENT_TERMINATOR, (line - 1), scriptUrl); - } - // there has not been anything to execute - it's just a comment line - continue; - } - // have we reached the end of a statement? - boolean execute = false; - if (sql.endsWith(";")) - { - sql = sql.substring(0, sql.length() - 1); - execute = true; - } - // append to the statement being built up - sb.append(" ").append(sql); - // execute, if required - if (execute) - { - Statement stmt = connection.createStatement(); - try - { - sql = sb.toString(); - if (logger.isDebugEnabled()) - { - logger.debug("Executing statment: " + sql); - } - stmt.execute(sql); - sb = new StringBuilder(1024); - } - finally - { - try { stmt.close(); } catch (Throwable e) {} - } - } - } - } - finally - { - try { reader.close(); } catch (Throwable e) {} - try { scriptInputStream.close(); } catch (Throwable e) {} - } - } -} +/* + * Copyright (C) 2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.domain.schema; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Writer; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.i18n.I18NUtil; +import org.alfresco.repo.admin.patch.impl.SchemaUpgradeScriptPatch; +import org.alfresco.util.TempFileProvider; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; +import org.hibernate.dialect.Dialect; +import org.hibernate.tool.hbm2ddl.DatabaseMetadata; +import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.orm.hibernate3.LocalSessionFactoryBean; + +/** + * Bootstraps the schema and schema update. The schema is considered missing if the applied patch table + * is not present, and the schema is considered empty if the applied patch table is empty. + * + * @author Derek Hulley + */ +public class SchemaBootstrap implements ApplicationListener +{ + /** The placeholder for the configured Dialect class name: ${db.script.dialect} */ + private static final String PLACEHOLDER_SCRIPT_DIALECT = "\\$\\{db\\.script\\.dialect\\}"; + + private static final String MSG_EXECUTING_SCRIPT = "schema.update.msg.executing_script"; + private static final String ERR_UPDATE_FAILED = "schema.update.err.update_failed"; + private static final String ERR_VALIDATION_FAILED = "schema.update.err.validation_failed"; + private static final String ERR_SCRIPT_NOT_RUN = "schema.update.err.update_script_not_run"; + private static final String ERR_SCRIPT_NOT_FOUND = "schema.update.err.script_not_found"; + private static final String ERR_STATEMENT_TERMINATOR = "schema.update.err.statement_terminator"; + + private static Log logger = LogFactory.getLog(SchemaBootstrap.class); + + private LocalSessionFactoryBean localSessionFactory; + private String schemaOuputFilename; + private boolean updateSchema; + private List postCreateScriptUrls; + private List validateUpdateScriptPatches; + private List applyUpdateScriptPatches; + + public SchemaBootstrap() + { + postCreateScriptUrls = new ArrayList(1); + validateUpdateScriptPatches = new ArrayList(4); + applyUpdateScriptPatches = new ArrayList(4); + } + + public void setLocalSessionFactory(LocalSessionFactoryBean localSessionFactory) throws BeansException + { + this.localSessionFactory = localSessionFactory; + } + + /** + * Set this to output the full database creation script + * + * @param schemaOuputFilename the name of a file to dump the schema to, or null to ignore + */ + public void setSchemaOuputFilename(String schemaOuputFilename) + { + this.schemaOuputFilename = schemaOuputFilename; + } + + /** + * Set whether to modify the schema or not. Either way, the schema will be validated. + * + * @param updateSchema true to update and validate the schema, otherwise false to just + * validate the schema. Default is true. + */ + public void setUpdateSchema(boolean updateSchema) + { + this.updateSchema = updateSchema; + } + + /** + * Set the scripts that must be executed after the schema has been created. + * + * @param postCreateScriptUrls file URLs + * + * @see #PLACEHOLDER_SCRIPT_DIALECT + */ + public void setPostCreateScriptUrls(List postUpdateScriptUrls) + { + this.postCreateScriptUrls = postUpdateScriptUrls; + } + + /** + * Set the schema script patches that must have been applied. These will not be + * applied to the database. These can be used where the script cannot be + * applied automatically or where a particular upgrade path is no longer supported. + * For example, at version 3.0, the upgrade scripts for version 1.4 may be considered + * unsupported - this doesn't prevent the manual application of the scripts, though. + * + * @param applyUpdateScriptPatches a list of schema patches to check + */ + public void setValidateUpdateScriptPatches(List scriptPatches) + { + this.validateUpdateScriptPatches = scriptPatches; + } + + /** + * Set the schema script patches that may be executed during an update. + * + * @param applyUpdateScriptPatches a list of schema patches to check + */ + public void setApplyUpdateScriptPatches(List scriptPatches) + { + this.applyUpdateScriptPatches = scriptPatches; + } + + public void onApplicationEvent(ApplicationEvent event) + { + if (!(event instanceof ContextRefreshedEvent)) + { + // only work on startup + return; + } + + // do everything in a transaction + Session session = getLocalSessionFactory().openSession(); + Transaction transaction = session.beginTransaction(); + try + { + // make sure that we don't autocommit + Connection connection = session.connection(); + connection.setAutoCommit(false); + + Configuration cfg = localSessionFactory.getConfiguration(); + // dump the schema, if required + if (schemaOuputFilename != null) + { + File schemaOutputFile = new File(schemaOuputFilename); + dumpSchemaCreate(cfg, schemaOutputFile); + } + + // update the schema, if required + if (updateSchema) + { + updateSchema(cfg, session, connection); + } + + // verify that all patches have been applied correctly + checkSchemaPatchScripts(cfg, session, connection, validateUpdateScriptPatches, false); // check scripts + checkSchemaPatchScripts(cfg, session, connection, applyUpdateScriptPatches, false); // check scripts + + // all done successfully + transaction.commit(); + } + catch (Throwable e) + { + try { transaction.rollback(); } catch (Throwable ee) {} + if (updateSchema) + { + throw new AlfrescoRuntimeException(ERR_UPDATE_FAILED, e); + } + else + { + throw new AlfrescoRuntimeException(ERR_VALIDATION_FAILED, e); + } + } + } + + private void dumpSchemaCreate(Configuration cfg, File schemaOutputFile) + { + // if the file exists, delete it + if (schemaOutputFile.exists()) + { + schemaOutputFile.delete(); + } + SchemaExport schemaExport = new SchemaExport(cfg) + .setFormat(true) + .setHaltOnError(true) + .setOutputFile(schemaOutputFile.getAbsolutePath()) + .setDelimiter(";"); + schemaExport.execute(false, false, false, true); + } + + private SessionFactory getLocalSessionFactory() + { + return (SessionFactory) localSessionFactory.getObject(); + } + + /** + * @return Returns the number of applied patches + */ + private int countAppliedPatches(Connection connection) throws Exception + { + Statement stmt = connection.createStatement(); + try + { + ResultSet rs = stmt.executeQuery("select count(id) from alf_applied_patch"); + rs.next(); + int count = rs.getInt(1); + return count; + } + catch (Throwable e) + { + // we'll try another table name + } + finally + { + try { stmt.close(); } catch (Throwable e) {} + } + // for pre-1.4 databases, the table was named differently + stmt = connection.createStatement(); + try + { + ResultSet rs = stmt.executeQuery("select count(id) from applied_patch"); + rs.next(); + int count = rs.getInt(1); + return count; + } + finally + { + try { stmt.close(); } catch (Throwable e) {} + } + } + + /** + * @return Returns the number of applied patches + */ + private boolean didPatchSucceed(Connection connection, String patchId) throws Exception + { + Statement stmt = connection.createStatement(); + try + { + ResultSet rs = stmt.executeQuery("select succeeded from alf_applied_patch where id = '" + patchId + "'"); + if (!rs.next()) + { + return false; + } + boolean succeeded = rs.getBoolean(1); + return succeeded; + } + catch (Throwable e) + { + // we'll try another table name + } + finally + { + try { stmt.close(); } catch (Throwable e) {} + } + // for pre-1.4 databases, the table was named differently + stmt = connection.createStatement(); + try + { + ResultSet rs = stmt.executeQuery("select succeeded from applied_patch where id = '" + patchId + "'"); + if (!rs.next()) + { + return false; + } + boolean succeeded = rs.getBoolean(1); + return succeeded; + } + finally + { + try { stmt.close(); } catch (Throwable e) {} + } + } + + /** + * Builds the schema from scratch or applies the necessary patches to the schema. + */ + private void updateSchema(Configuration cfg, Session session, Connection connection) throws Exception + { + boolean create = false; + try + { + countAppliedPatches(connection); + } + catch (Throwable e) + { + create = true; + } + if (create) + { + // Get the dialect + final Dialect dialect = Dialect.getDialect(cfg.getProperties()); + String dialectStr = dialect.getClass().getName(); + + // the applied patch table is missing - we assume that all other tables are missing + // perform a full update using Hibernate-generated statements + File tempFile = TempFileProvider.createTempFile("AlfrescoSchemaCreate-" + dialectStr + "-", ".sql"); + dumpSchemaCreate(cfg, tempFile); + FileInputStream tempInputStream = new FileInputStream(tempFile); + executeScriptFile(cfg, connection, tempInputStream, tempFile.getPath()); + // execute post-create scripts (not patches) + for (String scriptUrl : this.postCreateScriptUrls) + { + executeScriptUrl(cfg, connection, scriptUrl); + } + } + else + { + // we have a database, so just run the update scripts + checkSchemaPatchScripts(cfg, session, connection, validateUpdateScriptPatches, false); // check for scripts that must have been run + checkSchemaPatchScripts(cfg, session, connection, applyUpdateScriptPatches, true); // execute scripts as required + // let Hibernate do any required updates + File tempFile = null; + Writer writer = null; + try + { + final Dialect dialect = Dialect.getDialect(cfg.getProperties()); + DatabaseMetadata metadata = new DatabaseMetadata(connection, dialect); + String[] sqls = cfg.generateSchemaUpdateScript(dialect, metadata); + if (sqls.length > 0) + { + tempFile = TempFileProvider.createTempFile("AlfrescoSchemaUpdate", ".sql"); + writer = new BufferedWriter(new FileWriter(tempFile)); + for (String sql : sqls) + { + writer.append(sql); + writer.append(";\n"); + } + } + } + finally + { + if (writer != null) + { + try {writer.close();} catch (Throwable e) {} + } + } + // execute if there were changes raised by Hibernate + if (tempFile != null) + { + InputStream tempInputStream = new FileInputStream(tempFile); + executeScriptFile(cfg, connection, tempInputStream, tempFile.getPath()); + } + } + } + + /** + * Check that the necessary scripts have been executed against the database + */ + private void checkSchemaPatchScripts( + Configuration cfg, + Session session, + Connection connection, + List scriptPatches, + boolean apply) throws Exception + { + // first check if there have been any applied patches + int appliedPatchCount = countAppliedPatches(connection); + if (appliedPatchCount == 0) + { + // This is a new schema, so upgrade scripts are irrelevant + // and patches will not have been applied yet + return; + } + + for (SchemaUpgradeScriptPatch patch : scriptPatches) + { + final String patchId = patch.getId(); + final String scriptUrl = patch.getScriptUrl(); + + // check if the script was successfully executed + boolean wasSuccessfullyApplied = didPatchSucceed(connection, patchId); + if (wasSuccessfullyApplied) + { + // nothing to do - it has been done before + continue; + } + else if (!apply) + { + // the script was not run and may not be run automatically + throw AlfrescoRuntimeException.create(ERR_SCRIPT_NOT_RUN, scriptUrl); + } + // it wasn't run and it can be run now + executeScriptUrl(cfg, connection, scriptUrl); + } + } + + private void executeScriptUrl(Configuration cfg, Connection connection, String scriptUrl) throws Exception + { + Dialect dialect = Dialect.getDialect(cfg.getProperties()); + InputStream scriptInputStream = getScriptInputStream(dialect.getClass(), scriptUrl); + // check that it exists + if (scriptInputStream == null) + { + throw AlfrescoRuntimeException.create(ERR_SCRIPT_NOT_FOUND, scriptUrl); + } + // now execute it + executeScriptFile(cfg, connection, scriptInputStream, scriptUrl); + } + + /** + * Replaces the dialect placeholder in the script URL and attempts to find a file for + * it. If not found, the dialect hierarchy will be walked until a compatible script is + * found. This makes it possible to have scripts that are generic to all dialects. + * + * @return Returns an input stream onto the script, otherwise null + */ + private InputStream getScriptInputStream(Class dialectClazz, String scriptUrl) throws Exception + { + // replace the dialect placeholder + String dialectScriptUrl = scriptUrl.replaceAll(PLACEHOLDER_SCRIPT_DIALECT, dialectClazz.getName()); + // get a handle on the resource + ResourcePatternResolver rpr = new PathMatchingResourcePatternResolver(this.getClass().getClassLoader()); + Resource resource = rpr.getResource(dialectScriptUrl); + if (!resource.exists()) + { + // it wasn't found. Get the superclass of the dialect and try again + Class superClazz = dialectClazz.getSuperclass(); + if (Dialect.class.isAssignableFrom(superClazz)) + { + // we still have a Dialect - try again + return getScriptInputStream(superClazz, scriptUrl); + } + else + { + // we have exhausted all options + return null; + } + } + else + { + // we have a handle to it + return resource.getInputStream(); + } + } + + private void executeScriptFile( + Configuration cfg, + Connection connection, + InputStream scriptInputStream, + String scriptUrl) throws Exception + { + logger.info(I18NUtil.getMessage(MSG_EXECUTING_SCRIPT, scriptUrl)); + + BufferedReader reader = new BufferedReader(new InputStreamReader(scriptInputStream, "UTF8")); + try + { + int line = 0; + // loop through all statements + StringBuilder sb = new StringBuilder(1024); + while(true) + { + String sql = reader.readLine(); + line++; + + if (sql == null) + { + // nothing left in the file + break; + } + + // trim it + sql = sql.trim(); + if (sql.length() == 0 || + sql.startsWith( "--" ) || + sql.startsWith( "//" ) || + sql.startsWith( "/*" ) ) + { + if (sb.length() > 0) + { + // we have an unterminated statement + throw AlfrescoRuntimeException.create(ERR_STATEMENT_TERMINATOR, (line - 1), scriptUrl); + } + // there has not been anything to execute - it's just a comment line + continue; + } + // have we reached the end of a statement? + boolean execute = false; + if (sql.endsWith(";")) + { + sql = sql.substring(0, sql.length() - 1); + execute = true; + } + // append to the statement being built up + sb.append(" ").append(sql); + // execute, if required + if (execute) + { + Statement stmt = connection.createStatement(); + try + { + sql = sb.toString(); + if (logger.isDebugEnabled()) + { + logger.debug("Executing statment: " + sql); + } + stmt.execute(sql); + sb = new StringBuilder(1024); + } + finally + { + try { stmt.close(); } catch (Throwable e) {} + } + } + } + } + finally + { + try { reader.close(); } catch (Throwable e) {} + try { scriptInputStream.close(); } catch (Throwable e) {} + } + } +} diff --git a/source/java/org/alfresco/repo/jscript/Actions.java b/source/java/org/alfresco/repo/jscript/Actions.java index 818f52d130..b371b1b5aa 100644 --- a/source/java/org/alfresco/repo/jscript/Actions.java +++ b/source/java/org/alfresco/repo/jscript/Actions.java @@ -202,7 +202,7 @@ public final class Actions implements Scopeable @SuppressWarnings("synthetic-access") public void execute(Node node) { - if (this.parameters.isModified()) + if (this.parameters != null && this.parameters.isModified()) { Map actionParams = action.getParameterValues(); actionParams.clear(); diff --git a/source/java/org/alfresco/repo/jscript/Node.java b/source/java/org/alfresco/repo/jscript/Node.java index 25226c1629..daeb82ed3f 100644 --- a/source/java/org/alfresco/repo/jscript/Node.java +++ b/source/java/org/alfresco/repo/jscript/Node.java @@ -79,6 +79,11 @@ import org.springframework.util.StringUtils; */ public class Node implements Serializable, Scopeable { + /** + * Comment for serialVersionUID + */ + private static final long serialVersionUID = -3378946227712939600L; + private static Log logger = LogFactory.getLog(Node.class); private final static String NAMESPACE_BEGIN = "" + QName.NAMESPACE_BEGIN; @@ -885,6 +890,43 @@ public class Node implements Serializable, Scopeable this.services.getPermissionService().deletePermission(this.nodeRef, authority, permission); } + // ------------- + // Ownership API + + /** + * Set the owner of the node + */ + public void setOwner(String userId) + { + this.services.getOwnableService().setOwner(this.nodeRef, userId); + } + + /** + * Take ownership of the node. + */ + public void takeOwnership() + { + this.services.getOwnableService().takeOwnership(this.nodeRef); + } + + /** + * Get the owner of the node. + * @return + */ + public String getOwner() + { + return this.services.getOwnableService().getOwner(this.nodeRef); + } + + /** + * Make owner available as a property. + * + * @return + */ + public String jsGet_owner() + { + return getOwner(); + } // ------------------------------------------------------------------------------ // Create and Modify API @@ -1645,8 +1687,11 @@ public class Node implements Serializable, Scopeable { if (this.nodeService.exists(nodeRef)) { + // TODO: DC: Allow debug output of property values - for now it's disabled as this could potentially + // follow a large network of nodes. Unfortunately, JBPM issues unprotected debug statements + // where node.toString is used - will request this is fixed in next release of JBPM. return "Node Type: " + getType() + - "\nNode Properties: " + this.getProperties().toString() + + "\nNode Properties: " + this.getProperties().size() + "\nNode Aspects: " + this.getAspects().toString(); } else diff --git a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java index 4fe89d582b..6d5eff338d 100644 --- a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java +++ b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java @@ -73,7 +73,11 @@ public class FileFolderServiceImpl implements FileFolderService /** Shallow search for all files and folders */ private static final String LUCENE_QUERY_SHALLOW_ALL = "+PARENT:\"${cm:parent}\"" + - "-TYPE:\"" + ContentModel.TYPE_SYSTEM_FOLDER + "\" "; + "-TYPE:\"" + ContentModel.TYPE_SYSTEM_FOLDER + "\" " + + "+(" + + "TYPE:\"" + ContentModel.TYPE_CONTENT + "\" " + + "TYPE:\"" + ContentModel.TYPE_FOLDER + "\" " + + ")"; /** Shallow search for all files and folders */ private static final String LUCENE_QUERY_SHALLOW_FOLDERS = diff --git a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java index 279cdb5922..c06659c665 100644 --- a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java +++ b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java @@ -28,6 +28,7 @@ import junit.framework.TestCase; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; +import org.alfresco.repo.node.integrity.IntegrityChecker; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.model.FileExistsException; @@ -91,6 +92,9 @@ public class FileFolderServiceImplTest extends TestCase txn = transactionService.getUserTransaction(); txn.begin(); + // downgrade integrity + IntegrityChecker.setWarnInTransaction(); + // authenticate authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName()); diff --git a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java index f6de57d293..6dd08e7ca8 100644 --- a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java +++ b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java @@ -35,6 +35,7 @@ import org.alfresco.repo.dictionary.M2Model; import org.alfresco.repo.domain.hibernate.ChildAssocImpl; import org.alfresco.repo.domain.hibernate.NodeImpl; import org.alfresco.repo.node.db.NodeDaoService; +import org.alfresco.repo.node.integrity.IntegrityChecker; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent; @@ -161,6 +162,9 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis()); rootNodeRef = nodeService.getRootNode(storeRef); + + // downgrade integrity checks + IntegrityChecker.setWarnInTransaction(); } @Override diff --git a/source/java/org/alfresco/repo/node/PerformanceNodeServiceTest.java b/source/java/org/alfresco/repo/node/PerformanceNodeServiceTest.java index 8935297d7c..51810f9c1f 100644 --- a/source/java/org/alfresco/repo/node/PerformanceNodeServiceTest.java +++ b/source/java/org/alfresco/repo/node/PerformanceNodeServiceTest.java @@ -27,6 +27,7 @@ import org.alfresco.model.ContentModel; import org.alfresco.repo.dictionary.DictionaryComponent; import org.alfresco.repo.dictionary.DictionaryDAO; import org.alfresco.repo.dictionary.M2Model; +import org.alfresco.repo.node.integrity.IntegrityChecker; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.TransactionUtil; import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; @@ -160,6 +161,7 @@ public class PerformanceNodeServiceTest extends TestCase { public Object doWork() { + IntegrityChecker.setWarnInTransaction(); buildNodeChildren(rootNodeRef, 1, testDepth, testChildCount); return null; } diff --git a/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java b/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java index d689dd9912..1ac6c4a274 100644 --- a/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java +++ b/source/java/org/alfresco/repo/node/archive/ArchiveAndRestoreTest.java @@ -29,6 +29,7 @@ import junit.framework.TestCase; import org.alfresco.model.ContentModel; import org.alfresco.repo.node.StoreArchiveMap; import org.alfresco.repo.node.archive.RestoreNodeReport.RestoreStatus; +import org.alfresco.repo.node.integrity.IntegrityChecker; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.service.ServiceRegistry; @@ -114,6 +115,9 @@ public class ArchiveAndRestoreTest extends TestCase txn = transactionService.getUserTransaction(); txn.begin(); + // downgrade integrity checks + IntegrityChecker.setWarnInTransaction(); + try { authenticationComponent.setSystemUserAsCurrentUser(); diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index 0726a6a0dc..b92cc1f17e 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -1,1823 +1,1820 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.node.db; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Stack; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.model.ContentModel; -import org.alfresco.repo.domain.ChildAssoc; -import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.NodeAssoc; -import org.alfresco.repo.domain.NodeStatus; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.Store; -import org.alfresco.repo.node.AbstractNodeServiceImpl; -import org.alfresco.repo.node.StoreArchiveMap; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport; -import org.alfresco.service.cmr.dictionary.AspectDefinition; -import org.alfresco.service.cmr.dictionary.AssociationDefinition; -import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition; -import org.alfresco.service.cmr.dictionary.ClassDefinition; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.dictionary.InvalidAspectException; -import org.alfresco.service.cmr.dictionary.InvalidTypeException; -import org.alfresco.service.cmr.dictionary.PropertyDefinition; -import org.alfresco.service.cmr.dictionary.TypeDefinition; -import org.alfresco.service.cmr.repository.AssociationExistsException; -import org.alfresco.service.cmr.repository.AssociationRef; -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.InvalidNodeRefException; -import org.alfresco.service.cmr.repository.InvalidStoreRefException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.repository.Path; -import org.alfresco.service.cmr.repository.StoreExistsException; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.repository.NodeRef.Status; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.service.namespace.QNamePattern; -import org.alfresco.util.ParameterCheck; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.util.Assert; - -/** - * Node service using database persistence layer to fulfill functionality - * - * @author Derek Hulley - */ -public class DbNodeServiceImpl extends AbstractNodeServiceImpl -{ - private static Log logger = LogFactory.getLog(DbNodeServiceImpl.class); - private static Log loggerPaths = LogFactory.getLog(DbNodeServiceImpl.class.getName() + ".paths"); - - private NodeDaoService nodeDaoService; - private StoreArchiveMap storeArchiveMap; - private NodeService avmNodeService; - - public DbNodeServiceImpl() - { - storeArchiveMap = new StoreArchiveMap(); // in case it is not set - } - - public void setNodeDaoService(NodeDaoService nodeDaoService) - { - this.nodeDaoService = nodeDaoService; - } - - public void setStoreArchiveMap(StoreArchiveMap storeArchiveMap) - { - this.storeArchiveMap = storeArchiveMap; - } - - public void setAvmNodeService(NodeService avmNodeService) - { - this.avmNodeService = avmNodeService; - } - - /** - * Performs a null-safe get of the node - * - * @param nodeRef the node to retrieve - * @return Returns the node entity (never null) - * @throws InvalidNodeRefException if the referenced node could not be found - */ - private Node getNodeNotNull(NodeRef nodeRef) throws InvalidNodeRefException - { - Node unchecked = nodeDaoService.getNode(nodeRef); - if (unchecked == null) - { - throw new InvalidNodeRefException("Node does not exist: " + nodeRef, nodeRef); - } - return unchecked; - } - - public boolean exists(StoreRef storeRef) - { - Store store = nodeDaoService.getStore(storeRef.getProtocol(), storeRef.getIdentifier()); - boolean exists = (store != null); - // done - return exists; - } - - public boolean exists(NodeRef nodeRef) - { - Node node = nodeDaoService.getNode(nodeRef); - boolean exists = (node != null); - // done - return exists; - } - - public Status getNodeStatus(NodeRef nodeRef) - { - NodeStatus nodeStatus = nodeDaoService.getNodeStatus(nodeRef, false); - if (nodeStatus == null) // node never existed - { - return null; - } - else - { - return new NodeRef.Status( - nodeStatus.getTransaction().getChangeTxnId(), - nodeStatus.isDeleted()); - } - } - - /** - * @see NodeDaoService#getStores() - */ - public List getStores() - { - List stores = nodeDaoService.getStores(); - List storeRefs = new ArrayList(stores.size()); - for (Store store : stores) - { - storeRefs.add(store.getStoreRef()); - } - // Now get the AVMStores. - List avmStores = avmNodeService.getStores(); - storeRefs.addAll(avmStores); - // Return them all. - return storeRefs; - } - - /** - * Defers to the typed service - * @see StoreDaoService#createWorkspace(String) - */ - public StoreRef createStore(String protocol, String identifier) - { - StoreRef storeRef = new StoreRef(protocol, identifier); - // check that the store does not already exist - Store store = nodeDaoService.getStore(protocol, identifier); - if (store != null) - { - throw new StoreExistsException("Unable to create a store that already exists: " + storeRef, storeRef); - } - - // invoke policies - invokeBeforeCreateStore(ContentModel.TYPE_STOREROOT, storeRef); - - // create a new one - store = nodeDaoService.createStore(protocol, identifier); - // get the root node - Node rootNode = store.getRootNode(); - // assign the root aspect - this is expected of all roots, even store roots - addAspect(rootNode.getNodeRef(), - ContentModel.ASPECT_ROOT, - Collections.emptyMap()); - - // invoke policies - invokeOnCreateStore(rootNode.getNodeRef()); - - // done - if (!store.getStoreRef().equals(storeRef)) - { - throw new RuntimeException("Incorrect store reference"); - } - return storeRef; - } - - public NodeRef getRootNode(StoreRef storeRef) throws InvalidStoreRefException - { - Store store = nodeDaoService.getStore(storeRef.getProtocol(), storeRef.getIdentifier()); - if (store == null) - { - throw new InvalidStoreRefException("Store does not exist", storeRef); - } - // get the root - Node node = store.getRootNode(); - if (node == null) - { - throw new InvalidStoreRefException("Store does not have a root node", storeRef); - } - NodeRef nodeRef = node.getNodeRef(); - // done - return nodeRef; - } - - /** - * @see #createNode(NodeRef, QName, QName, QName, Map) - */ - public ChildAssociationRef createNode( - NodeRef parentRef, - QName assocTypeQName, - QName assocQName, - QName nodeTypeQName) - { - return this.createNode(parentRef, assocTypeQName, assocQName, nodeTypeQName, null); - } - - /** - * @see org.alfresco.service.cmr.repository.NodeService#createNode(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName, java.util.Map) - */ - public ChildAssociationRef createNode( - NodeRef parentRef, - QName assocTypeQName, - QName assocQName, - QName nodeTypeQName, - Map properties) - { - Assert.notNull(parentRef); - Assert.notNull(assocTypeQName); - Assert.notNull(assocQName); - - // null property map is allowed - if (properties == null) - { - properties = new HashMap(); - } - else - { - // Copy the incomming property map since we may need to modify it later - properties = new HashMap(properties); - } - - // Invoke policy behaviour - invokeBeforeUpdateNode(parentRef); - invokeBeforeCreateNode(parentRef, assocTypeQName, assocQName, nodeTypeQName); - - // get the store that the parent belongs to - StoreRef storeRef = parentRef.getStoreRef(); - Store store = nodeDaoService.getStore(storeRef.getProtocol(), storeRef.getIdentifier()); - if (store == null) - { - throw new RuntimeException("No store found for parent node: " + parentRef); - } - - // check the node type - TypeDefinition nodeTypeDef = dictionaryService.getType(nodeTypeQName); - if (nodeTypeDef == null) - { - throw new InvalidTypeException(nodeTypeQName); - } - - // get/generate an ID for the node - String newId = generateGuid(properties); - - // create the node instance - Node childNode = nodeDaoService.newNode(store, newId, nodeTypeQName); - - // get the parent node - Node parentNode = getNodeNotNull(parentRef); - - // Set the default property values - addDefaultPropertyValues(nodeTypeDef, properties); - - // Add the default aspects to the node - addDefaultAspects(nodeTypeDef, childNode, properties); - - // set the properties - it is a new node so only set properties if there are any - Map propertiesBefore = getPropertiesImpl(childNode); - Map propertiesAfter = null; - if (properties.size() > 0) - { - propertiesAfter = setPropertiesImpl(childNode, properties); - } - - // create the association - ChildAssoc childAssoc = nodeDaoService.newChildAssoc( - parentNode, - childNode, - true, - assocTypeQName, - assocQName); - setChildUniqueName(childNode); // ensure uniqueness - ChildAssociationRef childAssocRef = childAssoc.getChildAssocRef(); - - // Invoke policy behaviour - invokeOnCreateNode(childAssocRef); - invokeOnUpdateNode(parentRef); - if (propertiesAfter != null) - { - invokeOnUpdateProperties(childAssocRef.getChildRef(), propertiesBefore, propertiesAfter); - } - - // done - return childAssocRef; - } - - /** - * Add the default aspects to a given node - * - * @param nodeTypeDef - */ - private void addDefaultAspects(ClassDefinition classDefinition, Node node, Map properties) - { - NodeRef nodeRef = node.getNodeRef(); - - // get the mandatory aspects for the node type - List defaultAspectDefs = classDefinition.getDefaultAspects(); - - // add all the aspects to the node - Set nodeAspects = node.getAspects(); - for (AspectDefinition defaultAspectDef : defaultAspectDefs) - { - invokeBeforeAddAspect(nodeRef, defaultAspectDef.getName()); - nodeAspects.add(defaultAspectDef.getName()); - addDefaultPropertyValues(defaultAspectDef, properties); - invokeOnAddAspect(nodeRef, defaultAspectDef.getName()); - - // Now add any default aspects for this aspect - addDefaultAspects(defaultAspectDef, node, properties); - } - } - - /** - * Drops the old primary association and creates a new one - */ - public ChildAssociationRef moveNode( - NodeRef nodeToMoveRef, - NodeRef newParentRef, - QName assocTypeQName, - QName assocQName) - throws InvalidNodeRefException - { - Assert.notNull(nodeToMoveRef); - Assert.notNull(newParentRef); - Assert.notNull(assocTypeQName); - Assert.notNull(assocQName); - - // check the node references - Node nodeToMove = getNodeNotNull(nodeToMoveRef); - Node newParentNode = getNodeNotNull(newParentRef); - // get the primary parent assoc - ChildAssoc oldAssoc = nodeDaoService.getPrimaryParentAssoc(nodeToMove); - ChildAssociationRef oldAssocRef = oldAssoc.getChildAssocRef(); - // get the old parent - Node oldParentNode = oldAssoc.getParent(); - - boolean movingStore = !nodeToMoveRef.getStoreRef().equals(newParentRef.getStoreRef()); - - // data needed for policy invocation - QName nodeToMoveTypeQName = nodeToMove.getTypeQName(); - Set nodeToMoveAspects = nodeToMove.getAspects(); - - // Invoke policy behaviour - if (movingStore) - { - invokeBeforeDeleteNode(nodeToMoveRef); - invokeBeforeCreateNode(newParentRef, assocTypeQName, assocQName, nodeToMoveTypeQName); - } - else - { - invokeBeforeDeleteChildAssociation(oldAssocRef); - invokeBeforeCreateChildAssociation(newParentRef, nodeToMoveRef, assocTypeQName, assocQName); - invokeBeforeUpdateNode(oldParentNode.getNodeRef()); // old parent will be updated - invokeBeforeUpdateNode(newParentRef); // new parent ditto - } - - // remove the child assoc from the old parent - // don't cascade as we will still need the node afterwards - nodeDaoService.deleteChildAssoc(oldAssoc, false); - - // create a new assoc - ChildAssoc newAssoc = nodeDaoService.newChildAssoc( - newParentNode, - nodeToMove, - true, - assocTypeQName, - assocQName); - setChildUniqueName(nodeToMove); // ensure uniqueness - ChildAssociationRef newAssocRef = newAssoc.getChildAssocRef(); - - // If the node is moving stores, then drag the node hierarchy with it - if (movingStore) - { - // do the move - Store newStore = newParentNode.getStore(); - moveNodeToStore(nodeToMove, newStore); - // the node reference will have changed too - nodeToMoveRef = nodeToMove.getNodeRef(); - } - - // check that no cyclic relationships have been created - getPaths(nodeToMoveRef, false); - - // invoke policy behaviour - if (movingStore) - { - // TODO for now indicate that the node has been archived to prevent the version history from being removed - // in the future a onMove policy could be added and remove the need for onDelete and onCreate to be fired here - invokeOnDeleteNode(oldAssocRef, nodeToMoveTypeQName, nodeToMoveAspects, true); - invokeOnCreateNode(newAssoc.getChildAssocRef()); - } - else - { - invokeOnCreateChildAssociation(newAssoc.getChildAssocRef()); - invokeOnDeleteChildAssociation(oldAssoc.getChildAssocRef()); - invokeOnUpdateNode(oldParentNode.getNodeRef()); - invokeOnUpdateNode(newParentRef); - } - invokeOnMoveNode(oldAssocRef, newAssocRef); - - // update the node status - nodeDaoService.recordChangeId(nodeToMoveRef); - - // done - return newAssoc.getChildAssocRef(); - } - - public void setChildAssociationIndex(ChildAssociationRef childAssocRef, int index) - { - // get nodes - Node parentNode = getNodeNotNull(childAssocRef.getParentRef()); - Node childNode = getNodeNotNull(childAssocRef.getChildRef()); - - ChildAssoc assoc = nodeDaoService.getChildAssoc( - parentNode, - childNode, - childAssocRef.getTypeQName(), - childAssocRef.getQName()); - if (assoc == null) - { - throw new InvalidChildAssociationRefException("Unable to set child association index: \n" + - " assoc: " + childAssocRef + "\n" + - " index: " + index, - childAssocRef); - } - // set the index - assoc.setIndex(index); - } - - public QName getType(NodeRef nodeRef) throws InvalidNodeRefException - { - Node node = getNodeNotNull(nodeRef); - return node.getTypeQName(); - } - - /** - * @see org.alfresco.service.cmr.repository.NodeService#setType(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName) - */ - public void setType(NodeRef nodeRef, QName typeQName) throws InvalidNodeRefException - { - // check the node type - TypeDefinition nodeTypeDef = dictionaryService.getType(typeQName); - if (nodeTypeDef == null) - { - throw new InvalidTypeException(typeQName); - } - - // Invoke policies - invokeBeforeUpdateNode(nodeRef); - - // Get the node and set the new type - Node node = getNodeNotNull(nodeRef); - node.setTypeQName(typeQName); - - // Add the default aspects to the node (update the properties with any new default values) - Map properties = this.getPropertiesImpl(node); - addDefaultAspects(nodeTypeDef, node, properties); - this.setProperties(nodeRef, properties); - - // Invoke policies - invokeOnUpdateNode(nodeRef); - } - - /** - * @see Node#getAspects() - */ - public void addAspect( - NodeRef nodeRef, - QName aspectTypeQName, - Map aspectProperties) - throws InvalidNodeRefException, InvalidAspectException - { - // check that the aspect is legal - AspectDefinition aspectDef = dictionaryService.getAspect(aspectTypeQName); - if (aspectDef == null) - { - throw new InvalidAspectException("The aspect is invalid: " + aspectTypeQName, aspectTypeQName); - } - - // Invoke policy behaviours - invokeBeforeUpdateNode(nodeRef); - invokeBeforeAddAspect(nodeRef, aspectTypeQName); - - Node node = getNodeNotNull(nodeRef); - - // attach the properties to the current node properties - Map nodeProperties = getPropertiesImpl(node); - - if (aspectProperties != null) - { - nodeProperties.putAll(aspectProperties); - } - - // Set any default property values that appear on the aspect - addDefaultPropertyValues(aspectDef, nodeProperties); - - // Add any dependant aspect - addDefaultAspects(aspectDef, node, nodeProperties); - - // Set the property values back on the node - setProperties(nodeRef, nodeProperties); - - // physically attach the aspect to the node - if (node.getAspects().add(aspectTypeQName) == true) - { - // Invoke policy behaviours - invokeOnUpdateNode(nodeRef); - invokeOnAddAspect(nodeRef, aspectTypeQName); - - // update the node status - nodeDaoService.recordChangeId(nodeRef); - } - } - - /** - * @see Node#getAspects() - */ - public void removeAspect(NodeRef nodeRef, QName aspectTypeQName) - throws InvalidNodeRefException, InvalidAspectException - { - // Invoke policy behaviours - invokeBeforeUpdateNode(nodeRef); - invokeBeforeRemoveAspect(nodeRef, aspectTypeQName); - - // get the aspect - AspectDefinition aspectDef = dictionaryService.getAspect(aspectTypeQName); - if (aspectDef == null) - { - throw new InvalidAspectException(aspectTypeQName); - } - // get the node - Node node = getNodeNotNull(nodeRef); - - // remove the aspect, if present - boolean removed = node.getAspects().remove(aspectTypeQName); - // if the aspect was present, remove the associated properties - if (removed) - { - Map nodeProperties = node.getProperties(); - Map propertyDefs = aspectDef.getProperties(); - for (QName propertyName : propertyDefs.keySet()) - { - nodeProperties.remove(propertyName); - } - - // Invoke policy behaviours - invokeOnUpdateNode(nodeRef); - invokeOnRemoveAspect(nodeRef, aspectTypeQName); - - // update the node status - nodeDaoService.recordChangeId(nodeRef); - } - } - - /** - * Performs a check on the set of node aspects - * - * @see Node#getAspects() - */ - public boolean hasAspect(NodeRef nodeRef, QName aspectRef) throws InvalidNodeRefException, InvalidAspectException - { - Node node = getNodeNotNull(nodeRef); - Set aspectQNames = node.getAspects(); - boolean hasAspect = aspectQNames.contains(aspectRef); - // done - return hasAspect; - } - - public Set getAspects(NodeRef nodeRef) throws InvalidNodeRefException - { - Node node = getNodeNotNull(nodeRef); - Set aspectQNames = node.getAspects(); - // copy the set to ensure initialization - Set ret = new HashSet(aspectQNames.size()); - ret.addAll(aspectQNames); - // done - return ret; - } - - public void deleteNode(NodeRef nodeRef) - { - boolean isArchivedNode = false; - boolean requiresDelete = false; - - // Invoke policy behaviours - invokeBeforeDeleteNode(nodeRef); - - // get the node - Node node = getNodeNotNull(nodeRef); - // get the primary parent-child relationship before it is gone - ChildAssociationRef childAssocRef = getPrimaryParent(nodeRef); - // get type and aspect QNames as they will be unavailable after the delete - QName nodeTypeQName = node.getTypeQName(); - Set nodeAspectQNames = node.getAspects(); - - // check if we need to archive the node - StoreRef archiveStoreRef = null; - if (nodeAspectQNames.contains(ContentModel.ASPECT_TEMPORARY)) - { - // the node has the temporary aspect meaning - // it can not be archived - requiresDelete = true; - isArchivedNode = false; - } - else - { - StoreRef storeRef = nodeRef.getStoreRef(); - archiveStoreRef = storeArchiveMap.getArchiveMap().get(storeRef); - // get the type and check if we need archiving - TypeDefinition typeDef = dictionaryService.getType(node.getTypeQName()); - if (typeDef == null || !typeDef.isArchive() || archiveStoreRef == null) - { - requiresDelete = true; - } - } - - if (requiresDelete) - { - // perform a normal deletion - nodeDaoService.deleteNode(node, true); - isArchivedNode = false; - } - else - { - // archive it - archiveNode(nodeRef, archiveStoreRef); - isArchivedNode = true; - } - - // Invoke policy behaviours - invokeOnDeleteNode(childAssocRef, nodeTypeQName, nodeAspectQNames, isArchivedNode); - } - - public ChildAssociationRef addChild(NodeRef parentRef, NodeRef childRef, QName assocTypeQName, QName assocQName) - { - // Invoke policy behaviours - invokeBeforeUpdateNode(parentRef); - invokeBeforeCreateChildAssociation(parentRef, childRef, assocTypeQName, assocQName); - - // get the parent node and ensure that it is a container node - Node parentNode = getNodeNotNull(parentRef); - // get the child node - Node childNode = getNodeNotNull(childRef); - // make the association - ChildAssoc assoc = nodeDaoService.newChildAssoc( - parentNode, - childNode, - false, - assocTypeQName, - assocQName); - // ensure name uniqueness - setChildUniqueName(childNode); - ChildAssociationRef assocRef = assoc.getChildAssocRef(); - NodeRef childNodeRef = assocRef.getChildRef(); - - // check that the child addition of the child has not created a cyclic relationship - // this functionality is provided for free in getPath - getPaths(childNodeRef, false); - - // Invoke policy behaviours - invokeOnCreateChildAssociation(assocRef); - invokeOnUpdateNode(parentRef); - - return assoc.getChildAssocRef(); - } - - public void removeChild(NodeRef parentRef, NodeRef childRef) throws InvalidNodeRefException - { - Node parentNode = getNodeNotNull(parentRef); - Node childNode = getNodeNotNull(childRef); - Long childNodeId = childNode.getId(); - - // get all the child assocs - ChildAssociationRef primaryAssocRef = null; - Collection assocs = nodeDaoService.getChildAssocs(parentNode); - assocs = new HashSet(assocs); // copy set as we will be modifying it - for (ChildAssoc assoc : assocs) - { - if (!assoc.getChild().getId().equals(childNodeId)) - { - continue; // not a matching association - } - ChildAssociationRef assocRef = assoc.getChildAssocRef(); - // Is this a primary association? - if (assoc.getIsPrimary()) - { - // keep the primary associaton for last - primaryAssocRef = assocRef; - } - else - { - // delete the association instance - it is not primary - invokeBeforeDeleteChildAssociation(assocRef); - nodeDaoService.deleteChildAssoc(assoc, true); // cascade - invokeOnDeleteChildAssociation(assocRef); - } - } - // remove the child if the primary association was a match - if (primaryAssocRef != null) - { - deleteNode(primaryAssocRef.getChildRef()); - } - - // Invoke policy behaviours - invokeOnUpdateNode(parentRef); - - // done - } - - public Map getProperties(NodeRef nodeRef) throws InvalidNodeRefException - { - Node node = getNodeNotNull(nodeRef); - return getPropertiesImpl(node); - } - - private Map getPropertiesImpl(Node node) throws InvalidNodeRefException - { - NodeRef nodeRef = node.getNodeRef(); - - Map nodeProperties = node.getProperties(); - Map ret = new HashMap(nodeProperties.size()); - // copy values - for (Map.Entry entry: nodeProperties.entrySet()) - { - QName propertyQName = entry.getKey(); - PropertyValue propertyValue = entry.getValue(); - // get the property definition - PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); - // convert to the correct type - Serializable value = makeSerializableValue(propertyDef, propertyValue); - // copy across - ret.put(propertyQName, value); - } - // spoof referencable properties - addReferencableProperties(nodeRef, node.getId(), ret); - // done - return ret; - } - - public Serializable getProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException - { - // spoof referencable properties - if (qname.equals(ContentModel.PROP_STORE_PROTOCOL)) - { - return nodeRef.getStoreRef().getProtocol(); - } - else if (qname.equals(ContentModel.PROP_STORE_IDENTIFIER)) - { - return nodeRef.getStoreRef().getIdentifier(); - } - else if (qname.equals(ContentModel.PROP_NODE_UUID)) - { - return nodeRef.getId(); - } - - // get the property from the node - Node node = getNodeNotNull(nodeRef); - - if (qname.equals(ContentModel.PROP_NODE_DBID)) - { - return node.getId(); - } - - Map properties = node.getProperties(); - PropertyValue propertyValue = properties.get(qname); - - // get the property definition - PropertyDefinition propertyDef = dictionaryService.getProperty(qname); - // convert to the correct type - Serializable value = makeSerializableValue(propertyDef, propertyValue); - // done - return value; - } - - /** - * Ensures that all required properties are present on the node and copies the - * property values to the Node. - *

- * To remove a property, remove it from the map before calling this method. - * Null-valued properties are allowed. - *

- * If any of the values are null, a marker object is put in to mimic nulls. They will be turned back into - * a real nulls when the properties are requested again. - * - * @see Node#getProperties() - */ - public void setProperties(NodeRef nodeRef, Map properties) throws InvalidNodeRefException - { - Node node = getNodeNotNull(nodeRef); - - // Invoke policy behaviours - invokeBeforeUpdateNode(nodeRef); - - // Do the set properties - Map propertiesBefore = getPropertiesImpl(node); - Map propertiesAfter = setPropertiesImpl(node, properties); - - setChildUniqueName(node); // ensure uniqueness - - // Invoke policy behaviours - invokeOnUpdateNode(nodeRef); - invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter); - } - - /** - * Does the work of setting the property values. Returns a map containing the state of the properties after the set - * operation is complete. - * - * @param node the node - * @param properties the map of property values - * @return the map of property values after the set operation is complete - * @throws InvalidNodeRefException - */ - private Map setPropertiesImpl(Node node, Map properties) throws InvalidNodeRefException - { - ParameterCheck.mandatory("properties", properties); - - // remove referencable properties - removeReferencableProperties(properties); - - // copy properties onto node - Map nodeProperties = node.getProperties(); - nodeProperties.clear(); - - // check the property type and copy the values across - for (QName propertyQName : properties.keySet()) - { - PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); - Serializable value = properties.get(propertyQName); - // get a persistable value - PropertyValue propertyValue = makePropertyValue(propertyDef, value); - nodeProperties.put(propertyQName, propertyValue); - } - - // update the node status - NodeRef nodeRef = node.getNodeRef(); - nodeDaoService.recordChangeId(nodeRef); - - // Return the properties after - return Collections.unmodifiableMap(properties); - } - - /** - * Gets the properties map, sets the value (null is allowed) and checks that the new set - * of properties is valid. - * - * @see DbNodeServiceImpl.NullPropertyValue - */ - public void setProperty(NodeRef nodeRef, QName qname, Serializable value) throws InvalidNodeRefException - { - Assert.notNull(qname); - - // Invoke policy behaviours - invokeBeforeUpdateNode(nodeRef); - - // get the node - Node node = getNodeNotNull(nodeRef); - - // Do the set operation - Map propertiesBefore = getPropertiesImpl(node); - Map propertiesAfter = setPropertyImpl(node, qname, value); - - if (qname.equals(ContentModel.PROP_NAME)) - { - setChildUniqueName(node); // ensure uniqueness - } - - // Invoke policy behaviours - invokeOnUpdateNode(nodeRef); - invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter); - } - - /** - * Does the work of setting a property value. Returns the values of the properties after the set operation is - * complete. - * - * @param node the node - * @param qname the qname of the property - * @param value the value of the property - * @return the values of the properties after the set operation is complete - * @throws InvalidNodeRefException - */ - public Map setPropertyImpl(Node node, QName qname, Serializable value) throws InvalidNodeRefException - { - NodeRef nodeRef = node.getNodeRef(); - - Map properties = node.getProperties(); - PropertyDefinition propertyDef = dictionaryService.getProperty(qname); - // get a persistable value - PropertyValue propertyValue = makePropertyValue(propertyDef, value); - properties.put(qname, propertyValue); - - // update the node status - nodeDaoService.recordChangeId(nodeRef); - - return getPropertiesImpl(node); - } - - /** - * Transforms {@link Node#getParentAssocs()} to a new collection - */ - public Collection getParents(NodeRef nodeRef) throws InvalidNodeRefException - { - Node node = getNodeNotNull(nodeRef); - // get the assocs pointing to it - Collection parentAssocs = node.getParentAssocs(); - // list of results - Collection results = new ArrayList(parentAssocs.size()); - for (ChildAssoc assoc : parentAssocs) - { - // get the parent - Node parentNode = assoc.getParent(); - results.add(parentNode.getNodeRef()); - } - // done - return results; - } - - /** - * Filters out any associations if their qname is not a match to the given pattern. - */ - public List getParentAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern) - { - Node node = getNodeNotNull(nodeRef); - // get the assocs pointing to it - Collection parentAssocs = node.getParentAssocs(); - // shortcut if there are no assocs - if (parentAssocs.size() == 0) - { - return Collections.emptyList(); - } - // list of results - List results = new ArrayList(parentAssocs.size()); - for (ChildAssoc assoc : parentAssocs) - { - // does the qname match the pattern? - if (!qnamePattern.isMatch(assoc.getQname()) || !typeQNamePattern.isMatch(assoc.getTypeQName())) - { - // no match - ignore - continue; - } - results.add(assoc.getChildAssocRef()); - } - // done - return results; - } - - /** - * Filters out any associations if their qname is not a match to the given pattern. - */ - public List getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern) - { - Node node = getNodeNotNull(nodeRef); - // get the assocs pointing from it - Collection childAssocRefs = nodeDaoService.getChildAssocRefs(node); - // shortcut if there are no assocs - if (childAssocRefs.size() == 0) - { - return Collections.emptyList(); - } - // sort results - ArrayList orderedList = new ArrayList(childAssocRefs); - Collections.sort(orderedList); - - // list of results - int nthSibling = 0; - Iterator iterator = orderedList.iterator(); - while(iterator.hasNext()) - { - ChildAssociationRef childAssocRef = iterator.next(); - // does the qname match the pattern? - if (!qnamePattern.isMatch(childAssocRef.getQName()) || !typeQNamePattern.isMatch(childAssocRef.getTypeQName())) - { - // no match - remove - iterator.remove(); - } - else - { - childAssocRef.setNthSibling(nthSibling); - nthSibling++; - } - } - // done - return orderedList; - } - - public NodeRef getChildByName(NodeRef nodeRef, QName assocTypeQName, String childName) - { - Node node = getNodeNotNull(nodeRef); - ChildAssoc childAssoc = nodeDaoService.getChildAssoc(node, assocTypeQName, childName); - if (childAssoc != null) - { - return childAssoc.getChild().getNodeRef(); - } - else - { - return null; - } - } - - public ChildAssociationRef getPrimaryParent(NodeRef nodeRef) throws InvalidNodeRefException - { - Node node = getNodeNotNull(nodeRef); - // get the primary parent assoc - ChildAssoc assoc = nodeDaoService.getPrimaryParentAssoc(node); - - // done - the assoc may be null for a root node - ChildAssociationRef assocRef = null; - if (assoc == null) - { - assocRef = new ChildAssociationRef(null, null, null, nodeRef); - } - else - { - assocRef = assoc.getChildAssocRef(); - } - return assocRef; - } - - public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) - throws InvalidNodeRefException, AssociationExistsException - { - // Invoke policy behaviours - invokeBeforeUpdateNode(sourceRef); - - Node sourceNode = getNodeNotNull(sourceRef); - Node targetNode = getNodeNotNull(targetRef); - // see if it exists - NodeAssoc assoc = nodeDaoService.getNodeAssoc(sourceNode, targetNode, assocTypeQName); - if (assoc != null) - { - throw new AssociationExistsException(sourceRef, targetRef, assocTypeQName); - } - // we are sure that the association doesn't exist - make it - assoc = nodeDaoService.newNodeAssoc(sourceNode, targetNode, assocTypeQName); - AssociationRef assocRef = assoc.getNodeAssocRef(); - - // Invoke policy behaviours - invokeOnUpdateNode(sourceRef); - invokeOnCreateAssociation(assocRef); - - return assocRef; - } - - public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) - throws InvalidNodeRefException - { - Node sourceNode = getNodeNotNull(sourceRef); - Node targetNode = getNodeNotNull(targetRef); - // get the association - NodeAssoc assoc = nodeDaoService.getNodeAssoc(sourceNode, targetNode, assocTypeQName); - if (assoc == null) - { - // nothing to remove - return; - } - AssociationRef assocRef = assoc.getNodeAssocRef(); - - // Invoke policy behaviours - invokeBeforeUpdateNode(sourceRef); - - // delete it - nodeDaoService.deleteNodeAssoc(assoc); - - // Invoke policy behaviours - invokeOnUpdateNode(sourceRef); - invokeOnDeleteAssociation(assocRef); - } - - public List getTargetAssocs(NodeRef sourceRef, QNamePattern qnamePattern) - { - Node sourceNode = getNodeNotNull(sourceRef); - // get all assocs to target - Collection assocs = nodeDaoService.getTargetNodeAssocs(sourceNode); - List nodeAssocRefs = new ArrayList(assocs.size()); - for (NodeAssoc assoc : assocs) - { - // check qname pattern - if (!qnamePattern.isMatch(assoc.getTypeQName())) - { - continue; // the assoc name doesn't match the pattern given - } - nodeAssocRefs.add(assoc.getNodeAssocRef()); - } - // done - return nodeAssocRefs; - } - - public List getSourceAssocs(NodeRef targetRef, QNamePattern qnamePattern) - { - Node targetNode = getNodeNotNull(targetRef); - // get all assocs to source - Collection assocs = nodeDaoService.getSourceNodeAssocs(targetNode); - List nodeAssocRefs = new ArrayList(assocs.size()); - for (NodeAssoc assoc : assocs) - { - // check qname pattern - if (!qnamePattern.isMatch(assoc.getTypeQName())) - { - continue; // the assoc name doesn't match the pattern given - } - nodeAssocRefs.add(assoc.getNodeAssocRef()); - } - // done - return nodeAssocRefs; - } - - /** - * Recursive method used to build up paths from a given node to the root. - *

- * Whilst walking up the hierarchy to the root, some nodes may have a root 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( - final Node currentNode, - final Path currentPath, - Collection completedPaths, - Stack assocStack, - boolean primaryOnly) - throws CyclicChildRelationshipException - { - NodeRef currentNodeRef = currentNode.getNodeRef(); - // get the parent associations of the given node - Collection parentAssocs = currentNode.getParentAssocs(); - // does the node have parents - boolean hasParents = parentAssocs.size() > 0; - // does the current node have a root aspect? - boolean isRoot = hasAspect(currentNodeRef, ContentModel.ASPECT_ROOT); - boolean isStoreRoot = currentNode.getTypeQName().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, - getRootNode(currentNode.getNodeRef().getStoreRef())); - // 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(), - getRootNode(currentNode.getNodeRef().getStoreRef()), - 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 (parentAssocs.size() == 0 && !isRoot) - { - throw new RuntimeException("Node without parents does not have root aspect: " + - currentNodeRef); - } - // walk up each parent association - for (ChildAssoc assoc : parentAssocs) - { - // does the association already exist in the stack - if (assocStack.contains(assoc)) - { - // the association was present already - throw new CyclicChildRelationshipException( - "Cyclic parent-child relationship detected: \n" + - " current node: " + currentNode + "\n" + - " current path: " + currentPath + "\n" + - " next assoc: " + assoc, - assoc); - } - // do we consider only primary assocs? - if (primaryOnly && !assoc.getIsPrimary()) - { - continue; - } - // build a path element - NodeRef parentRef = assoc.getParent().getNodeRef(); - QName qname = assoc.getQname(); - NodeRef childRef = assoc.getChild().getNodeRef(); - boolean isPrimary = assoc.getIsPrimary(); - // build a real association reference - ChildAssociationRef assocRef = new ChildAssociationRef(assoc.getTypeQName(), parentRef, qname, childRef, isPrimary, -1); - // Ordering is not important here: We are building distinct paths upwards - 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 - Node parentNode = assoc.getParent(); - - // push the assoc stack, recurse and pop - assocStack.push(assoc); - prependPaths(parentNode, path, completedPaths, assocStack, primaryOnly); - assocStack.pop(); - } - // done - } - - /** - * @see #getPaths(NodeRef, boolean) - * @see #prependPaths(Node, Path, Collection, Stack, boolean) - */ - public Path getPath(NodeRef nodeRef) throws InvalidNodeRefException - { - List paths = getPaths(nodeRef, true); // checks primary path count - if (paths.size() == 1) - { - return paths.get(0); // we know there is only one - } - throw new RuntimeException("Primary path count not checked"); // checked by getPaths() - } - - /** - * When searching for primaryOnly == true, checks that there is exactly - * one path. - * @see #prependPaths(Node, Path, Collection, Stack, boolean) - */ - public List getPaths(NodeRef nodeRef, boolean primaryOnly) throws InvalidNodeRefException - { - // get the starting node - Node node = getNodeNotNull(nodeRef); - // create storage for the paths - only need 1 bucket if we are looking for the primary path - List paths = new ArrayList(primaryOnly ? 1 : 10); - // create an empty current path to start from - Path currentPath = new Path(); - // create storage for touched associations - Stack assocStack = new Stack(); - // call recursive method to sort it out - prependPaths(node, currentPath, paths, assocStack, primaryOnly); - - // check that for the primary only case we have exactly one path - if (primaryOnly && paths.size() != 1) - { - throw new RuntimeException("Node has " + paths.size() + " primary paths: " + nodeRef); - } - - // done - if (loggerPaths.isDebugEnabled()) - { - StringBuilder sb = new StringBuilder(256); - if (primaryOnly) - { - sb.append("Primary paths"); - } - else - { - sb.append("Paths"); - } - sb.append(" for node ").append(nodeRef); - for (Path path : paths) - { - sb.append("\n").append(" ").append(path); - } - loggerPaths.debug(sb); - } - return paths; - } - - private void archiveNode(NodeRef nodeRef, StoreRef archiveStoreRef) - { - Node node = getNodeNotNull(nodeRef); - ChildAssoc primaryParentAssoc = nodeDaoService.getPrimaryParentAssoc(node); - - // add the aspect - Set aspects = node.getAspects(); - aspects.add(ContentModel.ASPECT_ARCHIVED); - Map properties = node.getProperties(); - PropertyValue archivedByProperty = makePropertyValue( - dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_BY), - AuthenticationUtil.getCurrentUserName()); - properties.put(ContentModel.PROP_ARCHIVED_BY, archivedByProperty); - PropertyValue archivedDateProperty = makePropertyValue( - dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_DATE), - new Date()); - properties.put(ContentModel.PROP_ARCHIVED_DATE, archivedDateProperty); - PropertyValue archivedPrimaryParentNodeRefProperty = makePropertyValue( - dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC), - primaryParentAssoc.getChildAssocRef()); - properties.put(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC, archivedPrimaryParentNodeRefProperty); - PropertyValue originalOwnerProperty = properties.get(ContentModel.PROP_OWNER); - PropertyValue originalCreatorProperty = properties.get(ContentModel.PROP_CREATOR); - if (originalOwnerProperty != null || originalCreatorProperty != null) - { - properties.put( - ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER, - originalOwnerProperty != null ? originalOwnerProperty : originalCreatorProperty); - } - - // change the node ownership - aspects.add(ContentModel.ASPECT_OWNABLE); - PropertyValue newOwnerProperty = makePropertyValue( - dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER), - AuthenticationUtil.getCurrentUserName()); - properties.put(ContentModel.PROP_OWNER, newOwnerProperty); - - // move the node - NodeRef archiveStoreRootNodeRef = getRootNode(archiveStoreRef); - moveNode( - nodeRef, - archiveStoreRootNodeRef, - ContentModel.ASSOC_CHILDREN, - QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedItem")); - - // get the IDs of all the node's primary children, including its own - Map nodesById = getNodeHierarchy(node, null); - - // Archive all the associations between the archived nodes and non-archived nodes - for (Node nodeToArchive : nodesById.values()) - { - archiveAssocs(nodeToArchive, nodesById); - } - - // the node reference has changed due to the store move - nodeRef = node.getNodeRef(); - } - - /** - * Performs all the necessary housekeeping involved in changing a node's store. - * This method cascades down through all the primary children of the node as - * well. - * - * @param node the node whose store is changing - * @param store the new store for the node - */ - private void moveNodeToStore(Node node, Store store) - { - // get the IDs of all the node's primary children, including its own - Map nodesById = getNodeHierarchy(node, null); - - // move each node into the archive store - for (Node nodeToMove : nodesById.values()) - { - NodeRef oldNodeRef = nodeToMove.getNodeRef(); - nodeToMove.setStore(store); - NodeRef newNodeRef = nodeToMove.getNodeRef(); - - String txnId = AlfrescoTransactionSupport.getTransactionId(); - // update old status - NodeStatus oldNodeStatus = nodeDaoService.getNodeStatus(oldNodeRef, true); - oldNodeStatus.setNode(null); - oldNodeStatus.getTransaction().setChangeTxnId(txnId); - // create the new status - NodeStatus newNodeStatus = nodeDaoService.getNodeStatus(newNodeRef, true); - newNodeStatus.setNode(nodeToMove); - newNodeStatus.getTransaction().setChangeTxnId(txnId); - } - } - - /** - * Fill the map of all primary children below the given node. - * The given node will be added to the map and the method is recursive - * to all primary children. - * - * @param node the start of the hierarchy - * @param nodesById a map of nodes that will be reused as the return value - * @return Returns a map of nodes in the hierarchy keyed by their IDs - */ - private Map getNodeHierarchy(Node node, Map nodesById) - { - if (nodesById == null) - { - nodesById = new HashMap(23); - } - - Long id = node.getId(); - if (nodesById.containsKey(id)) - { - // this ID was already added - circular reference - logger.warn("Circular hierarchy found including node " + id); - return nodesById; - } - // add the node to the map - nodesById.put(id, node); - // recurse into the primary children - Collection childAssocs = nodeDaoService.getChildAssocs(node); - for (ChildAssoc childAssoc : childAssocs) - { - // cascade into primary associations - if (childAssoc.getIsPrimary()) - { - Node primaryChild = childAssoc.getChild(); - nodesById = getNodeHierarchy(primaryChild, nodesById); - } - } - return nodesById; - } - - /** - * Archive all associations to and from the given node, with the - * exception of associations to or from nodes in the given map. - *

- * Primary parent associations are also ignored. - * - * @param node the node whose associations must be archived - * @param nodesById a map of nodes partaking in the archival process - */ - private void archiveAssocs(Node node, Map nodesById) - { - List childAssocsToDelete = new ArrayList(5); - // child associations - ArrayList archivedChildAssocRefs = new ArrayList(5); - Collection childAssocs = nodeDaoService.getChildAssocs(node); - for (ChildAssoc assoc : childAssocs) - { - Long relatedNodeId = assoc.getChild().getId(); - if (nodesById.containsKey(relatedNodeId)) - { - // a sibling in the archive process - continue; - } - childAssocsToDelete.add(assoc); - archivedChildAssocRefs.add(assoc.getChildAssocRef()); - } - // parent associations - ArrayList archivedParentAssocRefs = new ArrayList(5); - for (ChildAssoc assoc : node.getParentAssocs()) - { - Long relatedNodeId = assoc.getParent().getId(); - if (nodesById.containsKey(relatedNodeId)) - { - // a sibling in the archive process - continue; - } - else if (assoc.getIsPrimary()) - { - // ignore the primary parent as this is handled more specifically - continue; - } - childAssocsToDelete.add(assoc); - archivedParentAssocRefs.add(assoc.getChildAssocRef()); - } - - List nodeAssocsToDelete = new ArrayList(5); - // source associations - ArrayList archivedSourceAssocRefs = new ArrayList(5); - for (NodeAssoc assoc : nodeDaoService.getSourceNodeAssocs(node)) - { - Long relatedNodeId = assoc.getSource().getId(); - if (nodesById.containsKey(relatedNodeId)) - { - // a sibling in the archive process - continue; - } - nodeAssocsToDelete.add(assoc); - archivedSourceAssocRefs.add(assoc.getNodeAssocRef()); - } - // target associations - ArrayList archivedTargetAssocRefs = new ArrayList(5); - for (NodeAssoc assoc : nodeDaoService.getTargetNodeAssocs(node)) - { - Long relatedNodeId = assoc.getTarget().getId(); - if (nodesById.containsKey(relatedNodeId)) - { - // a sibling in the archive process - continue; - } - nodeAssocsToDelete.add(assoc); - archivedTargetAssocRefs.add(assoc.getNodeAssocRef()); - } - // delete child assocs - for (ChildAssoc assoc : childAssocsToDelete) - { - nodeDaoService.deleteChildAssoc(assoc, false); - } - // delete node assocs - for (NodeAssoc assoc : nodeAssocsToDelete) - { - nodeDaoService.deleteNodeAssoc(assoc); - } - - // add archived aspect - node.getAspects().add(ContentModel.ASPECT_ARCHIVED_ASSOCS); - // set properties - Map properties = node.getProperties(); - - if (archivedParentAssocRefs.size() > 0) - { - PropertyDefinition propertyDef = dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_PARENT_ASSOCS); - PropertyValue propertyValue = makePropertyValue(propertyDef, archivedParentAssocRefs); - properties.put(ContentModel.PROP_ARCHIVED_PARENT_ASSOCS, propertyValue); - } - if (archivedChildAssocRefs.size() > 0) - { - PropertyDefinition propertyDef = dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_CHILD_ASSOCS); - PropertyValue propertyValue = makePropertyValue(propertyDef, archivedChildAssocRefs); - properties.put(ContentModel.PROP_ARCHIVED_CHILD_ASSOCS, propertyValue); - } - if (archivedSourceAssocRefs.size() > 0) - { - PropertyDefinition propertyDef = dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS); - PropertyValue propertyValue = makePropertyValue(propertyDef, archivedSourceAssocRefs); - properties.put(ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS, propertyValue); - } - if (archivedTargetAssocRefs.size() > 0) - { - PropertyDefinition propertyDef = dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_TARGET_ASSOCS); - PropertyValue propertyValue = makePropertyValue(propertyDef, archivedTargetAssocRefs); - properties.put(ContentModel.PROP_ARCHIVED_TARGET_ASSOCS, propertyValue); - } - } - - public NodeRef getStoreArchiveNode(StoreRef storeRef) - { - StoreRef archiveStoreRef = storeArchiveMap.getArchiveMap().get(storeRef); - if (archiveStoreRef == null) - { - // no mapping for the given store - return null; - } - else - { - return getRootNode(archiveStoreRef); - } - } - - public NodeRef restoreNode(NodeRef archivedNodeRef, NodeRef destinationParentNodeRef, QName assocTypeQName, QName assocQName) - { - Node archivedNode = getNodeNotNull(archivedNodeRef); - Set aspects = archivedNode.getAspects(); - Map properties = archivedNode.getProperties(); - // the node must be a top-level archive node - if (!aspects.contains(ContentModel.ASPECT_ARCHIVED)) - { - throw new AlfrescoRuntimeException("The node to archive is not an archive node"); - } - ChildAssociationRef originalPrimaryParentAssocRef = (ChildAssociationRef) makeSerializableValue( - dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC), - properties.get(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC)); - PropertyValue originalOwnerProperty = properties.get(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER); - // remove the aspect archived aspect - aspects.remove(ContentModel.ASPECT_ARCHIVED); - properties.remove(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC); - properties.remove(ContentModel.PROP_ARCHIVED_BY); - properties.remove(ContentModel.PROP_ARCHIVED_DATE); - properties.remove(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER); - - // restore the original ownership - if (originalOwnerProperty != null) - { - aspects.add(ContentModel.ASPECT_OWNABLE); - properties.put(ContentModel.PROP_OWNER, originalOwnerProperty); - } - - if (destinationParentNodeRef == null) - { - // we must restore to the original location - destinationParentNodeRef = originalPrimaryParentAssocRef.getParentRef(); - } - // check the associations - if (assocTypeQName == null) - { - assocTypeQName = originalPrimaryParentAssocRef.getTypeQName(); - } - if (assocQName == null) - { - assocQName = originalPrimaryParentAssocRef.getQName(); - } - - // move the node to the target parent, which may or may not be the original parent - moveNode( - archivedNodeRef, - destinationParentNodeRef, - assocTypeQName, - assocQName); - - // get the IDs of all the node's primary children, including its own - Map restoredNodesById = getNodeHierarchy(archivedNode, null); - // Restore the archived associations, if required - for (Node restoredNode : restoredNodesById.values()) - { - restoreAssocs(restoredNode); - } - - // the node reference has changed due to the store move - NodeRef restoredNodeRef = archivedNode.getNodeRef(); - - // done - if (logger.isDebugEnabled()) - { - logger.debug("Restored node: \n" + - " original noderef: " + archivedNodeRef + "\n" + - " restored noderef: " + restoredNodeRef + "\n" + - " new parent: " + destinationParentNodeRef); - } - return restoredNodeRef; - } - - private void restoreAssocs(Node node) - { - NodeRef nodeRef = node.getNodeRef(); - // set properties - Map properties = node.getProperties(); - - // restore parent associations - Collection parentAssocRefs = (Collection) getProperty( - nodeRef, - ContentModel.PROP_ARCHIVED_PARENT_ASSOCS); - if (parentAssocRefs != null) - { - for (ChildAssociationRef assocRef : parentAssocRefs) - { - NodeRef parentNodeRef = assocRef.getParentRef(); - if (!exists(parentNodeRef)) - { - continue; - } - Node parentNode = getNodeNotNull(parentNodeRef); - // get the name to use for the unique child check - QName assocTypeQName = assocRef.getTypeQName(); - nodeDaoService.newChildAssoc( - parentNode, - node, - assocRef.isPrimary(), - assocTypeQName, - assocRef.getQName()); - } - properties.remove(ContentModel.PROP_ARCHIVED_PARENT_ASSOCS); - } - - // make sure that the node name uniqueness is enforced - setChildUniqueName(node); - - // restore child associations - Collection childAssocRefs = (Collection) getProperty( - nodeRef, - ContentModel.PROP_ARCHIVED_CHILD_ASSOCS); - if (childAssocRefs != null) - { - for (ChildAssociationRef assocRef : childAssocRefs) - { - NodeRef childNodeRef = assocRef.getChildRef(); - if (!exists(childNodeRef)) - { - continue; - } - Node childNode = getNodeNotNull(childNodeRef); - QName assocTypeQName = assocRef.getTypeQName(); - // get the name to use for the unique child check - nodeDaoService.newChildAssoc( - node, - childNode, - assocRef.isPrimary(), - assocTypeQName, - assocRef.getQName()); - // ensure that the name uniqueness is enforced for the child node - setChildUniqueName(childNode); - } - properties.remove(ContentModel.PROP_ARCHIVED_CHILD_ASSOCS); - } - // restore source associations - Collection sourceAssocRefs = (Collection) getProperty( - nodeRef, - ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS); - if (sourceAssocRefs != null) - { - for (AssociationRef assocRef : sourceAssocRefs) - { - NodeRef sourceNodeRef = assocRef.getSourceRef(); - if (!exists(sourceNodeRef)) - { - continue; - } - Node sourceNode = getNodeNotNull(sourceNodeRef); - nodeDaoService.newNodeAssoc(sourceNode, node, assocRef.getTypeQName()); - } - properties.remove(ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS); - } - // restore target associations - Collection targetAssocRefs = (Collection) getProperty( - nodeRef, - ContentModel.PROP_ARCHIVED_TARGET_ASSOCS); - if (targetAssocRefs != null) - { - for (AssociationRef assocRef : targetAssocRefs) - { - NodeRef targetNodeRef = assocRef.getTargetRef(); - if (!exists(targetNodeRef)) - { - continue; - } - Node targetNode = getNodeNotNull(targetNodeRef); - nodeDaoService.newNodeAssoc(node, targetNode, assocRef.getTypeQName()); - } - properties.remove(ContentModel.PROP_ARCHIVED_TARGET_ASSOCS); - } - // remove the aspect - node.getAspects().remove(ContentModel.ASPECT_ARCHIVED_ASSOCS); - } - - /** - * Checks the dictionary's definition of the association to assign a unique name to the child node. - * - * @param assocTypeQName the type of the child association - * @param childNode the child node being added. The name will be extracted from it, if necessary. - */ - private void setChildUniqueName(Node childNode) - { - // get the name property - Map properties = childNode.getProperties(); - PropertyValue nameValue = properties.get(ContentModel.PROP_NAME); - String useName = null; - if (nameValue == null) - { - // no name has been assigned, so assign the ID of the child node - useName = childNode.getUuid(); - } - else - { - useName = (String) nameValue.getValue(DataTypeDefinition.TEXT); - } - // get all the parent assocs - Collection parentAssocs = childNode.getParentAssocs(); - for (ChildAssoc assoc : parentAssocs) - { - QName assocTypeQName = assoc.getTypeQName(); - AssociationDefinition assocDef = dictionaryService.getAssociation(assocTypeQName); - if (!assocDef.isChild()) - { - throw new DataIntegrityViolationException("Child association has non-child type: " + assoc.getId()); - } - ChildAssociationDefinition childAssocDef = (ChildAssociationDefinition) assocDef; - if (childAssocDef.getDuplicateChildNamesAllowed()) - { - // the name is irrelevant, so it doesn't need to be put into the unique key - nodeDaoService.setChildNameUnique(assoc, null); - } - else - { - nodeDaoService.setChildNameUnique(assoc, useName); - } - } - // done - if (logger.isDebugEnabled()) - { - logger.debug( - "Unique name set for all " + parentAssocs.size() + " parent associations: \n" + - " name: " + useName); - } - } -} +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.node.db; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.ChildAssoc; +import org.alfresco.repo.domain.Node; +import org.alfresco.repo.domain.NodeAssoc; +import org.alfresco.repo.domain.NodeStatus; +import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.domain.Store; +import org.alfresco.repo.node.AbstractNodeServiceImpl; +import org.alfresco.repo.node.StoreArchiveMap; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.cmr.dictionary.AspectDefinition; +import org.alfresco.service.cmr.dictionary.AssociationDefinition; +import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition; +import org.alfresco.service.cmr.dictionary.ClassDefinition; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.InvalidAspectException; +import org.alfresco.service.cmr.dictionary.InvalidTypeException; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.dictionary.TypeDefinition; +import org.alfresco.service.cmr.repository.AssociationExistsException; +import org.alfresco.service.cmr.repository.AssociationRef; +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.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.InvalidStoreRefException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.Path; +import org.alfresco.service.cmr.repository.StoreExistsException; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.NodeRef.Status; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.QNamePattern; +import org.alfresco.util.ParameterCheck; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.util.Assert; + +/** + * Node service using database persistence layer to fulfill functionality + * + * @author Derek Hulley + */ +public class DbNodeServiceImpl extends AbstractNodeServiceImpl +{ + private static Log logger = LogFactory.getLog(DbNodeServiceImpl.class); + private static Log loggerPaths = LogFactory.getLog(DbNodeServiceImpl.class.getName() + ".paths"); + + private NodeDaoService nodeDaoService; + private StoreArchiveMap storeArchiveMap; + private NodeService avmNodeService; + + public DbNodeServiceImpl() + { + storeArchiveMap = new StoreArchiveMap(); // in case it is not set + } + + public void setNodeDaoService(NodeDaoService nodeDaoService) + { + this.nodeDaoService = nodeDaoService; + } + + public void setStoreArchiveMap(StoreArchiveMap storeArchiveMap) + { + this.storeArchiveMap = storeArchiveMap; + } + + public void setAvmNodeService(NodeService avmNodeService) + { + this.avmNodeService = avmNodeService; + } + + /** + * Performs a null-safe get of the node + * + * @param nodeRef the node to retrieve + * @return Returns the node entity (never null) + * @throws InvalidNodeRefException if the referenced node could not be found + */ + private Node getNodeNotNull(NodeRef nodeRef) throws InvalidNodeRefException + { + Node unchecked = nodeDaoService.getNode(nodeRef); + if (unchecked == null) + { + throw new InvalidNodeRefException("Node does not exist: " + nodeRef, nodeRef); + } + return unchecked; + } + + public boolean exists(StoreRef storeRef) + { + Store store = nodeDaoService.getStore(storeRef.getProtocol(), storeRef.getIdentifier()); + boolean exists = (store != null); + // done + return exists; + } + + public boolean exists(NodeRef nodeRef) + { + Node node = nodeDaoService.getNode(nodeRef); + boolean exists = (node != null); + // done + return exists; + } + + public Status getNodeStatus(NodeRef nodeRef) + { + NodeStatus nodeStatus = nodeDaoService.getNodeStatus(nodeRef, false); + if (nodeStatus == null) // node never existed + { + return null; + } + else + { + return new NodeRef.Status( + nodeStatus.getTransaction().getChangeTxnId(), + nodeStatus.isDeleted()); + } + } + + /** + * @see NodeDaoService#getStores() + */ + public List getStores() + { + List stores = nodeDaoService.getStores(); + List storeRefs = new ArrayList(stores.size()); + for (Store store : stores) + { + storeRefs.add(store.getStoreRef()); + } + // Now get the AVMStores. + List avmStores = avmNodeService.getStores(); + storeRefs.addAll(avmStores); + // Return them all. + return storeRefs; + } + + /** + * Defers to the typed service + * @see StoreDaoService#createWorkspace(String) + */ + public StoreRef createStore(String protocol, String identifier) + { + StoreRef storeRef = new StoreRef(protocol, identifier); + // check that the store does not already exist + Store store = nodeDaoService.getStore(protocol, identifier); + if (store != null) + { + throw new StoreExistsException("Unable to create a store that already exists: " + storeRef, storeRef); + } + + // invoke policies + invokeBeforeCreateStore(ContentModel.TYPE_STOREROOT, storeRef); + + // create a new one + store = nodeDaoService.createStore(protocol, identifier); + // get the root node + Node rootNode = store.getRootNode(); + // assign the root aspect - this is expected of all roots, even store roots + addAspect(rootNode.getNodeRef(), + ContentModel.ASPECT_ROOT, + Collections.emptyMap()); + + // invoke policies + invokeOnCreateStore(rootNode.getNodeRef()); + + // done + if (!store.getStoreRef().equals(storeRef)) + { + throw new RuntimeException("Incorrect store reference"); + } + return storeRef; + } + + public NodeRef getRootNode(StoreRef storeRef) throws InvalidStoreRefException + { + Store store = nodeDaoService.getStore(storeRef.getProtocol(), storeRef.getIdentifier()); + if (store == null) + { + throw new InvalidStoreRefException("Store does not exist", storeRef); + } + // get the root + Node node = store.getRootNode(); + if (node == null) + { + throw new InvalidStoreRefException("Store does not have a root node", storeRef); + } + NodeRef nodeRef = node.getNodeRef(); + // done + return nodeRef; + } + + /** + * @see #createNode(NodeRef, QName, QName, QName, Map) + */ + public ChildAssociationRef createNode( + NodeRef parentRef, + QName assocTypeQName, + QName assocQName, + QName nodeTypeQName) + { + return this.createNode(parentRef, assocTypeQName, assocQName, nodeTypeQName, null); + } + + /** + * @see org.alfresco.service.cmr.repository.NodeService#createNode(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName, org.alfresco.service.namespace.QName, java.util.Map) + */ + public ChildAssociationRef createNode( + NodeRef parentRef, + QName assocTypeQName, + QName assocQName, + QName nodeTypeQName, + Map properties) + { + Assert.notNull(parentRef); + Assert.notNull(assocTypeQName); + Assert.notNull(assocQName); + + // null property map is allowed + if (properties == null) + { + properties = new HashMap(); + } + else + { + // Copy the incomming property map since we may need to modify it later + properties = new HashMap(properties); + } + + // Invoke policy behaviour + invokeBeforeUpdateNode(parentRef); + invokeBeforeCreateNode(parentRef, assocTypeQName, assocQName, nodeTypeQName); + + // get the store that the parent belongs to + StoreRef storeRef = parentRef.getStoreRef(); + Store store = nodeDaoService.getStore(storeRef.getProtocol(), storeRef.getIdentifier()); + if (store == null) + { + throw new RuntimeException("No store found for parent node: " + parentRef); + } + + // check the node type + TypeDefinition nodeTypeDef = dictionaryService.getType(nodeTypeQName); + if (nodeTypeDef == null) + { + throw new InvalidTypeException(nodeTypeQName); + } + + // get/generate an ID for the node + String newId = generateGuid(properties); + + // create the node instance + Node childNode = nodeDaoService.newNode(store, newId, nodeTypeQName); + + // get the parent node + Node parentNode = getNodeNotNull(parentRef); + + // Set the default property values + addDefaultPropertyValues(nodeTypeDef, properties); + + // Add the default aspects to the node + addDefaultAspects(nodeTypeDef, childNode, properties); + + // set the properties - it is a new node so only set properties if there are any + Map propertiesBefore = getPropertiesImpl(childNode); + Map propertiesAfter = null; + if (properties.size() > 0) + { + propertiesAfter = setPropertiesImpl(childNode, properties); + } + + // create the association + ChildAssoc childAssoc = nodeDaoService.newChildAssoc( + parentNode, + childNode, + true, + assocTypeQName, + assocQName); + setChildUniqueName(childNode); // ensure uniqueness + ChildAssociationRef childAssocRef = childAssoc.getChildAssocRef(); + + // Invoke policy behaviour + invokeOnCreateNode(childAssocRef); + invokeOnUpdateNode(parentRef); + if (propertiesAfter != null) + { + invokeOnUpdateProperties(childAssocRef.getChildRef(), propertiesBefore, propertiesAfter); + } + + // done + return childAssocRef; + } + + /** + * Add the default aspects to a given node + * + * @param nodeTypeDef + */ + private void addDefaultAspects(ClassDefinition classDefinition, Node node, Map properties) + { + NodeRef nodeRef = node.getNodeRef(); + + // get the mandatory aspects for the node type + List defaultAspectDefs = classDefinition.getDefaultAspects(); + + // add all the aspects to the node + Set nodeAspects = node.getAspects(); + for (AspectDefinition defaultAspectDef : defaultAspectDefs) + { + invokeBeforeAddAspect(nodeRef, defaultAspectDef.getName()); + nodeAspects.add(defaultAspectDef.getName()); + addDefaultPropertyValues(defaultAspectDef, properties); + invokeOnAddAspect(nodeRef, defaultAspectDef.getName()); + + // Now add any default aspects for this aspect + addDefaultAspects(defaultAspectDef, node, properties); + } + } + + /** + * Drops the old primary association and creates a new one + */ + public ChildAssociationRef moveNode( + NodeRef nodeToMoveRef, + NodeRef newParentRef, + QName assocTypeQName, + QName assocQName) + throws InvalidNodeRefException + { + Assert.notNull(nodeToMoveRef); + Assert.notNull(newParentRef); + Assert.notNull(assocTypeQName); + Assert.notNull(assocQName); + + // check the node references + Node nodeToMove = getNodeNotNull(nodeToMoveRef); + Node newParentNode = getNodeNotNull(newParentRef); + // get the primary parent assoc + ChildAssoc oldAssoc = nodeDaoService.getPrimaryParentAssoc(nodeToMove); + ChildAssociationRef oldAssocRef = oldAssoc.getChildAssocRef(); + // get the old parent + Node oldParentNode = oldAssoc.getParent(); + + boolean movingStore = !nodeToMoveRef.getStoreRef().equals(newParentRef.getStoreRef()); + + // data needed for policy invocation + QName nodeToMoveTypeQName = nodeToMove.getTypeQName(); + Set nodeToMoveAspects = nodeToMove.getAspects(); + + // Invoke policy behaviour + if (movingStore) + { + invokeBeforeDeleteNode(nodeToMoveRef); + invokeBeforeCreateNode(newParentRef, assocTypeQName, assocQName, nodeToMoveTypeQName); + } + else + { + invokeBeforeDeleteChildAssociation(oldAssocRef); + invokeBeforeCreateChildAssociation(newParentRef, nodeToMoveRef, assocTypeQName, assocQName); + invokeBeforeUpdateNode(oldParentNode.getNodeRef()); // old parent will be updated + invokeBeforeUpdateNode(newParentRef); // new parent ditto + } + + // remove the child assoc from the old parent + // don't cascade as we will still need the node afterwards + nodeDaoService.deleteChildAssoc(oldAssoc, false); + + // create a new assoc + ChildAssoc newAssoc = nodeDaoService.newChildAssoc( + newParentNode, + nodeToMove, + true, + assocTypeQName, + assocQName); + setChildUniqueName(nodeToMove); // ensure uniqueness + ChildAssociationRef newAssocRef = newAssoc.getChildAssocRef(); + + // If the node is moving stores, then drag the node hierarchy with it + if (movingStore) + { + // do the move + Store newStore = newParentNode.getStore(); + moveNodeToStore(nodeToMove, newStore); + // the node reference will have changed too + nodeToMoveRef = nodeToMove.getNodeRef(); + } + + // check that no cyclic relationships have been created + getPaths(nodeToMoveRef, false); + + // invoke policy behaviour + if (movingStore) + { + // TODO for now indicate that the node has been archived to prevent the version history from being removed + // in the future a onMove policy could be added and remove the need for onDelete and onCreate to be fired here + invokeOnDeleteNode(oldAssocRef, nodeToMoveTypeQName, nodeToMoveAspects, true); + invokeOnCreateNode(newAssoc.getChildAssocRef()); + } + else + { + invokeOnCreateChildAssociation(newAssoc.getChildAssocRef()); + invokeOnDeleteChildAssociation(oldAssoc.getChildAssocRef()); + invokeOnUpdateNode(oldParentNode.getNodeRef()); + invokeOnUpdateNode(newParentRef); + } + invokeOnMoveNode(oldAssocRef, newAssocRef); + + // update the node status + nodeDaoService.recordChangeId(nodeToMoveRef); + + // done + return newAssoc.getChildAssocRef(); + } + + public void setChildAssociationIndex(ChildAssociationRef childAssocRef, int index) + { + // get nodes + Node parentNode = getNodeNotNull(childAssocRef.getParentRef()); + Node childNode = getNodeNotNull(childAssocRef.getChildRef()); + + ChildAssoc assoc = nodeDaoService.getChildAssoc( + parentNode, + childNode, + childAssocRef.getTypeQName(), + childAssocRef.getQName()); + if (assoc == null) + { + throw new InvalidChildAssociationRefException("Unable to set child association index: \n" + + " assoc: " + childAssocRef + "\n" + + " index: " + index, + childAssocRef); + } + // set the index + assoc.setIndex(index); + } + + public QName getType(NodeRef nodeRef) throws InvalidNodeRefException + { + Node node = getNodeNotNull(nodeRef); + return node.getTypeQName(); + } + + /** + * @see org.alfresco.service.cmr.repository.NodeService#setType(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName) + */ + public void setType(NodeRef nodeRef, QName typeQName) throws InvalidNodeRefException + { + // check the node type + TypeDefinition nodeTypeDef = dictionaryService.getType(typeQName); + if (nodeTypeDef == null) + { + throw new InvalidTypeException(typeQName); + } + + // Invoke policies + invokeBeforeUpdateNode(nodeRef); + + // Get the node and set the new type + Node node = getNodeNotNull(nodeRef); + node.setTypeQName(typeQName); + + // Add the default aspects to the node (update the properties with any new default values) + Map properties = this.getPropertiesImpl(node); + addDefaultAspects(nodeTypeDef, node, properties); + this.setProperties(nodeRef, properties); + + // Invoke policies + invokeOnUpdateNode(nodeRef); + } + + /** + * @see Node#getAspects() + */ + public void addAspect( + NodeRef nodeRef, + QName aspectTypeQName, + Map aspectProperties) + throws InvalidNodeRefException, InvalidAspectException + { + // check that the aspect is legal + AspectDefinition aspectDef = dictionaryService.getAspect(aspectTypeQName); + if (aspectDef == null) + { + throw new InvalidAspectException("The aspect is invalid: " + aspectTypeQName, aspectTypeQName); + } + + // Invoke policy behaviours + invokeBeforeUpdateNode(nodeRef); + invokeBeforeAddAspect(nodeRef, aspectTypeQName); + + Node node = getNodeNotNull(nodeRef); + + // attach the properties to the current node properties + Map nodeProperties = getPropertiesImpl(node); + + if (aspectProperties != null) + { + nodeProperties.putAll(aspectProperties); + } + + // Set any default property values that appear on the aspect + addDefaultPropertyValues(aspectDef, nodeProperties); + + // Add any dependant aspect + addDefaultAspects(aspectDef, node, nodeProperties); + + // Set the property values back on the node + setProperties(nodeRef, nodeProperties); + + // physically attach the aspect to the node + if (node.getAspects().add(aspectTypeQName) == true) + { + // Invoke policy behaviours + invokeOnUpdateNode(nodeRef); + invokeOnAddAspect(nodeRef, aspectTypeQName); + + // update the node status + nodeDaoService.recordChangeId(nodeRef); + } + } + + /** + * @see Node#getAspects() + */ + public void removeAspect(NodeRef nodeRef, QName aspectTypeQName) + throws InvalidNodeRefException, InvalidAspectException + { + // Invoke policy behaviours + invokeBeforeUpdateNode(nodeRef); + invokeBeforeRemoveAspect(nodeRef, aspectTypeQName); + + // get the aspect + AspectDefinition aspectDef = dictionaryService.getAspect(aspectTypeQName); + if (aspectDef == null) + { + throw new InvalidAspectException(aspectTypeQName); + } + // get the node + Node node = getNodeNotNull(nodeRef); + + // remove the aspect, if present + boolean removed = node.getAspects().remove(aspectTypeQName); + // if the aspect was present, remove the associated properties + if (removed) + { + Map nodeProperties = node.getProperties(); + Map propertyDefs = aspectDef.getProperties(); + for (QName propertyName : propertyDefs.keySet()) + { + nodeProperties.remove(propertyName); + } + + // Invoke policy behaviours + invokeOnUpdateNode(nodeRef); + invokeOnRemoveAspect(nodeRef, aspectTypeQName); + + // update the node status + nodeDaoService.recordChangeId(nodeRef); + } + } + + /** + * Performs a check on the set of node aspects + * + * @see Node#getAspects() + */ + public boolean hasAspect(NodeRef nodeRef, QName aspectRef) throws InvalidNodeRefException, InvalidAspectException + { + Node node = getNodeNotNull(nodeRef); + Set aspectQNames = node.getAspects(); + boolean hasAspect = aspectQNames.contains(aspectRef); + // done + return hasAspect; + } + + public Set getAspects(NodeRef nodeRef) throws InvalidNodeRefException + { + Node node = getNodeNotNull(nodeRef); + Set aspectQNames = node.getAspects(); + // copy the set to ensure initialization + Set ret = new HashSet(aspectQNames.size()); + ret.addAll(aspectQNames); + // done + return ret; + } + + public void deleteNode(NodeRef nodeRef) + { + boolean isArchivedNode = false; + boolean requiresDelete = false; + + // Invoke policy behaviours + invokeBeforeDeleteNode(nodeRef); + + // get the node + Node node = getNodeNotNull(nodeRef); + // get the primary parent-child relationship before it is gone + ChildAssociationRef childAssocRef = getPrimaryParent(nodeRef); + // get type and aspect QNames as they will be unavailable after the delete + QName nodeTypeQName = node.getTypeQName(); + Set nodeAspectQNames = node.getAspects(); + + // check if we need to archive the node + StoreRef archiveStoreRef = null; + if (nodeAspectQNames.contains(ContentModel.ASPECT_TEMPORARY)) + { + // the node has the temporary aspect meaning + // it can not be archived + requiresDelete = true; + isArchivedNode = false; + } + else + { + StoreRef storeRef = nodeRef.getStoreRef(); + archiveStoreRef = storeArchiveMap.getArchiveMap().get(storeRef); + // get the type and check if we need archiving + TypeDefinition typeDef = dictionaryService.getType(node.getTypeQName()); + if (typeDef == null || !typeDef.isArchive() || archiveStoreRef == null) + { + requiresDelete = true; + } + } + + if (requiresDelete) + { + // perform a normal deletion + nodeDaoService.deleteNode(node, true); + isArchivedNode = false; + } + else + { + // archive it + archiveNode(nodeRef, archiveStoreRef); + isArchivedNode = true; + } + + // Invoke policy behaviours + invokeOnDeleteNode(childAssocRef, nodeTypeQName, nodeAspectQNames, isArchivedNode); + } + + public ChildAssociationRef addChild(NodeRef parentRef, NodeRef childRef, QName assocTypeQName, QName assocQName) + { + // Invoke policy behaviours + invokeBeforeUpdateNode(parentRef); + invokeBeforeCreateChildAssociation(parentRef, childRef, assocTypeQName, assocQName); + + // get the parent node and ensure that it is a container node + Node parentNode = getNodeNotNull(parentRef); + // get the child node + Node childNode = getNodeNotNull(childRef); + // make the association + ChildAssoc assoc = nodeDaoService.newChildAssoc( + parentNode, + childNode, + false, + assocTypeQName, + assocQName); + // ensure name uniqueness + setChildUniqueName(childNode); + ChildAssociationRef assocRef = assoc.getChildAssocRef(); + NodeRef childNodeRef = assocRef.getChildRef(); + + // check that the child addition of the child has not created a cyclic relationship + // this functionality is provided for free in getPath + getPaths(childNodeRef, false); + + // Invoke policy behaviours + invokeOnCreateChildAssociation(assocRef); + invokeOnUpdateNode(parentRef); + + return assoc.getChildAssocRef(); + } + + public void removeChild(NodeRef parentRef, NodeRef childRef) throws InvalidNodeRefException + { + Node parentNode = getNodeNotNull(parentRef); + Node childNode = getNodeNotNull(childRef); + Long childNodeId = childNode.getId(); + + // get all the child assocs + ChildAssociationRef primaryAssocRef = null; + Collection assocs = nodeDaoService.getChildAssocs(parentNode); + assocs = new HashSet(assocs); // copy set as we will be modifying it + for (ChildAssoc assoc : assocs) + { + if (!assoc.getChild().getId().equals(childNodeId)) + { + continue; // not a matching association + } + ChildAssociationRef assocRef = assoc.getChildAssocRef(); + // Is this a primary association? + if (assoc.getIsPrimary()) + { + // keep the primary associaton for last + primaryAssocRef = assocRef; + } + else + { + // delete the association instance - it is not primary + invokeBeforeDeleteChildAssociation(assocRef); + nodeDaoService.deleteChildAssoc(assoc, true); // cascade + invokeOnDeleteChildAssociation(assocRef); + } + } + // remove the child if the primary association was a match + if (primaryAssocRef != null) + { + deleteNode(primaryAssocRef.getChildRef()); + } + + // Invoke policy behaviours + invokeOnUpdateNode(parentRef); + + // done + } + + public Map getProperties(NodeRef nodeRef) throws InvalidNodeRefException + { + Node node = getNodeNotNull(nodeRef); + return getPropertiesImpl(node); + } + + private Map getPropertiesImpl(Node node) throws InvalidNodeRefException + { + NodeRef nodeRef = node.getNodeRef(); + + Map nodeProperties = node.getProperties(); + Map ret = new HashMap(nodeProperties.size()); + // copy values + for (Map.Entry entry: nodeProperties.entrySet()) + { + QName propertyQName = entry.getKey(); + PropertyValue propertyValue = entry.getValue(); + // get the property definition + PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); + // convert to the correct type + Serializable value = makeSerializableValue(propertyDef, propertyValue); + // copy across + ret.put(propertyQName, value); + } + // spoof referencable properties + addReferencableProperties(nodeRef, node.getId(), ret); + // done + return ret; + } + + public Serializable getProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException + { + // spoof referencable properties + if (qname.equals(ContentModel.PROP_STORE_PROTOCOL)) + { + return nodeRef.getStoreRef().getProtocol(); + } + else if (qname.equals(ContentModel.PROP_STORE_IDENTIFIER)) + { + return nodeRef.getStoreRef().getIdentifier(); + } + else if (qname.equals(ContentModel.PROP_NODE_UUID)) + { + return nodeRef.getId(); + } + + // get the property from the node + Node node = getNodeNotNull(nodeRef); + + if (qname.equals(ContentModel.PROP_NODE_DBID)) + { + return node.getId(); + } + + Map properties = node.getProperties(); + PropertyValue propertyValue = properties.get(qname); + + // get the property definition + PropertyDefinition propertyDef = dictionaryService.getProperty(qname); + // convert to the correct type + Serializable value = makeSerializableValue(propertyDef, propertyValue); + // done + return value; + } + + /** + * Ensures that all required properties are present on the node and copies the + * property values to the Node. + *

+ * To remove a property, remove it from the map before calling this method. + * Null-valued properties are allowed. + *

+ * If any of the values are null, a marker object is put in to mimic nulls. They will be turned back into + * a real nulls when the properties are requested again. + * + * @see Node#getProperties() + */ + public void setProperties(NodeRef nodeRef, Map properties) throws InvalidNodeRefException + { + Node node = getNodeNotNull(nodeRef); + + // Invoke policy behaviours + invokeBeforeUpdateNode(nodeRef); + + // Do the set properties + Map propertiesBefore = getPropertiesImpl(node); + Map propertiesAfter = setPropertiesImpl(node, properties); + + setChildUniqueName(node); // ensure uniqueness + + // Invoke policy behaviours + invokeOnUpdateNode(nodeRef); + invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter); + } + + /** + * Does the work of setting the property values. Returns a map containing the state of the properties after the set + * operation is complete. + * + * @param node the node + * @param properties the map of property values + * @return the map of property values after the set operation is complete + * @throws InvalidNodeRefException + */ + private Map setPropertiesImpl(Node node, Map properties) throws InvalidNodeRefException + { + ParameterCheck.mandatory("properties", properties); + + // remove referencable properties + removeReferencableProperties(properties); + + // copy properties onto node + Map nodeProperties = node.getProperties(); + nodeProperties.clear(); + + // check the property type and copy the values across + for (QName propertyQName : properties.keySet()) + { + PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); + Serializable value = properties.get(propertyQName); + // get a persistable value + PropertyValue propertyValue = makePropertyValue(propertyDef, value); + nodeProperties.put(propertyQName, propertyValue); + } + + // update the node status + NodeRef nodeRef = node.getNodeRef(); + nodeDaoService.recordChangeId(nodeRef); + + // Return the properties after + return Collections.unmodifiableMap(properties); + } + + /** + * Gets the properties map, sets the value (null is allowed) and checks that the new set + * of properties is valid. + * + * @see DbNodeServiceImpl.NullPropertyValue + */ + public void setProperty(NodeRef nodeRef, QName qname, Serializable value) throws InvalidNodeRefException + { + Assert.notNull(qname); + + // Invoke policy behaviours + invokeBeforeUpdateNode(nodeRef); + + // get the node + Node node = getNodeNotNull(nodeRef); + + // Do the set operation + Map propertiesBefore = getPropertiesImpl(node); + Map propertiesAfter = setPropertyImpl(node, qname, value); + + if (qname.equals(ContentModel.PROP_NAME)) + { + setChildUniqueName(node); // ensure uniqueness + } + + // Invoke policy behaviours + invokeOnUpdateNode(nodeRef); + invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter); + } + + /** + * Does the work of setting a property value. Returns the values of the properties after the set operation is + * complete. + * + * @param node the node + * @param qname the qname of the property + * @param value the value of the property + * @return the values of the properties after the set operation is complete + * @throws InvalidNodeRefException + */ + public Map setPropertyImpl(Node node, QName qname, Serializable value) throws InvalidNodeRefException + { + NodeRef nodeRef = node.getNodeRef(); + + Map properties = node.getProperties(); + PropertyDefinition propertyDef = dictionaryService.getProperty(qname); + // get a persistable value + PropertyValue propertyValue = makePropertyValue(propertyDef, value); + properties.put(qname, propertyValue); + + // update the node status + nodeDaoService.recordChangeId(nodeRef); + + return getPropertiesImpl(node); + } + + /** + * Transforms {@link Node#getParentAssocs()} to a new collection + */ + public Collection getParents(NodeRef nodeRef) throws InvalidNodeRefException + { + Node node = getNodeNotNull(nodeRef); + // get the assocs pointing to it + Collection parentAssocs = node.getParentAssocs(); + // list of results + Collection results = new ArrayList(parentAssocs.size()); + for (ChildAssoc assoc : parentAssocs) + { + // get the parent + Node parentNode = assoc.getParent(); + results.add(parentNode.getNodeRef()); + } + // done + return results; + } + + /** + * Filters out any associations if their qname is not a match to the given pattern. + */ + public List getParentAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern) + { + Node node = getNodeNotNull(nodeRef); + // get the assocs pointing to it + Collection parentAssocs = node.getParentAssocs(); + // shortcut if there are no assocs + if (parentAssocs.size() == 0) + { + return Collections.emptyList(); + } + // list of results + List results = new ArrayList(parentAssocs.size()); + for (ChildAssoc assoc : parentAssocs) + { + // does the qname match the pattern? + if (!qnamePattern.isMatch(assoc.getQname()) || !typeQNamePattern.isMatch(assoc.getTypeQName())) + { + // no match - ignore + continue; + } + results.add(assoc.getChildAssocRef()); + } + // done + return results; + } + + /** + * Filters out any associations if their qname is not a match to the given pattern. + */ + public List getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern) + { + Node node = getNodeNotNull(nodeRef); + // get the assocs pointing from it + Collection childAssocRefs = nodeDaoService.getChildAssocRefs(node); + // shortcut if there are no assocs + if (childAssocRefs.size() == 0) + { + return Collections.emptyList(); + } + // sort results + ArrayList orderedList = new ArrayList(childAssocRefs); + Collections.sort(orderedList); + + // list of results + int nthSibling = 0; + Iterator iterator = orderedList.iterator(); + while(iterator.hasNext()) + { + ChildAssociationRef childAssocRef = iterator.next(); + // does the qname match the pattern? + if (!qnamePattern.isMatch(childAssocRef.getQName()) || !typeQNamePattern.isMatch(childAssocRef.getTypeQName())) + { + // no match - remove + iterator.remove(); + } + else + { + childAssocRef.setNthSibling(nthSibling); + nthSibling++; + } + } + // done + return orderedList; + } + + public NodeRef getChildByName(NodeRef nodeRef, QName assocTypeQName, String childName) + { + Node node = getNodeNotNull(nodeRef); + ChildAssoc childAssoc = nodeDaoService.getChildAssoc(node, assocTypeQName, childName); + if (childAssoc != null) + { + return childAssoc.getChild().getNodeRef(); + } + else + { + return null; + } + } + + public ChildAssociationRef getPrimaryParent(NodeRef nodeRef) throws InvalidNodeRefException + { + Node node = getNodeNotNull(nodeRef); + // get the primary parent assoc + ChildAssoc assoc = nodeDaoService.getPrimaryParentAssoc(node); + + // done - the assoc may be null for a root node + ChildAssociationRef assocRef = null; + if (assoc == null) + { + assocRef = new ChildAssociationRef(null, null, null, nodeRef); + } + else + { + assocRef = assoc.getChildAssocRef(); + } + return assocRef; + } + + public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) + throws InvalidNodeRefException, AssociationExistsException + { + // Invoke policy behaviours + invokeBeforeUpdateNode(sourceRef); + + Node sourceNode = getNodeNotNull(sourceRef); + Node targetNode = getNodeNotNull(targetRef); + // see if it exists + NodeAssoc assoc = nodeDaoService.getNodeAssoc(sourceNode, targetNode, assocTypeQName); + if (assoc != null) + { + throw new AssociationExistsException(sourceRef, targetRef, assocTypeQName); + } + // we are sure that the association doesn't exist - make it + assoc = nodeDaoService.newNodeAssoc(sourceNode, targetNode, assocTypeQName); + AssociationRef assocRef = assoc.getNodeAssocRef(); + + // Invoke policy behaviours + invokeOnUpdateNode(sourceRef); + invokeOnCreateAssociation(assocRef); + + return assocRef; + } + + public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) + throws InvalidNodeRefException + { + Node sourceNode = getNodeNotNull(sourceRef); + Node targetNode = getNodeNotNull(targetRef); + // get the association + NodeAssoc assoc = nodeDaoService.getNodeAssoc(sourceNode, targetNode, assocTypeQName); + if (assoc == null) + { + // nothing to remove + return; + } + AssociationRef assocRef = assoc.getNodeAssocRef(); + + // Invoke policy behaviours + invokeBeforeUpdateNode(sourceRef); + + // delete it + nodeDaoService.deleteNodeAssoc(assoc); + + // Invoke policy behaviours + invokeOnUpdateNode(sourceRef); + invokeOnDeleteAssociation(assocRef); + } + + public List getTargetAssocs(NodeRef sourceRef, QNamePattern qnamePattern) + { + Node sourceNode = getNodeNotNull(sourceRef); + // get all assocs to target + Collection assocs = nodeDaoService.getTargetNodeAssocs(sourceNode); + List nodeAssocRefs = new ArrayList(assocs.size()); + for (NodeAssoc assoc : assocs) + { + // check qname pattern + if (!qnamePattern.isMatch(assoc.getTypeQName())) + { + continue; // the assoc name doesn't match the pattern given + } + nodeAssocRefs.add(assoc.getNodeAssocRef()); + } + // done + return nodeAssocRefs; + } + + public List getSourceAssocs(NodeRef targetRef, QNamePattern qnamePattern) + { + Node targetNode = getNodeNotNull(targetRef); + // get all assocs to source + Collection assocs = nodeDaoService.getSourceNodeAssocs(targetNode); + List nodeAssocRefs = new ArrayList(assocs.size()); + for (NodeAssoc assoc : assocs) + { + // check qname pattern + if (!qnamePattern.isMatch(assoc.getTypeQName())) + { + continue; // the assoc name doesn't match the pattern given + } + nodeAssocRefs.add(assoc.getNodeAssocRef()); + } + // done + return nodeAssocRefs; + } + + /** + * Recursive method used to build up paths from a given node to the root. + *

+ * Whilst walking up the hierarchy to the root, some nodes may have a root 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( + final Node currentNode, + final Path currentPath, + Collection completedPaths, + Stack assocStack, + boolean primaryOnly) + throws CyclicChildRelationshipException + { + NodeRef currentNodeRef = currentNode.getNodeRef(); + // get the parent associations of the given node + Collection parentAssocs = currentNode.getParentAssocs(); + // does the node have parents + boolean hasParents = parentAssocs.size() > 0; + // does the current node have a root aspect? + boolean isRoot = hasAspect(currentNodeRef, ContentModel.ASPECT_ROOT); + boolean isStoreRoot = currentNode.getTypeQName().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, + getRootNode(currentNode.getNodeRef().getStoreRef())); + // 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(), + getRootNode(currentNode.getNodeRef().getStoreRef()), + 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 (parentAssocs.size() == 0 && !isRoot) + { + throw new RuntimeException("Node without parents does not have root aspect: " + + currentNodeRef); + } + // walk up each parent association + for (ChildAssoc assoc : parentAssocs) + { + // does the association already exist in the stack + if (assocStack.contains(assoc)) + { + // the association was present already + throw new CyclicChildRelationshipException( + "Cyclic parent-child relationship detected: \n" + + " current node: " + currentNode + "\n" + + " current path: " + currentPath + "\n" + + " next assoc: " + assoc, + assoc); + } + // do we consider only primary assocs? + if (primaryOnly && !assoc.getIsPrimary()) + { + continue; + } + // build a path element + NodeRef parentRef = assoc.getParent().getNodeRef(); + QName qname = assoc.getQname(); + NodeRef childRef = assoc.getChild().getNodeRef(); + boolean isPrimary = assoc.getIsPrimary(); + // build a real association reference + ChildAssociationRef assocRef = new ChildAssociationRef(assoc.getTypeQName(), parentRef, qname, childRef, isPrimary, -1); + // Ordering is not important here: We are building distinct paths upwards + 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 + Node parentNode = assoc.getParent(); + + // push the assoc stack, recurse and pop + assocStack.push(assoc); + prependPaths(parentNode, path, completedPaths, assocStack, primaryOnly); + assocStack.pop(); + } + // done + } + + /** + * @see #getPaths(NodeRef, boolean) + * @see #prependPaths(Node, Path, Collection, Stack, boolean) + */ + public Path getPath(NodeRef nodeRef) throws InvalidNodeRefException + { + List paths = getPaths(nodeRef, true); // checks primary path count + if (paths.size() == 1) + { + return paths.get(0); // we know there is only one + } + throw new RuntimeException("Primary path count not checked"); // checked by getPaths() + } + + /** + * When searching for primaryOnly == true, checks that there is exactly + * one path. + * @see #prependPaths(Node, Path, Collection, Stack, boolean) + */ + public List getPaths(NodeRef nodeRef, boolean primaryOnly) throws InvalidNodeRefException + { + // get the starting node + Node node = getNodeNotNull(nodeRef); + // create storage for the paths - only need 1 bucket if we are looking for the primary path + List paths = new ArrayList(primaryOnly ? 1 : 10); + // create an empty current path to start from + Path currentPath = new Path(); + // create storage for touched associations + Stack assocStack = new Stack(); + // call recursive method to sort it out + prependPaths(node, currentPath, paths, assocStack, primaryOnly); + + // check that for the primary only case we have exactly one path + if (primaryOnly && paths.size() != 1) + { + throw new RuntimeException("Node has " + paths.size() + " primary paths: " + nodeRef); + } + + // done + if (loggerPaths.isDebugEnabled()) + { + StringBuilder sb = new StringBuilder(256); + if (primaryOnly) + { + sb.append("Primary paths"); + } + else + { + sb.append("Paths"); + } + sb.append(" for node ").append(nodeRef); + for (Path path : paths) + { + sb.append("\n").append(" ").append(path); + } + loggerPaths.debug(sb); + } + return paths; + } + + private void archiveNode(NodeRef nodeRef, StoreRef archiveStoreRef) + { + Node node = getNodeNotNull(nodeRef); + ChildAssoc primaryParentAssoc = nodeDaoService.getPrimaryParentAssoc(node); + + // add the aspect + Set aspects = node.getAspects(); + aspects.add(ContentModel.ASPECT_ARCHIVED); + Map properties = node.getProperties(); + PropertyValue archivedByProperty = makePropertyValue( + dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_BY), + AuthenticationUtil.getCurrentUserName()); + properties.put(ContentModel.PROP_ARCHIVED_BY, archivedByProperty); + PropertyValue archivedDateProperty = makePropertyValue( + dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_DATE), + new Date()); + properties.put(ContentModel.PROP_ARCHIVED_DATE, archivedDateProperty); + PropertyValue archivedPrimaryParentNodeRefProperty = makePropertyValue( + dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC), + primaryParentAssoc.getChildAssocRef()); + properties.put(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC, archivedPrimaryParentNodeRefProperty); + PropertyValue originalOwnerProperty = properties.get(ContentModel.PROP_OWNER); + PropertyValue originalCreatorProperty = properties.get(ContentModel.PROP_CREATOR); + if (originalOwnerProperty != null || originalCreatorProperty != null) + { + properties.put( + ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER, + originalOwnerProperty != null ? originalOwnerProperty : originalCreatorProperty); + } + + // change the node ownership + aspects.add(ContentModel.ASPECT_OWNABLE); + PropertyValue newOwnerProperty = makePropertyValue( + dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER), + AuthenticationUtil.getCurrentUserName()); + properties.put(ContentModel.PROP_OWNER, newOwnerProperty); + + // move the node + NodeRef archiveStoreRootNodeRef = getRootNode(archiveStoreRef); + moveNode( + nodeRef, + archiveStoreRootNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedItem")); + + // get the IDs of all the node's primary children, including its own + Map nodesById = getNodeHierarchy(node, null); + + // Archive all the associations between the archived nodes and non-archived nodes + for (Node nodeToArchive : nodesById.values()) + { + archiveAssocs(nodeToArchive, nodesById); + } + + // the node reference has changed due to the store move + nodeRef = node.getNodeRef(); + } + + /** + * Performs all the necessary housekeeping involved in changing a node's store. + * This method cascades down through all the primary children of the node as + * well. + * + * @param node the node whose store is changing + * @param store the new store for the node + */ + private void moveNodeToStore(Node node, Store store) + { + // get the IDs of all the node's primary children, including its own + Map nodesById = getNodeHierarchy(node, null); + + // move each node into the archive store + for (Node nodeToMove : nodesById.values()) + { + NodeRef oldNodeRef = nodeToMove.getNodeRef(); + nodeToMove.setStore(store); + NodeRef newNodeRef = nodeToMove.getNodeRef(); + + // update old status + NodeStatus oldNodeStatus = nodeDaoService.getNodeStatus(oldNodeRef, true); + oldNodeStatus.setNode(null); + // create the new status + NodeStatus newNodeStatus = nodeDaoService.getNodeStatus(newNodeRef, true); + newNodeStatus.setNode(nodeToMove); + } + } + + /** + * Fill the map of all primary children below the given node. + * The given node will be added to the map and the method is recursive + * to all primary children. + * + * @param node the start of the hierarchy + * @param nodesById a map of nodes that will be reused as the return value + * @return Returns a map of nodes in the hierarchy keyed by their IDs + */ + private Map getNodeHierarchy(Node node, Map nodesById) + { + if (nodesById == null) + { + nodesById = new HashMap(23); + } + + Long id = node.getId(); + if (nodesById.containsKey(id)) + { + // this ID was already added - circular reference + logger.warn("Circular hierarchy found including node " + id); + return nodesById; + } + // add the node to the map + nodesById.put(id, node); + // recurse into the primary children + Collection childAssocs = nodeDaoService.getChildAssocs(node); + for (ChildAssoc childAssoc : childAssocs) + { + // cascade into primary associations + if (childAssoc.getIsPrimary()) + { + Node primaryChild = childAssoc.getChild(); + nodesById = getNodeHierarchy(primaryChild, nodesById); + } + } + return nodesById; + } + + /** + * Archive all associations to and from the given node, with the + * exception of associations to or from nodes in the given map. + *

+ * Primary parent associations are also ignored. + * + * @param node the node whose associations must be archived + * @param nodesById a map of nodes partaking in the archival process + */ + private void archiveAssocs(Node node, Map nodesById) + { + List childAssocsToDelete = new ArrayList(5); + // child associations + ArrayList archivedChildAssocRefs = new ArrayList(5); + Collection childAssocs = nodeDaoService.getChildAssocs(node); + for (ChildAssoc assoc : childAssocs) + { + Long relatedNodeId = assoc.getChild().getId(); + if (nodesById.containsKey(relatedNodeId)) + { + // a sibling in the archive process + continue; + } + childAssocsToDelete.add(assoc); + archivedChildAssocRefs.add(assoc.getChildAssocRef()); + } + // parent associations + ArrayList archivedParentAssocRefs = new ArrayList(5); + for (ChildAssoc assoc : node.getParentAssocs()) + { + Long relatedNodeId = assoc.getParent().getId(); + if (nodesById.containsKey(relatedNodeId)) + { + // a sibling in the archive process + continue; + } + else if (assoc.getIsPrimary()) + { + // ignore the primary parent as this is handled more specifically + continue; + } + childAssocsToDelete.add(assoc); + archivedParentAssocRefs.add(assoc.getChildAssocRef()); + } + + List nodeAssocsToDelete = new ArrayList(5); + // source associations + ArrayList archivedSourceAssocRefs = new ArrayList(5); + for (NodeAssoc assoc : nodeDaoService.getSourceNodeAssocs(node)) + { + Long relatedNodeId = assoc.getSource().getId(); + if (nodesById.containsKey(relatedNodeId)) + { + // a sibling in the archive process + continue; + } + nodeAssocsToDelete.add(assoc); + archivedSourceAssocRefs.add(assoc.getNodeAssocRef()); + } + // target associations + ArrayList archivedTargetAssocRefs = new ArrayList(5); + for (NodeAssoc assoc : nodeDaoService.getTargetNodeAssocs(node)) + { + Long relatedNodeId = assoc.getTarget().getId(); + if (nodesById.containsKey(relatedNodeId)) + { + // a sibling in the archive process + continue; + } + nodeAssocsToDelete.add(assoc); + archivedTargetAssocRefs.add(assoc.getNodeAssocRef()); + } + // delete child assocs + for (ChildAssoc assoc : childAssocsToDelete) + { + nodeDaoService.deleteChildAssoc(assoc, false); + } + // delete node assocs + for (NodeAssoc assoc : nodeAssocsToDelete) + { + nodeDaoService.deleteNodeAssoc(assoc); + } + + // add archived aspect + node.getAspects().add(ContentModel.ASPECT_ARCHIVED_ASSOCS); + // set properties + Map properties = node.getProperties(); + + if (archivedParentAssocRefs.size() > 0) + { + PropertyDefinition propertyDef = dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_PARENT_ASSOCS); + PropertyValue propertyValue = makePropertyValue(propertyDef, archivedParentAssocRefs); + properties.put(ContentModel.PROP_ARCHIVED_PARENT_ASSOCS, propertyValue); + } + if (archivedChildAssocRefs.size() > 0) + { + PropertyDefinition propertyDef = dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_CHILD_ASSOCS); + PropertyValue propertyValue = makePropertyValue(propertyDef, archivedChildAssocRefs); + properties.put(ContentModel.PROP_ARCHIVED_CHILD_ASSOCS, propertyValue); + } + if (archivedSourceAssocRefs.size() > 0) + { + PropertyDefinition propertyDef = dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS); + PropertyValue propertyValue = makePropertyValue(propertyDef, archivedSourceAssocRefs); + properties.put(ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS, propertyValue); + } + if (archivedTargetAssocRefs.size() > 0) + { + PropertyDefinition propertyDef = dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_TARGET_ASSOCS); + PropertyValue propertyValue = makePropertyValue(propertyDef, archivedTargetAssocRefs); + properties.put(ContentModel.PROP_ARCHIVED_TARGET_ASSOCS, propertyValue); + } + } + + public NodeRef getStoreArchiveNode(StoreRef storeRef) + { + StoreRef archiveStoreRef = storeArchiveMap.getArchiveMap().get(storeRef); + if (archiveStoreRef == null) + { + // no mapping for the given store + return null; + } + else + { + return getRootNode(archiveStoreRef); + } + } + + public NodeRef restoreNode(NodeRef archivedNodeRef, NodeRef destinationParentNodeRef, QName assocTypeQName, QName assocQName) + { + Node archivedNode = getNodeNotNull(archivedNodeRef); + Set aspects = archivedNode.getAspects(); + Map properties = archivedNode.getProperties(); + // the node must be a top-level archive node + if (!aspects.contains(ContentModel.ASPECT_ARCHIVED)) + { + throw new AlfrescoRuntimeException("The node to archive is not an archive node"); + } + ChildAssociationRef originalPrimaryParentAssocRef = (ChildAssociationRef) makeSerializableValue( + dictionaryService.getProperty(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC), + properties.get(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC)); + PropertyValue originalOwnerProperty = properties.get(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER); + // remove the aspect archived aspect + aspects.remove(ContentModel.ASPECT_ARCHIVED); + properties.remove(ContentModel.PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC); + properties.remove(ContentModel.PROP_ARCHIVED_BY); + properties.remove(ContentModel.PROP_ARCHIVED_DATE); + properties.remove(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER); + + // restore the original ownership + if (originalOwnerProperty != null) + { + aspects.add(ContentModel.ASPECT_OWNABLE); + properties.put(ContentModel.PROP_OWNER, originalOwnerProperty); + } + + if (destinationParentNodeRef == null) + { + // we must restore to the original location + destinationParentNodeRef = originalPrimaryParentAssocRef.getParentRef(); + } + // check the associations + if (assocTypeQName == null) + { + assocTypeQName = originalPrimaryParentAssocRef.getTypeQName(); + } + if (assocQName == null) + { + assocQName = originalPrimaryParentAssocRef.getQName(); + } + + // move the node to the target parent, which may or may not be the original parent + moveNode( + archivedNodeRef, + destinationParentNodeRef, + assocTypeQName, + assocQName); + + // get the IDs of all the node's primary children, including its own + Map restoredNodesById = getNodeHierarchy(archivedNode, null); + // Restore the archived associations, if required + for (Node restoredNode : restoredNodesById.values()) + { + restoreAssocs(restoredNode); + } + + // the node reference has changed due to the store move + NodeRef restoredNodeRef = archivedNode.getNodeRef(); + + // done + if (logger.isDebugEnabled()) + { + logger.debug("Restored node: \n" + + " original noderef: " + archivedNodeRef + "\n" + + " restored noderef: " + restoredNodeRef + "\n" + + " new parent: " + destinationParentNodeRef); + } + return restoredNodeRef; + } + + private void restoreAssocs(Node node) + { + NodeRef nodeRef = node.getNodeRef(); + // set properties + Map properties = node.getProperties(); + + // restore parent associations + Collection parentAssocRefs = (Collection) getProperty( + nodeRef, + ContentModel.PROP_ARCHIVED_PARENT_ASSOCS); + if (parentAssocRefs != null) + { + for (ChildAssociationRef assocRef : parentAssocRefs) + { + NodeRef parentNodeRef = assocRef.getParentRef(); + if (!exists(parentNodeRef)) + { + continue; + } + Node parentNode = getNodeNotNull(parentNodeRef); + // get the name to use for the unique child check + QName assocTypeQName = assocRef.getTypeQName(); + nodeDaoService.newChildAssoc( + parentNode, + node, + assocRef.isPrimary(), + assocTypeQName, + assocRef.getQName()); + } + properties.remove(ContentModel.PROP_ARCHIVED_PARENT_ASSOCS); + } + + // make sure that the node name uniqueness is enforced + setChildUniqueName(node); + + // restore child associations + Collection childAssocRefs = (Collection) getProperty( + nodeRef, + ContentModel.PROP_ARCHIVED_CHILD_ASSOCS); + if (childAssocRefs != null) + { + for (ChildAssociationRef assocRef : childAssocRefs) + { + NodeRef childNodeRef = assocRef.getChildRef(); + if (!exists(childNodeRef)) + { + continue; + } + Node childNode = getNodeNotNull(childNodeRef); + QName assocTypeQName = assocRef.getTypeQName(); + // get the name to use for the unique child check + nodeDaoService.newChildAssoc( + node, + childNode, + assocRef.isPrimary(), + assocTypeQName, + assocRef.getQName()); + // ensure that the name uniqueness is enforced for the child node + setChildUniqueName(childNode); + } + properties.remove(ContentModel.PROP_ARCHIVED_CHILD_ASSOCS); + } + // restore source associations + Collection sourceAssocRefs = (Collection) getProperty( + nodeRef, + ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS); + if (sourceAssocRefs != null) + { + for (AssociationRef assocRef : sourceAssocRefs) + { + NodeRef sourceNodeRef = assocRef.getSourceRef(); + if (!exists(sourceNodeRef)) + { + continue; + } + Node sourceNode = getNodeNotNull(sourceNodeRef); + nodeDaoService.newNodeAssoc(sourceNode, node, assocRef.getTypeQName()); + } + properties.remove(ContentModel.PROP_ARCHIVED_SOURCE_ASSOCS); + } + // restore target associations + Collection targetAssocRefs = (Collection) getProperty( + nodeRef, + ContentModel.PROP_ARCHIVED_TARGET_ASSOCS); + if (targetAssocRefs != null) + { + for (AssociationRef assocRef : targetAssocRefs) + { + NodeRef targetNodeRef = assocRef.getTargetRef(); + if (!exists(targetNodeRef)) + { + continue; + } + Node targetNode = getNodeNotNull(targetNodeRef); + nodeDaoService.newNodeAssoc(node, targetNode, assocRef.getTypeQName()); + } + properties.remove(ContentModel.PROP_ARCHIVED_TARGET_ASSOCS); + } + // remove the aspect + node.getAspects().remove(ContentModel.ASPECT_ARCHIVED_ASSOCS); + } + + /** + * Checks the dictionary's definition of the association to assign a unique name to the child node. + * + * @param assocTypeQName the type of the child association + * @param childNode the child node being added. The name will be extracted from it, if necessary. + * @return Returns the value to be put on the child association for uniqueness, or null if + */ + private void setChildUniqueName(Node childNode) + { + // get the name property + Map properties = childNode.getProperties(); + PropertyValue nameValue = properties.get(ContentModel.PROP_NAME); + String useName = null; + if (nameValue == null) + { + // no name has been assigned, so assign the ID of the child node + useName = childNode.getUuid(); + } + else + { + useName = (String) nameValue.getValue(DataTypeDefinition.TEXT); + } + // get all the parent assocs + Collection parentAssocs = childNode.getParentAssocs(); + for (ChildAssoc assoc : parentAssocs) + { + QName assocTypeQName = assoc.getTypeQName(); + AssociationDefinition assocDef = dictionaryService.getAssociation(assocTypeQName); + if (!assocDef.isChild()) + { + throw new DataIntegrityViolationException("Child association has non-child type: " + assoc.getId()); + } + ChildAssociationDefinition childAssocDef = (ChildAssociationDefinition) assocDef; + if (childAssocDef.getDuplicateChildNamesAllowed()) + { + // the name is irrelevant, so it doesn't need to be put into the unique key + nodeDaoService.setChildNameUnique(assoc, null); + } + else + { + nodeDaoService.setChildNameUnique(assoc, useName); + } + } + // done + if (logger.isDebugEnabled()) + { + logger.debug( + "Unique name set for all " + parentAssocs.size() + " parent associations: \n" + + " name: " + useName); + } + } +} diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java index 43341b58c3..d99ddb00fe 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java @@ -17,6 +17,7 @@ package org.alfresco.repo.node.db; import java.io.Serializable; +import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; @@ -30,6 +31,8 @@ import org.alfresco.repo.node.BaseNodeServiceTest; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.TransactionUtil; import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.NodeRef; @@ -47,6 +50,7 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest { private TransactionService txnService; private NodeDaoService nodeDaoService; + private DictionaryService dictionaryService; protected NodeService getNodeService() { @@ -59,6 +63,7 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest super.onSetUpInTransaction(); txnService = (TransactionService) applicationContext.getBean("transactionComponent"); nodeDaoService = (NodeDaoService) applicationContext.getBean("nodeDaoService"); + dictionaryService = (DictionaryService) applicationContext.getBean("dictionaryService"); } /** @@ -258,18 +263,34 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest /** * Checks that the string_value retrieval against a property type is working */ - public void testGetContentDataStringValues() throws Exception + public void testGetContentDataValues() throws Exception { - ContentData contentData = new ContentData("abc", MimetypeMap.MIMETYPE_TEXT_PLAIN, 0L, null); - // put this in as a random property + final DataTypeDefinition contentDataType = dictionaryService.getDataType(DataTypeDefinition.CONTENT); + + ContentData contentDataSingle = new ContentData("url-single", MimetypeMap.MIMETYPE_TEXT_PLAIN, 0L, null); + ContentData contentDataMultiple = new ContentData("url-multiple", MimetypeMap.MIMETYPE_TEXT_PLAIN, 0L, null); + // put this in as a random single property nodeService.setProperty( rootNodeRef, - QName.createQName(NAMESPACE, "random"), - contentData); + QName.createQName(NAMESPACE, "random-single"), + contentDataSingle); + + // create a collection of mixed types + ArrayList collection = new ArrayList(3); + collection.add("abc"); + collection.add(new Integer(123)); + collection.add(contentDataMultiple); + nodeService.setProperty( + rootNodeRef, + QName.createQName(NAMESPACE, "random-multiple"), + collection); + // get a list of all content values - List contentDataStrings = nodeDaoService.getContentDataStrings(); - assertNotNull(contentDataStrings); - assertTrue("ContentData not represented as a String in results", - contentDataStrings.contains(contentData.toString())); + List allContentDatas = nodeDaoService.getPropertyValuesByActualType(contentDataType); + assertTrue("At least two instances expected", allContentDatas.size() >= 2); + assertTrue("Single content data not present in results", + allContentDatas.contains(contentDataSingle)); + assertTrue("Multi-valued buried content data not present in results", + allContentDatas.contains(contentDataMultiple)); } } diff --git a/source/java/org/alfresco/repo/node/db/NodeDaoService.java b/source/java/org/alfresco/repo/node/db/NodeDaoService.java index 3fba9af4f9..c44fb7fca7 100644 --- a/source/java/org/alfresco/repo/node/db/NodeDaoService.java +++ b/source/java/org/alfresco/repo/node/db/NodeDaoService.java @@ -16,6 +16,7 @@ */ package org.alfresco.repo.node.db; +import java.io.Serializable; import java.util.Collection; import java.util.List; @@ -24,9 +25,12 @@ import org.alfresco.repo.domain.Node; import org.alfresco.repo.domain.NodeAssoc; import org.alfresco.repo.domain.NodeStatus; import org.alfresco.repo.domain.Store; +import org.alfresco.repo.domain.Transaction; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.InvalidTypeException; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.namespace.QName; /** @@ -76,11 +80,12 @@ public interface NodeDaoService * null is returned. * * @param nodeRef the node reference - * @param create true to create the entity if it doesn't exist + * @param create true if the node status is to be updated in the transaction, i.e. + * the current transaction must be assigned to the status * @return Returns the node status if the node exists or once existed, otherwise * returns null if create == false */ - public NodeStatus getNodeStatus(NodeRef nodeRef, boolean create); + public NodeStatus getNodeStatus(NodeRef nodeRef, boolean update); /** * Sets the current transaction ID on the node status. Note that the node @@ -224,10 +229,18 @@ public interface NodeDaoService public void deleteNodeAssoc(NodeAssoc assoc); /** - * Fetch all content data strings. These are all string values that begin - * with contentUrl=. + * Fetch all property values for the given type definition. This will also dig out values that + * were persisted as type d:any. * - * @return Returns the string values for content data + * @return Returns the values for the given type definition */ - public List getContentDataStrings(); + public List getPropertyValuesByActualType(DataTypeDefinition actualDataTypeDefinition); + + public Transaction getLastTxn(final StoreRef storeRef); + public int getTxnUpdateCountForStore(final StoreRef storeRef, final long txnId); + public int getTxnDeleteCountForStore(final StoreRef storeRef, final long txnId); + public int getTransactionCount(); + public List getNextTxns(final Transaction lastTxn, final int count); + public List getTxnChangesForStore(final StoreRef storeRef, final long txnId); + public List getTxnChanges(final long txnId); } diff --git a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java index b7f35e16ed..8881eea7d6 100644 --- a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java @@ -22,10 +22,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import java.util.zip.CRC32; import org.alfresco.error.AlfrescoRuntimeException; @@ -35,6 +33,7 @@ import org.alfresco.repo.domain.Node; import org.alfresco.repo.domain.NodeAssoc; import org.alfresco.repo.domain.NodeKey; import org.alfresco.repo.domain.NodeStatus; +import org.alfresco.repo.domain.PropertyValue; import org.alfresco.repo.domain.Server; import org.alfresco.repo.domain.Store; import org.alfresco.repo.domain.StoreKey; @@ -48,19 +47,25 @@ import org.alfresco.repo.domain.hibernate.StoreImpl; import org.alfresco.repo.domain.hibernate.TransactionImpl; import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.repo.transaction.TransactionAwareSingleton; import org.alfresco.repo.transaction.TransactionalDao; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.InvalidTypeException; import org.alfresco.service.cmr.repository.AssociationExistsException; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.cmr.repository.datatype.TypeConverter; import org.alfresco.service.namespace.QName; import org.alfresco.util.GUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.ObjectDeletedException; import org.hibernate.Query; +import org.hibernate.ScrollMode; +import org.hibernate.ScrollableResults; import org.hibernate.Session; import org.springframework.dao.DataAccessException; import org.springframework.dao.DataIntegrityViolationException; @@ -83,7 +88,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements private static final String QUERY_GET_NODE_ASSOCS_TO_AND_FROM = "node.GetNodeAssocsToAndFrom"; private static final String QUERY_GET_TARGET_ASSOCS = "node.GetTargetAssocs"; private static final String QUERY_GET_SOURCE_ASSOCS = "node.GetSourceAssocs"; - private static final String QUERY_GET_CONTENT_DATA_STRINGS = "node.GetContentDataStrings"; + private static final String QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_ACTUAL_TYPE = "node.GetNodesWithPropertyValuesByActualType"; private static final String QUERY_GET_SERVER_BY_IPADDRESS = "server.getServerByIpAddress"; private static Log logger = LogFactory.getLog(HibernateNodeDaoServiceImpl.class); @@ -91,9 +96,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements /** a uuid identifying this unique instance */ private final String uuid; - private final ReadLock serverReadLock; - private final WriteLock serverWriteLock; - private Server server; + private static TransactionAwareSingleton serverIdSingleton = new TransactionAwareSingleton(); /** * @@ -101,10 +104,6 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements public HibernateNodeDaoServiceImpl() { this.uuid = GUID.generate(); - - ReentrantReadWriteLock serverReadWriteLock = new ReentrantReadWriteLock(); - serverReadLock = serverReadWriteLock.readLock(); - serverWriteLock = serverReadWriteLock.writeLock(); } /** @@ -137,21 +136,16 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements */ private Server getServer() { - // get readlock - serverReadLock.lock(); - try + Long serverId = serverIdSingleton.get(); + Server server = null; + if (serverId != null) { + server = (Server) getSession().get(ServerImpl.class, serverId); if (server != null) { return server; } } - finally - { - serverReadLock.unlock(); - } - // get the write lock - serverWriteLock.lock(); try { final String ipAddress = InetAddress.getLocalHost().getHostAddress(); @@ -185,16 +179,15 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements } } } + // push the value into the singleton + serverIdSingleton.put(server.getId()); + return server; } catch (Exception e) { throw new AlfrescoRuntimeException("Failed to create server instance", e); } - finally - { - serverWriteLock.unlock(); - } } private static final String RESOURCE_KEY_TRANSACTION_ID = "hibernate.transaction.id"; @@ -307,7 +300,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements /** * Fetch the node status, if it exists */ - public NodeStatus getNodeStatus(NodeRef nodeRef, boolean create) + public NodeStatus getNodeStatus(NodeRef nodeRef, boolean update) { NodeKey nodeKey = new NodeKey(nodeRef); NodeStatus status = null; @@ -325,13 +318,18 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements throw e; } // create if necessary - if (status == null && create) + if (status == null && update) { status = new NodeStatusImpl(); status.setKey(nodeKey); status.setTransaction(getCurrentTransaction()); getHibernateTemplate().save(status); } + else if (status != null && update) + { + // update the transaction + status.setTransaction(getCurrentTransaction()); + } // done return status; } @@ -532,10 +530,10 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements assoc.setChildNodeNameCrc(-1L); // random names compete only with each other assoc.setQname(qname); assoc.setIsPrimary(isPrimary); - // persist it, catching the duplicate child name - getHibernateTemplate().save(assoc); // maintain inverse sets assoc.buildAssociation(parentNode, childNode); + // persist it + getHibernateTemplate().save(assoc); // done return assoc; } @@ -934,18 +932,234 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements getSession().flush(); } + public List getPropertyValuesByActualType(DataTypeDefinition actualDataTypeDefinition) + { + // get the in-database string representation of the actual type + QName typeQName = actualDataTypeDefinition.getName(); + final String actualTypeString = PropertyValue.getActualTypeString(typeQName); + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session + .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_ACTUAL_TYPE) + .setString("actualTypeString", actualTypeString); + return query.scroll(ScrollMode.FORWARD_ONLY); + } + }; + ScrollableResults results = (ScrollableResults) getHibernateTemplate().execute(callback); + // Loop through, extracting content URLs + List convertedValues = new ArrayList(1000); + TypeConverter converter = DefaultTypeConverter.INSTANCE; + while(results.next()) + { + Node node = (Node) results.get()[0]; + // loop through all the node properties + Map properties = node.getProperties(); + for (PropertyValue propertyValue : properties.values()) + { + // ignore nulls + if (propertyValue == null) + { + continue; + } + // Get the actual value(s) as a collection + Collection values = propertyValue.getCollection(DataTypeDefinition.ANY); + // attempt to convert instance in the collection + for (Serializable value : values) + { + // ignore nulls (null entries in collections) + if (value == null) + { + continue; + } + try + { + Serializable convertedValue = (Serializable) converter.convert(actualDataTypeDefinition, value); + // it converted, so add it + convertedValues.add(convertedValue); + } + catch (Throwable e) + { + // The value can't be converted - forget it + } + } + } + // evict all data from the session + getSession().clear(); + } + return convertedValues; + } + + /* + * Queries for transactions + */ + private static final String QUERY_GET_LAST_TXN_ID_FOR_STORE = "txn.GetLastTxnIdForStore"; + private static final String QUERY_GET_TXN_UPDATE_COUNT_FOR_STORE = "txn.GetTxnUpdateCountForStore"; + private static final String QUERY_GET_TXN_DELETE_COUNT_FOR_STORE = "txn.GetTxnDeleteCountForStore"; + private static final String QUERY_COUNT_TRANSACTIONS = "txn.CountTransactions"; + private static final String QUERY_GET_NEXT_TXNS = "txn.GetNextTxns"; + private static final String QUERY_GET_TXN_CHANGES_FOR_STORE = "txn.GetTxnChangesForStore"; + private static final String QUERY_GET_TXN_CHANGES = "txn.GetTxnChanges"; + @SuppressWarnings("unchecked") - public List getContentDataStrings() + public Transaction getLastTxn(final StoreRef storeRef) { HibernateCallback callback = new HibernateCallback() { public Object doInHibernate(Session session) { - Query query = session.getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CONTENT_DATA_STRINGS); + Query query = session.getNamedQuery(QUERY_GET_LAST_TXN_ID_FOR_STORE); + query.setString("protocol", storeRef.getProtocol()) + .setString("identifier", storeRef.getIdentifier()) + .setMaxResults(1) + .setReadOnly(true); + return query.uniqueResult(); + } + }; + Long txnId = (Long) getHibernateTemplate().execute(callback); + Transaction txn = null; + if (txnId != null) + { + txn = (Transaction) getSession().get(TransactionImpl.class, txnId); + } + // done + return txn; + } + + @SuppressWarnings("unchecked") + public int getTxnUpdateCountForStore(final StoreRef storeRef, final long txnId) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_TXN_UPDATE_COUNT_FOR_STORE); + query.setLong("txnId", txnId) + .setString("protocol", storeRef.getProtocol()) + .setString("identifier", storeRef.getIdentifier()) + .setMaxResults(1) + .setReadOnly(true); + return query.uniqueResult(); + } + }; + Integer count = (Integer) getHibernateTemplate().execute(callback); + // done + return count; + } + + @SuppressWarnings("unchecked") + public int getTxnDeleteCountForStore(final StoreRef storeRef, final long txnId) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_TXN_DELETE_COUNT_FOR_STORE); + query.setLong("txnId", txnId) + .setString("protocol", storeRef.getProtocol()) + .setString("identifier", storeRef.getIdentifier()) + .setMaxResults(1) + .setReadOnly(true); + return query.uniqueResult(); + } + }; + Integer count = (Integer) getHibernateTemplate().execute(callback); + // done + return count; + } + + @SuppressWarnings("unchecked") + public int getTransactionCount() + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_COUNT_TRANSACTIONS); + query.setMaxResults(1) + .setReadOnly(true); + return query.uniqueResult(); + } + }; + Integer count = (Integer) getHibernateTemplate().execute(callback); + // done + return count.intValue(); + } + + @SuppressWarnings("unchecked") + public List getNextTxns(final Transaction lastTxn, final int count) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + long lastTxnId = (lastTxn == null) ? -1L : lastTxn.getId(); + + Query query = session.getNamedQuery(QUERY_GET_NEXT_TXNS); + query.setLong("lastTxnId", lastTxnId) + .setMaxResults(count) + .setReadOnly(true); return query.list(); } }; - List queryResults = (List) getHibernateTemplate().execute(callback); - return queryResults; + List results = (List) getHibernateTemplate().execute(callback); + // done + return results; + } + + @SuppressWarnings("unchecked") + public List getTxnChangesForStore(final StoreRef storeRef, final long txnId) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_TXN_CHANGES_FOR_STORE); + query.setLong("txnId", txnId) + .setString("protocol", storeRef.getProtocol()) + .setString("identifier", storeRef.getIdentifier()) + .setReadOnly(true); + return query.list(); + } + }; + List results = (List) getHibernateTemplate().execute(callback); + // transform into a simpler form + List nodeRefs = new ArrayList(results.size()); + for (NodeStatus nodeStatus : results) + { + NodeRef nodeRef = new NodeRef(storeRef, nodeStatus.getKey().getGuid()); + nodeRefs.add(nodeRef); + } + // done + return nodeRefs; + } + + @SuppressWarnings("unchecked") + public List getTxnChanges(final long txnId) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_TXN_CHANGES); + query.setLong("txnId", txnId) + .setReadOnly(true); + return query.list(); + } + }; + List results = (List) getHibernateTemplate().execute(callback); + // transform into a simpler form + List nodeRefs = new ArrayList(results.size()); + for (NodeStatus nodeStatus : results) + { + NodeRef nodeRef = new NodeRef( + nodeStatus.getKey().getProtocol(), + nodeStatus.getKey().getIdentifier(), + nodeStatus.getKey().getGuid()); + nodeRefs.add(nodeRef); + } + // done + return nodeRefs; } } diff --git a/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java b/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java new file mode 100644 index 0000000000..c715264264 --- /dev/null +++ b/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2005-2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.node.index; + +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; + +import net.sf.acegisecurity.Authentication; + +import org.alfresco.repo.node.db.NodeDaoService; +import org.alfresco.repo.search.Indexer; +import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.transaction.TransactionComponent; +import org.alfresco.repo.transaction.TransactionUtil; +import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.util.PropertyCheck; +import org.alfresco.util.VmShutdownListener; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Abstract helper for reindexing. + * + * @see #reindexImpl() + * @see #getIndexerWriteLock() + * @see #isShuttingDown() + * + * @author Derek Hulley + */ +public abstract class AbstractReindexComponent implements IndexRecovery +{ + private static Log logger = LogFactory.getLog(AbstractReindexComponent.class); + + /** kept to notify the thread that it should quit */ + private static VmShutdownListener vmShutdownListener = new VmShutdownListener("MissingContentReindexComponent"); + + private AuthenticationComponent authenticationComponent; + /** provides transactions to atomically index each missed transaction */ + protected TransactionComponent transactionService; + /** the component to index the node hierarchy */ + protected Indexer indexer; + /** the FTS indexer that we will prompt to pick up on any un-indexed text */ + protected FullTextSearchIndexer ftsIndexer; + /** the component providing searches of the indexed nodes */ + protected SearchService searcher; + /** the component giving direct access to store instances */ + protected NodeService nodeService; + /** the component giving direct access to transaction instances */ + protected NodeDaoService nodeDaoService; + + private boolean shutdown; + private final WriteLock indexerWriteLock; + + public AbstractReindexComponent() + { + shutdown = false; + ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + indexerWriteLock = readWriteLock.writeLock(); + } + + /** + * Convenience method to get a common write lock. This can be used to avoid + * concurrent access to the work methods. + */ + protected WriteLock getIndexerWriteLock() + { + return indexerWriteLock; + } + + /** + * Programmatically notify a reindex thread to terminate + * + * @param shutdown true to shutdown, false to reset + */ + public void setShutdown(boolean shutdown) + { + this.shutdown = shutdown; + } + + /** + * + * @return Returns true if the VM shutdown hook has been triggered, or the instance + * was programmatically {@link #shutdown shut down} + */ + protected boolean isShuttingDown() + { + return shutdown || vmShutdownListener.isVmShuttingDown(); + } + + /** + * @param authenticationComponent ensures that reindexing operates as system user + */ + public void setAuthenticationComponent(AuthenticationComponent authenticationComponent) + { + this.authenticationComponent = authenticationComponent; + } + + /** + * Set the low-level transaction component to use + * + * @param transactionComponent provide transactions to index each missed transaction + */ + public void setTransactionComponent(TransactionComponent transactionComponent) + { + this.transactionService = transactionComponent; + } + + /** + * @param indexer the indexer that will be index + */ + public void setIndexer(Indexer indexer) + { + this.indexer = indexer; + } + + /** + * @param ftsIndexer the FTS background indexer + */ + public void setFtsIndexer(FullTextSearchIndexer ftsIndexer) + { + this.ftsIndexer = ftsIndexer; + } + + /** + * @param searcher component providing index searches + */ + public void setSearcher(SearchService searcher) + { + this.searcher = searcher; + } + + /** + * @param nodeService provides information about nodes for indexing + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * @param nodeDaoService provides access to transaction-related queries + */ + public void setNodeDaoService(NodeDaoService nodeDaoService) + { + this.nodeDaoService = nodeDaoService; + } + + /** + * Perform the actual work. This method will be called as the system user + * and within an existing transaction. This thread will only ever be accessed + * by a single thread per instance. + * + */ + protected abstract void reindexImpl(); + + /** + * If this object is currently busy, then it just nothing + */ + public final void reindex() + { + PropertyCheck.mandatory(this, "authenticationComponent", this.authenticationComponent); + PropertyCheck.mandatory(this, "ftsIndexer", this.ftsIndexer); + PropertyCheck.mandatory(this, "indexer", this.indexer); + PropertyCheck.mandatory(this, "searcher", this.searcher); + PropertyCheck.mandatory(this, "nodeService", this.nodeService); + PropertyCheck.mandatory(this, "nodeDaoService", this.nodeDaoService); + PropertyCheck.mandatory(this, "transactionComponent", this.transactionService); + + if (indexerWriteLock.tryLock()) + { + Authentication auth = null; + try + { + auth = AuthenticationUtil.getCurrentAuthentication(); + // authenticate as the system user + authenticationComponent.setSystemUserAsCurrentUser(); + TransactionWork reindexWork = new TransactionWork() + { + public Object doWork() throws Exception + { + reindexImpl(); + return null; + } + }; + TransactionUtil.executeInUserTransaction(transactionService, reindexWork); + } + finally + { + try { indexerWriteLock.unlock(); } catch (Throwable e) {} + if (auth != null) + { + authenticationComponent.setCurrentAuthentication(auth); + } + } + // done + if (logger.isDebugEnabled()) + { + logger.debug("Reindex work completed: " + this); + } + } + else + { + if (logger.isDebugEnabled()) + { + logger.debug("Bypassed reindex work - already busy: " + this); + } + } + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/node/index/FtsIndexRecoveryComponent.java b/source/java/org/alfresco/repo/node/index/FtsIndexRecoveryComponent.java deleted file mode 100644 index cb0f787831..0000000000 --- a/source/java/org/alfresco/repo/node/index/FtsIndexRecoveryComponent.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.node.index; - -import java.util.ArrayList; -import java.util.List; - -import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer; -import org.alfresco.repo.transaction.TransactionUtil; -import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.transaction.TransactionService; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Ensures that the FTS indexing picks up on any outstanding documents that - * require indexing. - *

- * FTS indexing is a background process. It is therefore possible that - * certain documents don't get indexed when the server shuts down. - * - * @author Derek Hulley - */ -public class FtsIndexRecoveryComponent implements IndexRecovery -{ - private static Log logger = LogFactory.getLog(FtsIndexRecoveryComponent.class); - - /** provides transactions to atomically index each missed transaction */ - private TransactionService transactionService; - /** the FTS indexer that we will prompt to pick up on any un-indexed text */ - private FullTextSearchIndexer ftsIndexer; - /** the component giving direct access to node instances */ - private NodeService nodeService; - /** the workspaces to reindex */ - private List storeRefs; - - public FtsIndexRecoveryComponent() - { - this.storeRefs = new ArrayList(2); - } - - /** - * @param transactionService provide transactions to index each missed transaction - */ - public void setTransactionService(TransactionService transactionService) - { - this.transactionService = transactionService; - } - - /** - * @param ftsIndexer the FTS background indexer - */ - public void setFtsIndexer(FullTextSearchIndexer ftsIndexer) - { - this.ftsIndexer = ftsIndexer; - } - - /** - * @param nodeService provides information about nodes for indexing - */ - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - /** - * Set the workspaces that need reindexing - * - * @param storeRefStrings a list of strings representing store references - */ - public void setStores(List storeRefStrings) - { - storeRefs.clear(); - for (String storeRefStr : storeRefStrings) - { - StoreRef storeRef = new StoreRef(storeRefStr); - storeRefs.add(storeRef); - } - } - - /** - * Ensures that the FTS indexing is activated for any outstanding full text searches. - */ - public void reindex() - { - TransactionWork reindexWork = new TransactionWork() - { - public Object doWork() - { - // reindex each store - for (StoreRef storeRef : storeRefs) - { - // check if the store exists - if (!nodeService.exists(storeRef)) - { - // store does not exist - if (logger.isDebugEnabled()) - { - logger.debug("Skipping reindex of non-existent store: " + storeRef); - } - continue; - } - - // prompt FTS to reindex the store - ftsIndexer.requiresIndex(storeRef); - } - // done - return null; - } - }; - TransactionUtil.executeInUserTransaction(transactionService, reindexWork); - // done - if (logger.isDebugEnabled()) - { - logger.debug("Prompted FTS index on stores: " + storeRefs); - } - } -} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/node/index/FtsIndexRecoveryComponentTest.java b/source/java/org/alfresco/repo/node/index/FtsIndexRecoveryComponentTest.java deleted file mode 100644 index 501fe3cdff..0000000000 --- a/source/java/org/alfresco/repo/node/index/FtsIndexRecoveryComponentTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.node.index; - -import junit.framework.TestCase; - -import org.alfresco.repo.transaction.TransactionUtil; -import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.ApplicationContextHelper; -import org.springframework.context.ApplicationContext; - -/** - * Checks that the FTS index recovery component is working - * - * @author Derek Hulley - */ -public class FtsIndexRecoveryComponentTest extends TestCase -{ - private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); - - private IndexRecovery indexRecoverer; - private TransactionService txnService; - - public void setUp() throws Exception - { - indexRecoverer = (IndexRecovery) ctx.getBean("indexRecoveryComponent"); - txnService = (TransactionService) ctx.getBean("transactionComponent"); - } - - public void testReindexing() throws Exception - { - // performs a reindex - TransactionWork reindexWork = new TransactionWork() - { - public Object doWork() - { - indexRecoverer.reindex(); - return null; - } - }; - - // reindex - TransactionUtil.executeInNonPropagatingUserTransaction(txnService, reindexWork); - } -} diff --git a/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java b/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java index 54fb4c460b..e67c1648bf 100644 --- a/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java +++ b/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java @@ -16,660 +16,365 @@ */ package org.alfresco.repo.node.index; -import java.util.ArrayList; import java.util.List; -import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.i18n.I18NUtil; import org.alfresco.model.ContentModel; -import org.alfresco.repo.domain.NodeStatus; -import org.alfresco.repo.search.Indexer; -import org.alfresco.repo.search.impl.lucene.LuceneIndexerImpl; -import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer; +import org.alfresco.repo.domain.Transaction; +import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; import org.alfresco.repo.transaction.TransactionUtil; import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.NodeRef.Status; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.hibernate.CacheMode; -import org.hibernate.Query; -import org.hibernate.Session; -import org.springframework.orm.hibernate3.HibernateCallback; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; /** - * Ensures that the FTS indexing picks up on any outstanding documents that - * require indexing. - *

- * This component must be used as a singleton (one per VM) and may only be - * called to reindex once. It will start a thread that processes all available - * transactions and keeps checking to ensure that the index is up to date with - * the latest database changes. - *

- * The following points are important: - *

    - *
  • - * By default, the Hibernate L2 cache is used during processing. - * This can be disabled by either disabling the L2 cache globally - * for the server (not recommended) or by setting the - * {@link #setL2CacheMode(String) l2CacheMode} property. If the - * database is static then the L2 cache usage can be set to use - * the NORMAL mode. REFRESH should be - * used where the server will still be accessed from some clients - * despite the database changing. NORMAL can be used - * in the case of the caches being clustered, i.e. the caches will - * not be out of date w.r.t. the database. - *
  • - *
  • - * This process should only be used continuously where the index - * transactions are following the database transactions. Use the - * {@link #setRunContinuously(boolean) runContinuously} property - * to change this behaviour. - *
  • - *
+ * Component to check and recover the indexes. * * @author Derek Hulley */ -public class FullIndexRecoveryComponent extends HibernateDaoSupport implements IndexRecovery +public class FullIndexRecoveryComponent extends AbstractReindexComponent { - public static final String QUERY_GET_NEXT_CHANGE_TXN_IDS = "node.GetNextChangeTxnIds"; - public static final String QUERY_GET_CHANGED_NODE_STATUSES = "node.GetChangedNodeStatuses"; - public static final String QUERY_GET_DELETED_NODE_STATUSES = "node.GetDeletedNodeStatuses"; - public static final String QUERY_GET_CHANGED_NODE_STATUSES_COUNT = "node.GetChangedNodeStatusesCount"; - - private static final String START_TXN_ID = "000"; + private static final String ERR_STORE_NOT_UP_TO_DATE = "index.recovery.store_not_up_to_date"; + private static final String MSG_RECOVERY_STARTING = "index.recovery.starting"; + private static final String MSG_RECOVERY_COMPLETE = "index.recovery.complete"; + private static final String MSG_RECOVERY_PROGRESS = "index.recovery.progress"; + private static final String MSG_RECOVERY_TERMINATED = "index.recovery.terminated"; private static Log logger = LogFactory.getLog(FullIndexRecoveryComponent.class); - /** ensures that this process is kicked off once per VM */ - private static boolean started = false; - /** The current transaction ID being processed */ - private static String currentTxnId = START_TXN_ID; - /** kept to notify the thread that it should quit */ - private boolean killThread = false; - - /** provides transactions to atomically index each missed transaction */ - private TransactionService transactionService; - /** the component to index the node hierarchy */ - private Indexer indexer; - /** the FTS indexer that we will prompt to pick up on any un-indexed text */ - private FullTextSearchIndexer ftsIndexer; - /** the component providing searches of the indexed nodes */ - private SearchService searcher; - /** the component giving direct access to node instances */ - private NodeService nodeService; - /** set this to run the index recovery component */ - private boolean executeFullRecovery; - /** set this on to keep checking for new transactions and never stop */ - private boolean runContinuously; - /** set the time to wait between checking indexes */ - private long waitTime; - /** controls how the L2 cache is used */ - private CacheMode l2CacheMode; - - /** - * @return Returns the ID of the current (or last) transaction processed - */ - public static String getCurrentTransactionId() + public static enum RecoveryMode { - return currentTxnId; + /** Do nothing - not even a check */ + NONE, + /** Perform a quick check on the state of the indexes only */ + VALIDATE, + /** Performs a quick validation and then starts a full pass-through on failure */ + AUTO, + /** Performs a full pass-through of all recorded transactions to ensure that the indexes are up to date */ + FULL; } - + + private RecoveryMode recoveryMode; + public FullIndexRecoveryComponent() { - this.killThread = false; - this.executeFullRecovery = false; - this.runContinuously = false; - this.waitTime = 1000L; - this.l2CacheMode = CacheMode.REFRESH; - - // ensure that we kill the thread when the VM is shutting down - Runnable shutdownRunnable = new Runnable() - { - public void run() - { - killThread = true; - }; - }; - Thread shutdownThread = new Thread(shutdownRunnable); - Runtime.getRuntime().addShutdownHook(shutdownThread); + recoveryMode = RecoveryMode.VALIDATE; } /** - * @return Returns true if the component has already been started + * Set the type of recovery to perform. + * + * @param recoveryMode one of the {@link RecoveryMode } values */ - public static boolean isStarted() + public void setRecoveryMode(String recoveryMode) { - return started; - } - - /** - * @param transactionService provide transactions to index each missed transaction - */ - public void setTransactionService(TransactionService transactionService) - { - this.transactionService = transactionService; - } - - /** - * @param indexer the indexer that will be index - */ - public void setIndexer(Indexer indexer) - { - this.indexer = indexer; + this.recoveryMode = RecoveryMode.valueOf(recoveryMode); } - /** - * @param ftsIndexer the FTS background indexer - */ - public void setFtsIndexer(FullTextSearchIndexer ftsIndexer) + @Override + protected void reindexImpl() { - this.ftsIndexer = ftsIndexer; - } - - /** - * @param searcher component providing index searches - */ - public void setSearcher(SearchService searcher) - { - this.searcher = searcher; - } - - /** - * @param nodeService provides information about nodes for indexing - */ - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - /** - * Set this to true to initiate the full index recovery. - *

- * This used to default to true but is now false. Set this - * if the potentially long-running process of checking and fixing the - * indexes must be started. - * - * @param executeFullRecovery - */ - public void setExecuteFullRecovery(boolean executeFullRecovery) - { - this.executeFullRecovery = executeFullRecovery; - } - - /** - * Set this to ensure that the process continuously checks for new transactions. - * If not, it will permanently terminate once it catches up with the current - * transactions. - * - * @param runContinuously true to never cease looking for new transactions - */ - public void setRunContinuously(boolean runContinuously) - { - this.runContinuously = runContinuously; - } - - /** - * Set the time to wait between checking for new transaction changes in the database. - * - * @param waitTime the time to wait in milliseconds - */ - public void setWaitTime(long waitTime) - { - this.waitTime = waitTime; - } - - /** - * Set the hibernate cache mode by name - * - * @see org.hibernate.CacheMode - */ - public void setL2CacheMode(String l2CacheModeStr) - { - if (l2CacheModeStr.equals("GET")) + if (logger.isDebugEnabled()) { - l2CacheMode = CacheMode.GET; - } - else if (l2CacheModeStr.equals("IGNORE")) - { - l2CacheMode = CacheMode.IGNORE; - } - else if (l2CacheModeStr.equals("NORMAL")) - { - l2CacheMode = CacheMode.NORMAL; - } - else if (l2CacheModeStr.equals("PUT")) - { - l2CacheMode = CacheMode.PUT; - } - else if (l2CacheModeStr.equals("REFRESH")) - { - l2CacheMode = CacheMode.REFRESH; - } - else - { - throw new IllegalArgumentException("Unrecognised Hibernate L2 cache mode: " + l2CacheModeStr); - } - } - - /** - * Ensure that the index is up to date with the current state of the persistence layer. - * The full list of unique transaction change IDs is retrieved and used to detect - * which are not present in the index. All the node changes and deletions for the - * remaining transactions are then indexed. - */ - public synchronized void reindex() - { - if (FullIndexRecoveryComponent.started) - { - throw new AlfrescoRuntimeException - ("Only one FullIndexRecoveryComponent may be used per VM and it may only be called once"); + logger.debug("Performing index recovery for type: " + recoveryMode); } - // ensure that we don't redo this work - FullIndexRecoveryComponent.started = true; - - // work to mark the stores for full text reindexing - TransactionWork ftsReindexWork = new TransactionWork() + // do we just ignore + if (recoveryMode == RecoveryMode.NONE) { - public Object doWork() - { - List storeRefs = nodeService.getStores(); - // reindex each store - for (StoreRef storeRef : storeRefs) - { - // check if the store exists - if (!nodeService.exists(storeRef)) - { - // store does not exist - if (logger.isDebugEnabled()) - { - logger.debug("Skipping reindex of non-existent store: " + storeRef); - } - continue; - } - - // prompt FTS to reindex the store - ftsIndexer.requiresIndex(storeRef); - } - // done - if (logger.isDebugEnabled()) - { - logger.debug("Prompted FTS index on stores: " + storeRefs); - } - return null; - } - }; - TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, ftsReindexWork); - - // start full index recovery, if necessary - if (!this.executeFullRecovery) + return; + } + // check the level of cover required + boolean fullRecoveryRequired = false; + if (recoveryMode == RecoveryMode.FULL) // no validate required { - if (logger.isDebugEnabled()) + fullRecoveryRequired = true; + } + else // validate first + { + List storeRefs = nodeService.getStores(); + for (StoreRef storeRef : storeRefs) { - logger.debug("Full index recovery is off - quitting"); + // get the last txn ID in the database + Transaction txn = nodeDaoService.getLastTxn(storeRef); + boolean lastChangeTxnIdInIndex = isTxnIdPresentInIndex(storeRef, txn); + if (lastChangeTxnIdInIndex) + { + // this store is good + continue; + } + // this store isn't up to date + String msg = I18NUtil.getMessage(ERR_STORE_NOT_UP_TO_DATE, storeRef); + logger.warn(msg); + // the store is out of date - validation failed + if (recoveryMode == RecoveryMode.VALIDATE) + { + // next store + continue; + } + else if (recoveryMode == RecoveryMode.AUTO) + { + fullRecoveryRequired = true; + } } } - else + + // put the server into read-only mode for the duration + boolean allowWrite = !transactionService.isReadOnly(); + try { - // set the state of the reindex - FullIndexRecoveryComponent.currentTxnId = START_TXN_ID; + // set the server into read-only mode + transactionService.setAllowWrite(false); - // start a stateful thread that will begin processing the reindexing the transactions - Runnable runnable = new ReindexRunner(); - Thread reindexThread = new Thread(runnable); - // make it a daemon thread - reindexThread.setDaemon(true); - // it should not be a high priority - reindexThread.setPriority(Thread.MIN_PRIORITY); - // start it - reindexThread.start(); - - if (logger.isDebugEnabled()) + // do we need to perform a full recovery + if (fullRecoveryRequired) { - logger.debug("Full index recovery thread started: \n" + - " continuous: " + runContinuously); + performFullRecovery(); } } + finally + { + // restore read-only state + transactionService.setAllowWrite(allowWrite); + } + } - /** - * Stateful thread runnable that executes reindex calls. - * - * @see FullIndexRecoveryComponent#reindexNodes() - * - * @author Derek Hulley - */ - private class ReindexRunner implements Runnable + private static final int MAX_TRANSACTIONS_PER_ITERATION = 1000; + private void performFullRecovery() { - public void run() + int txnCount = nodeDaoService.getTransactionCount(); + // starting + String msgStart = I18NUtil.getMessage(MSG_RECOVERY_STARTING, txnCount); + logger.info(msgStart); + + // count the transactions + int processedCount = 0; + Transaction lastTxn = null; + while(true) { - // keep this thread going permanently - while (!killThread) + List nextTxns = nodeDaoService.getNextTxns( + lastTxn, + MAX_TRANSACTIONS_PER_ITERATION); + + // reindex each transaction + for (Transaction txn : nextTxns) { - try + Long txnId = txn.getId(); + // check if we have to terminate + if (isShuttingDown()) { - // reindex nodes - List txnsIndexed = FullIndexRecoveryComponent.this.reindexNodes(); - // reindex missing content -// @SuppressWarnings("unused") -// int missingContentCount = FullIndexRecoveryComponent.this.reindexMissingContent(); - // check if the process should terminate - if (txnsIndexed.size() == 0 && !runContinuously) - { - // the thread has caught up with all the available work and should not - // run continuously - if (logger.isDebugEnabled()) - { - logger.debug("Thread quitting - no more available indexing to do: \n" + - " last txn: " + FullIndexRecoveryComponent.getCurrentTransactionId()); - } - break; - } - // brief pause - synchronized(FullIndexRecoveryComponent.this) - { - FullIndexRecoveryComponent.this.wait(waitTime); - } + String msgTerminated = I18NUtil.getMessage(MSG_RECOVERY_TERMINATED); + logger.warn(msgTerminated); + return; } - catch (InterruptedException e) + + reindexTransaction(txnId); + + // dump a progress report every 10% of the way + double before = (double) processedCount / (double) txnCount * 10.0; // 0 - 10 + processedCount++; + double after = (double) processedCount / (double) txnCount * 10.0; // 0 - 10 + if (Math.floor(before) < Math.floor(after)) // crossed a 0 - 10 integer boundary { - // ignore - } - catch (Throwable e) - { - if (killThread) - { - // the shutdown may have caused the exception - ignore it - } - else - { - // we are still a go; report it - logger.error("Reindex failure", e); - } + int complete = ((int)Math.floor(after))*10; + String msgProgress = I18NUtil.getMessage(MSG_RECOVERY_PROGRESS, complete); + logger.info(msgProgress); } } + + // have we finished? + if (nextTxns.size() == 0) + { + // there are no more + break; + } + lastTxn = nextTxns.get(nextTxns.size() - 1); } - } - - /** - * @return Returns the transaction ID just reindexed, i.e. where some work was performed - */ - private List reindexNodes() - { - // get a list of all transactions still requiring a check - List txnsToCheck = getNextChangeTxnIds(FullIndexRecoveryComponent.currentTxnId); - - // loop over each transaction - for (String changeTxnId : txnsToCheck) - { - reindexNodes(changeTxnId); - } - // done - return txnsToCheck; + String msgDone = I18NUtil.getMessage(MSG_RECOVERY_COMPLETE); + logger.info(msgDone); } /** - * Reindexes changes specific to the change transaction ID. - *

- * All exceptions are absorbed. + * Perform a full reindexing of the given transaction in the context of a completely + * new transaction. + * + * @param txnId the transaction identifier */ - private void reindexNodes(final String changeTxnId) + public void reindexTransaction(final long txnId) { - /* - * This must execute each within its own transaction. - * The cache size is therefore not an issue. - */ + if (logger.isDebugEnabled()) + { + logger.debug("Reindexing transaction: " + txnId); + } + TransactionWork reindexWork = new TransactionWork() { public Object doWork() throws Exception { - // perform the work in a Hibernate callback - HibernateCallback callback = new ReindexCallback(changeTxnId); - getHibernateTemplate().execute(callback); + // get the node references pertinent to the transaction + List nodeRefs = nodeDaoService.getTxnChanges(txnId); + // reindex each node + for (NodeRef nodeRef : nodeRefs) + { + Status nodeStatus = nodeService.getNodeStatus(nodeRef); + if (nodeStatus == null) + { + // it's not there any more + continue; + } + if (nodeStatus.isDeleted()) // node deleted + { + // only the child node ref is relevant + ChildAssociationRef assocRef = new ChildAssociationRef( + ContentModel.ASSOC_CHILDREN, + null, + null, + nodeRef); + indexer.deleteNode(assocRef); + } + else // node created + { + // get the primary assoc for the node + ChildAssociationRef primaryAssocRef = nodeService.getPrimaryParent(nodeRef); + // reindex + indexer.createNode(primaryAssocRef); + } + } // done return null; } }; - try - { - TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, reindexWork); - } - catch (Throwable e) - { - logger.error("Transaction reindex failed: \n" + - " txn: " + changeTxnId, - e); - } - finally - { - // Up the current transaction now, in case the process fails at this point. - // This will prevent the transaction from being processed again. - // This applies to failures as well, which should be dealt with externally - // and having the entire process start again, e.g. such as a system reboot - currentTxnId = changeTxnId; - } + TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, reindexWork, true); + // done } - /** - * Stateful inner class that implements a single reindex call for a given store - * and transaction. - *

- * It must be called within its own transaction. - * - * @author Derek Hulley - */ - private class ReindexCallback implements HibernateCallback + private boolean isTxnIdPresentInIndex(StoreRef storeRef, Transaction txn) { - private final String changeTxnId; - - public ReindexCallback(String changeTxnId) + if (logger.isDebugEnabled()) { - this.changeTxnId = changeTxnId; + logger.debug("Checking for transaction in index: \n" + + " store: " + storeRef + "\n" + + " txn: " + txn); } - /** - * Changes the L2 cache usage before reindexing for each store - * - * @see #reindexNodes(StoreRef, String) - */ - public Object doInHibernate(Session session) + String changeTxnId = txn.getChangeTxnId(); + // count the changes in the transaction + int updateCount = nodeDaoService.getTxnUpdateCountForStore(storeRef, txn.getId()); + int deleteCount = nodeDaoService.getTxnDeleteCountForStore(storeRef, txn.getId()); + if (logger.isDebugEnabled()) { - // set the way the L2 cache is used - getSession().setCacheMode(l2CacheMode); - - // reindex each store -// for (StoreRef storeRef : storeRefs) -// { -// if (!nodeService.exists(storeRef)) -// { -// // the store is not present -// continue; -// } -// // reindex for store -// reindexNodes(storeRef, changeTxnId); -// } - // done - return null; + logger.debug("Transaction has " + updateCount + " updates and " + deleteCount + " deletes: " + txn); } - private void reindexNodes(StoreRef storeRef, String changeTxnId) + // do the most update check, which is most common + if (deleteCount == 0 && updateCount == 0) + { + if (logger.isDebugEnabled()) + { + logger.debug("No changes in transaction: " + txn); + } + // there's nothing to check for + return true; + } + else if (updateCount > 0) { - // check if we need to perform this operation - SearchParameters sp = new SearchParameters(); - sp.addStore(storeRef); - - // search for it in the index - String query = "TX:\"" + changeTxnId + "\""; - sp.setLanguage(SearchService.LANGUAGE_LUCENE); - sp.setQuery(query); ResultSet results = null; try { + SearchParameters sp = new SearchParameters(); + sp.addStore(storeRef); + // search for it in the index, sorting with youngest first, fetching only 1 + sp.setLanguage(SearchService.LANGUAGE_LUCENE); + sp.setQuery("TX:" + LuceneQueryParser.escape(changeTxnId)); + sp.setLimit(1); + results = searcher.query(sp); - // did the index have any of these changes? + if (results.length() > 0) { - // the transaction has an entry in the index - assume that it was - // atomically correct if (logger.isDebugEnabled()) { - logger.debug("Transaction present in index - no indexing required: \n" + - " store: " + storeRef + "\n" + - " txn: " + changeTxnId); + logger.debug("Index has results for txn (OK): " + txn); } - return; + return true; // there were updates/creates and results for the txn were found + } + else + { + if (logger.isDebugEnabled()) + { + logger.debug("Index has no results for txn (Index out of date): " + txn); + } + return false; } } finally { - if (results != null) - { - results.close(); - } - } - // the index has no record of this - // were there any changes, or is it all just deletions? - int changedCount = getChangedNodeStatusesCount(storeRef, changeTxnId); - if (changedCount == 0) - { - // no nodes were changed in the transaction, i.e. they are only deletions - // the index is quite right not to have any entries for the transaction - if (logger.isDebugEnabled()) - { - logger.debug("Transaction only has deletions - no indexing required: \n" + - " store: " + storeRef + "\n" + - " txn: " + changeTxnId); - } - return; - } - - // process the deletions relevant to the txn and the store - List deletedNodeStatuses = getDeletedNodeStatuses(storeRef, changeTxnId); - for (NodeStatus status : deletedNodeStatuses) - { - NodeRef nodeRef = new NodeRef(storeRef, status.getKey().getGuid()); - // only the child node ref is relevant - ChildAssociationRef assocRef = new ChildAssociationRef( - ContentModel.ASSOC_CHILDREN, - null, - null, - nodeRef); - indexer.deleteNode(assocRef); - } - - // process additions - List changedNodeStatuses = getChangedNodeStatuses(storeRef, changeTxnId); - for (NodeStatus status : changedNodeStatuses) - { - NodeRef nodeRef = new NodeRef(storeRef, status.getKey().getGuid()); - // get the primary assoc for the node - ChildAssociationRef primaryAssocRef = nodeService.getPrimaryParent(nodeRef); - // reindex - indexer.createNode(primaryAssocRef); - } - - // done - if (logger.isDebugEnabled()) - { - logger.debug("Transaction reindexed: \n" + - " store: " + storeRef + "\n" + - " txn: " + changeTxnId + "\n" + - " deletions: " + deletedNodeStatuses.size() + "\n" + - " modifications: " + changedNodeStatuses.size()); + if (results != null) { results.close(); } } } - }; - - /** - * Retrieve next 50 transaction IDs that are greater than the given transaction ID. - * - * @param currentTxnId the transaction ID that must be less than all returned results - * @return Returns an ordered list of the next 50 transaction IDs - */ - @SuppressWarnings("unchecked") - public List getNextChangeTxnIds(final String currentTxnId) - { - HibernateCallback callback = new HibernateCallback() + // there have been deletes, so we have to ensure that none of the nodes deleted are present in the index + // get all node refs for the transaction + Long txnId = txn.getId(); + List nodeRefs = nodeDaoService.getTxnChangesForStore(storeRef, txnId); + for (NodeRef nodeRef : nodeRefs) { - public Object doInHibernate(Session session) + if (logger.isDebugEnabled()) { - Query query = session.getNamedQuery(QUERY_GET_NEXT_CHANGE_TXN_IDS); - query.setString("currentTxnId", currentTxnId) - .setMaxResults(50) - .setReadOnly(true); - return query.list(); + logger.debug("Searching for node in index: \n" + + " node: " + nodeRef + "\n" + + " txn: " + txn); } - }; - List queryResults = (List) getHibernateTemplate().execute(callback); - // done - return queryResults; - } - - @SuppressWarnings("unchecked") - public int getChangedNodeStatusesCount(final StoreRef storeRef, final String changeTxnId) - { - HibernateCallback callback = new HibernateCallback() + // we know that these are all deletions + ResultSet results = null; + try + { + SearchParameters sp = new SearchParameters(); + sp.addStore(storeRef); + // search for it in the index, sorting with youngest first, fetching only 1 + sp.setLanguage(SearchService.LANGUAGE_LUCENE); + sp.setQuery("ID:" + LuceneQueryParser.escape(nodeRef.toString())); + sp.setLimit(1); + + results = searcher.query(sp); + + if (results.length() == 0) + { + // no results, as expected + if (logger.isDebugEnabled()) + { + logger.debug(" --> Node not found (OK)"); + } + continue; + } + else + { + if (logger.isDebugEnabled()) + { + logger.debug(" --> Node found (Index out of date)"); + } + return false; + } + } + finally + { + if (results != null) { results.close(); } + } + } + + // all tests passed + if (logger.isDebugEnabled()) { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_CHANGED_NODE_STATUSES_COUNT); - query.setString("storeProtocol", storeRef.getProtocol()) - .setString("storeIdentifier", storeRef.getIdentifier()) - .setString("changeTxnId", changeTxnId) - .setReadOnly(true); - return query.uniqueResult(); - } - }; - Integer changeCount = (Integer) getHibernateTemplate().execute(callback); - // done - return changeCount.intValue(); - } - - @SuppressWarnings("unchecked") - public List getChangedNodeStatuses(final StoreRef storeRef, final String changeTxnId) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_CHANGED_NODE_STATUSES); - query.setString("storeProtocol", storeRef.getProtocol()) - .setString("storeIdentifier", storeRef.getIdentifier()) - .setString("changeTxnId", changeTxnId) - .setReadOnly(true); - return query.list(); - } - }; - List queryResults = (List) getHibernateTemplate().execute(callback); - // done - return queryResults; - } - - @SuppressWarnings("unchecked") - public List getDeletedNodeStatuses(final StoreRef storeRef, final String changeTxnId) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_DELETED_NODE_STATUSES); - query.setString("storeProtocol", storeRef.getProtocol()) - .setString("storeIdentifier", storeRef.getIdentifier()) - .setString("changeTxnId", changeTxnId) - .setReadOnly(true); - return query.list(); - } - }; - List queryResults = (List) getHibernateTemplate().execute(callback); - // done - return queryResults; + logger.debug("Index is in synch with transaction: " + txn); + } + return true; } } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponentTest.java b/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponentTest.java index bfd8e4a0ab..b04525e5be 100644 --- a/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponentTest.java +++ b/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponentTest.java @@ -16,24 +16,8 @@ */ package org.alfresco.repo.node.index; -import java.util.ArrayList; -import java.util.List; - import junit.framework.TestCase; -import org.alfresco.model.ContentModel; -import org.alfresco.repo.search.Indexer; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport; -import org.alfresco.repo.transaction.TransactionUtil; -import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.InvalidStoreRefException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ApplicationContextHelper; import org.springframework.context.ApplicationContext; @@ -46,114 +30,35 @@ public class FullIndexRecoveryComponentTest extends TestCase { private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); - private TransactionService transactionService; private FullIndexRecoveryComponent indexRecoverer; - private NodeService nodeService; - private TransactionService txnService; - private Indexer indexer; - - private List storeRefs; - public void setUp() throws Exception { - transactionService = (TransactionService) ctx.getBean("transactionComponent"); indexRecoverer = (FullIndexRecoveryComponent) ctx.getBean("indexRecoveryComponent"); - txnService = (TransactionService) ctx.getBean("transactionComponent"); - nodeService = (NodeService) ctx.getBean("nodeService"); - indexer = (Indexer) ctx.getBean("indexerComponent"); - - // create 2 stores - TransactionWork> createStoresWork = new TransactionWork>() - { - public List doWork() throws Exception - { - List storeRefs = new ArrayList(2); - storeRefs.add(nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, getName() + System.nanoTime())); - storeRefs.add(nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, getName() + System.nanoTime())); - return storeRefs; - } - }; - storeRefs = TransactionUtil.executeInUserTransaction(transactionService, createStoresWork); } - public void testNothing() throws Exception + public void testSetup() throws Exception { } - public void xtestReindexing() throws Exception + public synchronized void testReindexing() throws Exception { - // don't do anything if the component has already started - if (FullIndexRecoveryComponent.isStarted()) - { - return; - } - // deletes a content node from the index - final List storeRefStrings = new ArrayList(2); - TransactionWork dropNodeIndexWork = new TransactionWork() - { - public String doWork() - { - // create a node in each store and drop it from the index - for (StoreRef storeRef : storeRefs) - { - try - { - NodeRef rootNodeRef = nodeService.getRootNode(storeRef); - ChildAssociationRef assocRef = nodeService.createNode( - rootNodeRef, - ContentModel.ASSOC_CONTAINS, - QName.createQName(NamespaceService.ALFRESCO_URI, "unindexedChild" + System.currentTimeMillis()), - ContentModel.TYPE_BASE); - // this will have indexed it, so remove it from the index - indexer.deleteNode(assocRef); - // make the string version of the storeRef - storeRefStrings.add(storeRef.toString()); - } - catch (InvalidStoreRefException e) - { - // just ignore stores that are invalid - } - } - return AlfrescoTransactionSupport.getTransactionId(); - } - }; - - // create un-indexed nodes - String txnId = TransactionUtil.executeInNonPropagatingUserTransaction(txnService, dropNodeIndexWork); - - indexRecoverer.setExecuteFullRecovery(true); -// indexRecoverer.setStores(storeRefStrings); + indexRecoverer.setRecoveryMode(FullIndexRecoveryComponent.RecoveryMode.FULL.name()); // reindex - indexRecoverer.reindex(); - - // check that reindexing fails - try + Thread reindexThread = new Thread() { - indexRecoverer.reindex(); - fail("Reindexer failed to prevent reindex from being called twice"); - } - catch (RuntimeException e) - { - // expected - } + public void run() + { + indexRecoverer.reindex(); + } + }; + reindexThread.setDaemon(true); + reindexThread.start(); +// reindexThread.run(); - // loop for some time, giving it a chance to do its thing - String lastProcessedTxnId = null; - for (int i = 0; i < 60; i++) - { - lastProcessedTxnId = FullIndexRecoveryComponent.getCurrentTransactionId(); - if (lastProcessedTxnId.equals(txnId)) - { - break; - } - // wait for a second - synchronized(this) - { - this.wait(1000L); - } - } - // check that the index was recovered - assertEquals("Index transaction not up to date", txnId, lastProcessedTxnId); + // wait a bit and then terminate + wait(10000); + indexRecoverer.setShutdown(true); + wait(10000); } } diff --git a/source/java/org/alfresco/repo/node/index/MissingContentReindexComponent.java b/source/java/org/alfresco/repo/node/index/MissingContentReindexComponent.java index 2f1b115e62..3080244605 100644 --- a/source/java/org/alfresco/repo/node/index/MissingContentReindexComponent.java +++ b/source/java/org/alfresco/repo/node/index/MissingContentReindexComponent.java @@ -1,741 +1,141 @@ -///* -// * Copyright (C) 2005-2006 Alfresco, Inc. -// * -// * Licensed under the Mozilla Public License version 1.1 -// * with a permitted attribution clause. You may obtain a -// * copy of the License at -// * -// * http://www.alfresco.org/legal/license.txt -// * -// * Unless required by applicable law or agreed to in writing, -// * software distributed under the License is distributed on an -// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -// * either express or implied. See the License for the specific -// * language governing permissions and limitations under the -// * License. -// */ -//package org.alfresco.repo.node.index; -// -//import java.util.ArrayList; -//import java.util.List; -// -//import org.alfresco.error.AlfrescoRuntimeException; -//import org.alfresco.model.ContentModel; -//import org.alfresco.repo.domain.NodeStatus; -//import org.alfresco.repo.search.Indexer; -//import org.alfresco.repo.search.impl.lucene.LuceneIndexerImpl; -//import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer; -//import org.alfresco.repo.transaction.TransactionUtil; -//import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; -//import org.alfresco.service.cmr.repository.ChildAssociationRef; -//import org.alfresco.service.cmr.repository.NodeRef; -//import org.alfresco.service.cmr.repository.NodeService; -//import org.alfresco.service.cmr.repository.StoreRef; -//import org.alfresco.service.cmr.search.ResultSet; -//import org.alfresco.service.cmr.search.SearchParameters; -//import org.alfresco.service.cmr.search.SearchService; -//import org.alfresco.service.transaction.TransactionService; -//import org.apache.commons.logging.Log; -//import org.apache.commons.logging.LogFactory; -//import org.hibernate.CacheMode; -//import org.hibernate.Query; -//import org.hibernate.Session; -//import org.springframework.orm.hibernate3.HibernateCallback; -//import org.springframework.orm.hibernate3.support.HibernateDaoSupport; -// -///** -// * Ensures that the FTS indexing picks up on any outstanding documents that -// * require indexing. -// *

-// * This component must be used as a singleton (one per VM) and may only be -// * called to reindex once. It will start a thread that processes all available -// * transactions and keeps checking to ensure that the index is up to date with -// * the latest database changes. -// *

-// * The following points are important: -// *

    -// *
  • -// * By default, the Hibernate L2 cache is used during processing. -// * This can be disabled by either disabling the L2 cache globally -// * for the server (not recommended) or by setting the -// * {@link #setL2CacheMode(String) l2CacheMode} property. If the -// * database is static then the L2 cache usage can be set to use -// * the NORMAL mode. REFRESH should be -// * used where the server will still be accessed from some clients -// * despite the database changing. NORMAL can be used -// * in the case of the caches being clustered, i.e. the caches will -// * not be out of date w.r.t. the database. -// *
  • -// *
  • -// * This process should only be used continuously where the index -// * transactions are following the database transactions. Use the -// * {@link #setRunContinuously(boolean) runContinuously} property -// * to change this behaviour. -// *
  • -// *
-// * -// * @author Derek Hulley -// */ -//public class MissingContentReindexComponent extends HibernateDaoSupport implements IndexRecovery -//{ -// public static final String QUERY_GET_NEXT_CHANGE_TXN_IDS = "node.GetNextChangeTxnIds"; -// public static final String QUERY_GET_CHANGED_NODE_STATUSES = "node.GetChangedNodeStatuses"; -// public static final String QUERY_GET_DELETED_NODE_STATUSES = "node.GetDeletedNodeStatuses"; -// public static final String QUERY_GET_CHANGED_NODE_STATUSES_COUNT = "node.GetChangedNodeStatusesCount"; -// -// private static final String START_TXN_ID = "000"; -// -// private static Log logger = LogFactory.getLog(FullIndexRecoveryComponent.class); -// -// /** ensures that this process is kicked off once per VM */ -// private static boolean started = false; -// /** The current transaction ID being processed */ -// private static String currentTxnId = START_TXN_ID; -// /** kept to notify the thread that it should quite */ -// private boolean killThread = false; -// -// /** provides transactions to atomically index each missed transaction */ -// private TransactionService transactionService; -// /** the component to index the node hierarchy */ -// private Indexer indexer; -// /** the FTS indexer that we will prompt to pick up on any un-indexed text */ -// private FullTextSearchIndexer ftsIndexer; -// /** the component providing searches of the indexed nodes */ -// private SearchService searcher; -// /** the component giving direct access to node instances */ -// private NodeService nodeService; -// /** set this to run the index recovery component */ -// private boolean executeFullRecovery; -// /** set this on to keep checking for new transactions and never stop */ -// private boolean runContinuously; -// /** set the time to wait between checking indexes */ -// private long waitTime; -// /** controls how the L2 cache is used */ -// private CacheMode l2CacheMode; -// -// /** -// * @return Returns the ID of the current (or last) transaction processed -// */ -// public static String getCurrentTransactionId() -// { -// return currentTxnId; -// } -// -// public FullIndexRecoveryComponent() -// { -// this.killThread = false; -// this.executeFullRecovery = false; -// this.runContinuously = false; -// this.waitTime = 1000L; -// this.l2CacheMode = CacheMode.REFRESH; -// -// // ensure that we kill the thread when the VM is shutting down -// Runnable shutdownRunnable = new Runnable() -// { -// public void run() -// { -// killThread = true; -// }; -// }; -// Thread shutdownThread = new Thread(shutdownRunnable); -// Runtime.getRuntime().addShutdownHook(shutdownThread); -// } -// -// /** -// * @return Returns true if the component has already been started -// */ -// public static boolean isStarted() -// { -// return started; -// } -// -// /** -// * @param transactionService provide transactions to index each missed transaction -// */ -// public void setTransactionService(TransactionService transactionService) -// { -// this.transactionService = transactionService; -// } -// -// /** -// * @param indexer the indexer that will be index -// */ -// public void setIndexer(Indexer indexer) -// { -// this.indexer = indexer; -// } -// -// /** -// * @param ftsIndexer the FTS background indexer -// */ -// public void setFtsIndexer(FullTextSearchIndexer ftsIndexer) -// { -// this.ftsIndexer = ftsIndexer; -// } -// -// /** -// * @param searcher component providing index searches -// */ -// public void setSearcher(SearchService searcher) -// { -// this.searcher = searcher; -// } -// -// /** -// * @param nodeService provides information about nodes for indexing -// */ -// public void setNodeService(NodeService nodeService) -// { -// this.nodeService = nodeService; -// } -// -// /** -// * Set this to true to initiate the full index recovery. -// *

-// * This used to default to true but is now false. Set this -// * if the potentially long-running process of checking and fixing the -// * indexes must be started. -// * -// * @param executeFullRecovery -// */ -// public void setExecuteFullRecovery(boolean executeFullRecovery) -// { -// this.executeFullRecovery = executeFullRecovery; -// } -// -// /** -// * Set this to ensure that the process continuously checks for new transactions. -// * If not, it will permanently terminate once it catches up with the current -// * transactions. -// * -// * @param runContinuously true to never cease looking for new transactions -// */ -// public void setRunContinuously(boolean runContinuously) -// { -// this.runContinuously = runContinuously; -// } -// -// /** -// * Set the time to wait between checking for new transaction changes in the database. -// * -// * @param waitTime the time to wait in milliseconds -// */ -// public void setWaitTime(long waitTime) -// { -// this.waitTime = waitTime; -// } -// -// /** -// * Set the hibernate cache mode by name -// * -// * @see org.hibernate.CacheMode -// */ -// public void setL2CacheMode(String l2CacheModeStr) -// { -// if (l2CacheModeStr.equals("GET")) -// { -// l2CacheMode = CacheMode.GET; -// } -// else if (l2CacheModeStr.equals("IGNORE")) -// { -// l2CacheMode = CacheMode.IGNORE; -// } -// else if (l2CacheModeStr.equals("NORMAL")) -// { -// l2CacheMode = CacheMode.NORMAL; -// } -// else if (l2CacheModeStr.equals("PUT")) -// { -// l2CacheMode = CacheMode.PUT; -// } -// else if (l2CacheModeStr.equals("REFRESH")) -// { -// l2CacheMode = CacheMode.REFRESH; -// } -// else -// { -// throw new IllegalArgumentException("Unrecognised Hibernate L2 cache mode: " + l2CacheModeStr); -// } -// } -// -// /** -// * Ensure that the index is up to date with the current state of the persistence layer. -// * The full list of unique transaction change IDs is retrieved and used to detect -// * which are not present in the index. All the node changes and deletions for the -// * remaining transactions are then indexed. -// */ -// public synchronized void reindex() -// { -// if (FullIndexRecoveryComponent.started) -// { -// throw new AlfrescoRuntimeException -// ("Only one FullIndexRecoveryComponent may be used per VM and it may only be called once"); -// } -// -// // ensure that we don't redo this work -// FullIndexRecoveryComponent.started = true; -// -// // work to mark the stores for full text reindexing -// TransactionWork ftsReindexWork = new TransactionWork() -// { -// public Object doWork() -// { -// List storeRefs = nodeService.getStores(); -// // reindex each store -// for (StoreRef storeRef : storeRefs) -// { -// // check if the store exists -// if (!nodeService.exists(storeRef)) -// { -// // store does not exist -// if (logger.isDebugEnabled()) -// { -// logger.debug("Skipping reindex of non-existent store: " + storeRef); -// } -// continue; -// } -// -// // prompt FTS to reindex the store -// ftsIndexer.requiresIndex(storeRef); -// } -// // done -// if (logger.isDebugEnabled()) -// { -// logger.debug("Prompted FTS index on stores: " + storeRefs); -// } -// return null; -// } -// }; -// TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, ftsReindexWork); -// -// // start full index recovery, if necessary -// if (!this.executeFullRecovery) -// { -// if (logger.isDebugEnabled()) -// { -// logger.debug("Full index recovery is off - quitting"); -// } -// } -// else -// { -// // set the state of the reindex -// FullIndexRecoveryComponent.currentTxnId = START_TXN_ID; -// -// // start a stateful thread that will begin processing the reindexing the transactions -// Runnable runnable = new ReindexRunner(); -// Thread reindexThread = new Thread(runnable); -// // make it a daemon thread -// reindexThread.setDaemon(true); -// // it should not be a high priority -// reindexThread.setPriority(Thread.MIN_PRIORITY); -// // start it -// reindexThread.start(); -// -// if (logger.isDebugEnabled()) -// { -// logger.debug("Full index recovery thread started: \n" + -// " continuous: " + runContinuously); -// } -// } -// } -// -// /** -// * Stateful thread runnable that executes reindex calls. -// * -// * @see FullIndexRecoveryComponent#reindexNodes() -// * -// * @author Derek Hulley -// */ -// private class ReindexRunner implements Runnable -// { -// public void run() -// { -// // keep this thread going permanently -// while (!killThread) -// { -// try -// { -// // reindex nodes -// List txnsIndexed = FullIndexRecoveryComponent.this.reindexNodes(); -// // reindex missing content -// @SuppressWarnings("unused") -// int missingContentCount = FullIndexRecoveryComponent.this.reindexMissingContent(); -// // check if the process should terminate -// if (txnsIndexed.size() == 0 && !runContinuously) -// { -// // the thread has caught up with all the available work and should not -// // run continuously -// if (logger.isDebugEnabled()) -// { -// logger.debug("Thread quitting - no more available indexing to do: \n" + -// " last txn: " + FullIndexRecoveryComponent.getCurrentTransactionId()); -// } -// break; -// } -// // brief pause -// synchronized(FullIndexRecoveryComponent.this) -// { -// FullIndexRecoveryComponent.this.wait(waitTime); -// } -// } -// catch (InterruptedException e) -// { -// // ignore -// } -// catch (Throwable e) -// { -// if (killThread) -// { -// // the shutdown may have caused the exception - ignore it -// } -// else -// { -// // we are still a go; report it -// logger.error("Reindex failure", e); -// } -// } -// } -// } -// } -// -// /** -// * @return Returns the number of documents reindexed -// */ -// private int reindexMissingContent() -// { -// int count = 0; -// for (StoreRef storeRef : storeRefs) -// { -// count += reindexMissingContent(storeRef); -// } -// return count; -// } -// -// /** -// * @param storeRef the store to check for missing content -// * @return Returns the number of documents reindexed -// */ -// private int reindexMissingContent(StoreRef storeRef) -// { -// SearchParameters sp = new SearchParameters(); -// sp.addStore(storeRef); -// -// // search for it in the index -// String query = "TEXT:" + LuceneIndexerImpl.NOT_INDEXED_CONTENT_MISSING; -// sp.setLanguage(SearchService.LANGUAGE_LUCENE); -// sp.setQuery(query); -// ResultSet results = null; -// try -// { -// results = searcher.query(sp); -// -// int count = 0; -// // loop over the results and get the details of the nodes that have missing content -// List assocRefs = results.getChildAssocRefs(); -// for (ChildAssociationRef assocRef : assocRefs) -// { -// final NodeRef childNodeRef = assocRef.getChildRef(); -// // prompt for a reindex - it might fail again, but we just keep plugging away -// TransactionWork reindexWork = new TransactionWork() -// { -// public Object doWork() -// { -// indexer.updateNode(childNodeRef); -// return null; -// } -// }; -// TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, reindexWork); -// count++; -// } -// // done -// if (logger.isDebugEnabled()) -// { -// logger.debug("Reindexed missing content: \n" + -// " store: " + storeRef + "\n" + -// " node count: " + count); -// } -// return count; -// } -// finally -// { -// if (results != null) -// { -// results.close(); -// } -// } -// } -// -// /** -// * @return Returns the transaction ID just reindexed, i.e. where some work was performed -// */ -// private List reindexNodes() -// { -// // get a list of all transactions still requiring a check -// List txnsToCheck = getNextChangeTxnIds(FullIndexRecoveryComponent.currentTxnId); -// -// // loop over each transaction -// for (String changeTxnId : txnsToCheck) -// { -// reindexNodes(changeTxnId); -// } -// -// // done -// return txnsToCheck; -// } -// -// /** -// * Reindexes changes specific to the change transaction ID. -// *

-// * All exceptions are absorbed. -// */ -// private void reindexNodes(final String changeTxnId) -// { -// /* -// * This must execute each within its own transaction. -// * The cache size is therefore not an issue. -// */ -// TransactionWork reindexWork = new TransactionWork() -// { -// public Object doWork() throws Exception -// { -// // perform the work in a Hibernate callback -// HibernateCallback callback = new ReindexCallback(changeTxnId); -// getHibernateTemplate().execute(callback); -// // done -// return null; -// } -// }; -// try -// { -// TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, reindexWork); -// } -// catch (Throwable e) -// { -// logger.error("Transaction reindex failed: \n" + -// " txn: " + changeTxnId, -// e); -// } -// finally -// { -// // Up the current transaction now, in case the process fails at this point. -// // This will prevent the transaction from being processed again. -// // This applies to failures as well, which should be dealt with externally -// // and having the entire process start again, e.g. such as a system reboot -// currentTxnId = changeTxnId; -// } -// } -// -// /** -// * Stateful inner class that implements a single reindex call for a given store -// * and transaction. -// *

-// * It must be called within its own transaction. -// * -// * @author Derek Hulley -// */ -// private class ReindexCallback implements HibernateCallback -// { -// private final String changeTxnId; -// -// public ReindexCallback(String changeTxnId) -// { -// this.changeTxnId = changeTxnId; -// } -// -// /** -// * Changes the L2 cache usage before reindexing for each store -// * -// * @see #reindexNodes(StoreRef, String) -// */ -// public Object doInHibernate(Session session) -// { -// // set the way the L2 cache is used -// getSession().setCacheMode(l2CacheMode); -// -// // reindex each store -// for (StoreRef storeRef : storeRefs) -// { -// if (!nodeService.exists(storeRef)) -// { -// // the store is not present -// continue; -// } -// // reindex for store -// reindexNodes(storeRef, changeTxnId); -// } -// // done -// return null; -// } -// -// private void reindexNodes(StoreRef storeRef, String changeTxnId) -// { -// // check if we need to perform this operation -// SearchParameters sp = new SearchParameters(); -// sp.addStore(storeRef); -// -// // search for it in the index -// String query = "TX:\"" + changeTxnId + "\""; -// sp.setLanguage(SearchService.LANGUAGE_LUCENE); -// sp.setQuery(query); -// ResultSet results = null; -// try -// { -// results = searcher.query(sp); -// // did the index have any of these changes? -// if (results.length() > 0) -// { -// // the transaction has an entry in the index - assume that it was -// // atomically correct -// if (logger.isDebugEnabled()) -// { -// logger.debug("Transaction present in index - no indexing required: \n" + -// " store: " + storeRef + "\n" + -// " txn: " + changeTxnId); -// } -// return; -// } -// } -// finally -// { -// if (results != null) -// { -// results.close(); -// } -// } -// // the index has no record of this -// // were there any changes, or is it all just deletions? -// int changedCount = getChangedNodeStatusesCount(storeRef, changeTxnId); -// if (changedCount == 0) -// { -// // no nodes were changed in the transaction, i.e. they are only deletions -// // the index is quite right not to have any entries for the transaction -// if (logger.isDebugEnabled()) -// { -// logger.debug("Transaction only has deletions - no indexing required: \n" + -// " store: " + storeRef + "\n" + -// " txn: " + changeTxnId); -// } -// return; -// } -// -// // process the deletions relevant to the txn and the store -// List deletedNodeStatuses = getDeletedNodeStatuses(storeRef, changeTxnId); -// for (NodeStatus status : deletedNodeStatuses) -// { -// NodeRef nodeRef = new NodeRef(storeRef, status.getKey().getGuid()); -// // only the child node ref is relevant -// ChildAssociationRef assocRef = new ChildAssociationRef( -// ContentModel.ASSOC_CHILDREN, -// null, -// null, -// nodeRef); -// indexer.deleteNode(assocRef); -// } -// -// // process additions -// List changedNodeStatuses = getChangedNodeStatuses(storeRef, changeTxnId); -// for (NodeStatus status : changedNodeStatuses) -// { -// NodeRef nodeRef = new NodeRef(storeRef, status.getKey().getGuid()); -// // get the primary assoc for the node -// ChildAssociationRef primaryAssocRef = nodeService.getPrimaryParent(nodeRef); -// // reindex -// indexer.createNode(primaryAssocRef); -// } -// -// // done -// if (logger.isDebugEnabled()) -// { -// logger.debug("Transaction reindexed: \n" + -// " store: " + storeRef + "\n" + -// " txn: " + changeTxnId + "\n" + -// " deletions: " + deletedNodeStatuses.size() + "\n" + -// " modifications: " + changedNodeStatuses.size()); -// } -// } -// }; -// -// /** -// * Retrieve all transaction IDs that are greater than the given transaction ID. -// * -// * @param currentTxnId the transaction ID that must be less than all returned results -// * @return Returns an ordered list of transaction IDs -// */ -// @SuppressWarnings("unchecked") -// public List getNextChangeTxnIds(final String currentTxnId) -// { -// HibernateCallback callback = new HibernateCallback() -// { -// public Object doInHibernate(Session session) -// { -// Query query = session.getNamedQuery(QUERY_GET_NEXT_CHANGE_TXN_IDS); -// query.setString("currentTxnId", currentTxnId) -// .setReadOnly(true); -// return query.list(); -// } -// }; -// List queryResults = (List) getHibernateTemplate().execute(callback); -// // done -// return queryResults; -// } -// -// @SuppressWarnings("unchecked") -// public int getChangedNodeStatusesCount(final StoreRef storeRef, final String changeTxnId) -// { -// HibernateCallback callback = new HibernateCallback() -// { -// public Object doInHibernate(Session session) -// { -// Query query = session.getNamedQuery(QUERY_GET_CHANGED_NODE_STATUSES_COUNT); -// query.setString("storeProtocol", storeRef.getProtocol()) -// .setString("storeIdentifier", storeRef.getIdentifier()) -// .setString("changeTxnId", changeTxnId) -// .setReadOnly(true); -// return query.uniqueResult(); -// } -// }; -// Integer changeCount = (Integer) getHibernateTemplate().execute(callback); -// // done -// return changeCount.intValue(); -// } -// -// @SuppressWarnings("unchecked") -// public List getChangedNodeStatuses(final StoreRef storeRef, final String changeTxnId) -// { -// HibernateCallback callback = new HibernateCallback() -// { -// public Object doInHibernate(Session session) -// { -// Query query = session.getNamedQuery(QUERY_GET_CHANGED_NODE_STATUSES); -// query.setString("storeProtocol", storeRef.getProtocol()) -// .setString("storeIdentifier", storeRef.getIdentifier()) -// .setString("changeTxnId", changeTxnId) -// .setReadOnly(true); -// return query.list(); -// } -// }; -// List queryResults = (List) getHibernateTemplate().execute(callback); -// // done -// return queryResults; -// } -// -// @SuppressWarnings("unchecked") -// public List getDeletedNodeStatuses(final StoreRef storeRef, final String changeTxnId) -// { -// HibernateCallback callback = new HibernateCallback() -// { -// public Object doInHibernate(Session session) -// { -// Query query = session.getNamedQuery(QUERY_GET_DELETED_NODE_STATUSES); -// query.setString("storeProtocol", storeRef.getProtocol()) -// .setString("storeIdentifier", storeRef.getIdentifier()) -// .setString("changeTxnId", changeTxnId) -// .setReadOnly(true); -// return query.list(); -// } -// }; -// List queryResults = (List) getHibernateTemplate().execute(callback); -// // done -// return queryResults; -// } -//} \ No newline at end of file +/* + * Copyright (C) 2005-2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.node.index; + +import java.util.List; + +import org.alfresco.repo.search.impl.lucene.LuceneIndexerImpl; +import org.alfresco.repo.transaction.TransactionUtil; +import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.ResultSetRow; +import org.alfresco.service.cmr.search.SearchParameters; +import org.alfresco.service.cmr.search.SearchService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This component attempts to reindex + * + * @author Derek Hulley + */ +public class MissingContentReindexComponent extends AbstractReindexComponent +{ + private static Log logger = LogFactory.getLog(MissingContentReindexComponent.class); + + /** keep track of whether the FTS indexer thread has been poked */ + private boolean ftsIndexerCalled; + + public MissingContentReindexComponent() + { + ftsIndexerCalled = false; + } + + /** + * If this object is currently busy, then it just nothing + */ + @Override + public void reindexImpl() + { + List storeRefs = nodeService.getStores(); + int count = 0; + for (StoreRef storeRef : storeRefs) + { + // prompt the FTS reindexing + if (!ftsIndexerCalled) + { + ftsIndexer.requiresIndex(storeRef); + } + // reindex missing content + count += reindexMissingContent(storeRef); + // check if we have to break out + if (isShuttingDown()) + { + break; + } + } + + // The FTS indexer only needs to be prompted once + ftsIndexerCalled = true; + + // done + if (logger.isDebugEnabled()) + { + logger.debug("Missing content indexing touched " + count + " content nodes"); + } + } + + /** + * @param storeRef the store to check for missing content + * @return Returns the number of documents reindexed + */ + private int reindexMissingContent(StoreRef storeRef) + { + SearchParameters sp = new SearchParameters(); + sp.addStore(storeRef); + + // search for it in the index, sorting with youngest first + sp.setLanguage(SearchService.LANGUAGE_LUCENE); + sp.setQuery("TEXT:" + LuceneIndexerImpl.NOT_INDEXED_CONTENT_MISSING); + sp.addSort(SearchParameters.SORT_IN_DOCUMENT_ORDER_DESCENDING); + ResultSet results = null; + try + { + results = searcher.query(sp); + + int count = 0; + // iterate over the nodes and prompt for reindexing + for (ResultSetRow row : results) + { + final NodeRef childNodeRef = row.getNodeRef(); + // prompt for a reindex - it might fail again, but we just keep plugging away + TransactionWork reindexWork = new TransactionWork() + { + public Object doWork() + { + indexer.updateNode(childNodeRef); + return null; + } + }; + TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, reindexWork); + // check if we have to break out + if (isShuttingDown()) + { + break; + } + } + // done + if (logger.isDebugEnabled()) + { + logger.debug( + "Reindexed missing content: \n" + + " store: " + storeRef + "\n" + + " node count: " + count); + } + return count; + } + finally + { + if (results != null) + { + results.close(); + } + } + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/node/index/MissingContentReindexComponentTest.java b/source/java/org/alfresco/repo/node/index/MissingContentReindexComponentTest.java new file mode 100644 index 0000000000..04e3830c63 --- /dev/null +++ b/source/java/org/alfresco/repo/node/index/MissingContentReindexComponentTest.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2005-2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.node.index; + +import junit.framework.TestCase; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.AbstractContentStore; +import org.alfresco.repo.content.ContentStore; +import org.alfresco.repo.node.db.NodeDaoService; +import org.alfresco.repo.search.Indexer; +import org.alfresco.repo.search.impl.lucene.LuceneIndexerImpl; +import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.transaction.TransactionComponent; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.SearchParameters; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.springframework.context.ApplicationContext; + +/** + * @see org.alfresco.repo.node.index.MissingContentReindexComponent + * + * @author Derek Hulley + */ +public class MissingContentReindexComponentTest extends TestCase +{ + private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + + private AuthenticationComponent authenticationComponent; + private SearchService searchService; + private NodeService nodeService; + private FileFolderService fileFolderService; + private ContentStore contentStore; + private FullTextSearchIndexer ftsIndexer; + private NodeRef rootNodeRef; + private MissingContentReindexComponent reindexer; + + @Override + protected void setUp() throws Exception + { + ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); + searchService = serviceRegistry.getSearchService(); + nodeService = serviceRegistry.getNodeService(); + fileFolderService = serviceRegistry.getFileFolderService(); + authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponentImpl"); + contentStore = (ContentStore) ctx.getBean("fileContentStore"); + ftsIndexer = (FullTextSearchIndexer) ctx.getBean("LuceneFullTextSearchIndexer"); + + Indexer indexer = (Indexer) ctx.getBean("indexerComponent"); + NodeDaoService nodeDaoService = (NodeDaoService) ctx.getBean("nodeDaoService"); + TransactionService transactionService = serviceRegistry.getTransactionService(); + reindexer = new MissingContentReindexComponent(); + reindexer.setAuthenticationComponent(authenticationComponent); + reindexer.setFtsIndexer(ftsIndexer); + reindexer.setIndexer(indexer); + reindexer.setNodeDaoService(nodeDaoService); + reindexer.setNodeService(nodeService); + reindexer.setSearcher(searchService); + reindexer.setTransactionComponent((TransactionComponent)transactionService); + + // authenticate + authenticationComponent.setSystemUserAsCurrentUser(); + + // create a root node for the test + StoreRef storeRef = nodeService.createStore("test", getName() + "-" + System.nanoTime()); + rootNodeRef = nodeService.getRootNode(storeRef); + rootNodeRef = nodeService.createNode( + rootNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQName("cm:x"), + ContentModel.TYPE_FOLDER).getChildRef(); + } + + @Override + protected void tearDown() throws Exception + { + authenticationComponent.clearCurrentSecurityContext(); + } + + /** + * Create a node with a content URL that points to missing content. It then + * checks that the indexing flagged it, prompts a reindex of missing content + * and checks that the text was properly indexed. + */ + public synchronized void testReindex() throws Exception + { + // create a node with missing content + String contentUrl = AbstractContentStore.createNewUrl(); + ContentData contentData = new ContentData(contentUrl, "text/plain", 0L, "UTF8"); + + // create the file node + NodeRef nodeRef = fileFolderService.create(rootNodeRef, "myfile", ContentModel.TYPE_CONTENT).getNodeRef(); + // add the content + nodeService.setProperty(nodeRef, ContentModel.PROP_CONTENT, contentData); + + // wait a bit for the indexing + ftsIndexer.index(); + wait(1000); + + // check that the content was but that the content was M.I.A. + SearchParameters sp = new SearchParameters(); + sp.addStore(rootNodeRef.getStoreRef()); + sp.setLanguage(SearchService.LANGUAGE_LUCENE); + sp.setQuery("TEXT:" + LuceneIndexerImpl.NOT_INDEXED_CONTENT_MISSING); + sp.addSort(SearchParameters.SORT_IN_DOCUMENT_ORDER_DESCENDING); + ResultSet results = null; + try + { + results = searchService.query(sp); + assertTrue("Content missing NICM not found", results.length() == 1); + } + finally + { + if (results != null) { results.close(); } + } + + // now put some content in the store + ContentWriter writer = contentStore.getWriter(null, contentUrl); + writer.setMimetype("text/plain"); + writer.setEncoding("UTF8"); + writer.putContent("123abc456def"); + + // prompt for reindex + reindexer.reindex(); + + // wait for it to have been indexed again + ftsIndexer.index(); + wait(1000); + + // search for the text + sp = new SearchParameters(); + sp.addStore(rootNodeRef.getStoreRef()); + sp.setLanguage(SearchService.LANGUAGE_LUCENE); + sp.setQuery("TEXT:" + "123abc456def"); + sp.addSort("@" + ContentModel.PROP_CREATED, false); + results = null; + try + { + results = searchService.query(sp); + assertTrue("Indexed content node found", results.length() == 1); + } + finally + { + if (results != null) { results.close(); } + } + } +} diff --git a/source/java/org/alfresco/repo/node/integrity/IntegrityChecker.java b/source/java/org/alfresco/repo/node/integrity/IntegrityChecker.java index e93ff18425..6f7be2bda8 100644 --- a/source/java/org/alfresco/repo/node/integrity/IntegrityChecker.java +++ b/source/java/org/alfresco/repo/node/integrity/IntegrityChecker.java @@ -88,6 +88,8 @@ public class IntegrityChecker /** key against which the set of events is stored in the current transaction */ private static final String KEY_EVENT_SET = "IntegrityChecker.EventSet"; + /** key to store the local flag to disable integrity errors, i.e. downgrade to warnings */ + private static final String KEY_WARN_IN_TRANSACTION = "IntegrityChecker.WarnInTransaction"; private PolicyComponent policyComponent; private DictionaryService dictionaryService; @@ -97,6 +99,36 @@ public class IntegrityChecker private int maxErrorsPerTransaction; private boolean traceOn; + /** + * Downgrade violations to warnings within the current transaction. This is temporary and + * is dependent on there being a current transaction active against the + * current thread. When set, this will override the global + * {@link #setFailOnViolation(boolean) failure behaviour}. + */ + public static void setWarnInTransaction() + { + AlfrescoTransactionSupport.bindResource(KEY_WARN_IN_TRANSACTION, Boolean.TRUE); + } + + /** + * @return Returns true if the current transaction should only warn on violations. + * If false, the global setting will take effect. + * + * @see #setWarnInTransaction() + */ + public static boolean isWarnInTransaction() + { + Boolean warnInTransaction = (Boolean) AlfrescoTransactionSupport.getResource(KEY_WARN_IN_TRANSACTION); + if (warnInTransaction == null || warnInTransaction == Boolean.FALSE) + { + return false; + } + else + { + return true; + } + } + /** */ public IntegrityChecker() @@ -572,7 +604,8 @@ public class IntegrityChecker } sb.append("\n").append(failure); } - if (failOnViolation) + boolean warnOnly = IntegrityChecker.isWarnInTransaction(); + if (failOnViolation && !warnOnly) { logger.error(sb.toString()); throw new IntegrityException(failures); diff --git a/source/java/org/alfresco/repo/node/integrity/IntegrityTest.java b/source/java/org/alfresco/repo/node/integrity/IntegrityTest.java index 93c9ac253f..724393d11d 100644 --- a/source/java/org/alfresco/repo/node/integrity/IntegrityTest.java +++ b/source/java/org/alfresco/repo/node/integrity/IntegrityTest.java @@ -198,6 +198,18 @@ public class IntegrityTest extends TestCase assertNotNull("Static IntegrityChecker not created", integrityChecker); } + public void testTemporaryDowngrading() throws Exception + { + assertEquals("Per-transaction override not correct", false, IntegrityChecker.isWarnInTransaction()); + // create bad node + NodeRef nodeRef = createNode("abc", TEST_TYPE_WITH_PROPERTIES, null); + // switch it off + IntegrityChecker.setWarnInTransaction(); + assertEquals("Per-transaction override not correct", true, IntegrityChecker.isWarnInTransaction()); + // now, only warnings should occur + checkIntegrityNoFailure(); + } + public void testCreateWithoutProperties() throws Exception { NodeRef nodeRef = createNode("abc", TEST_TYPE_WITH_PROPERTIES, null); diff --git a/source/java/org/alfresco/repo/ownable/impl/OwnableServiceTest.java b/source/java/org/alfresco/repo/ownable/impl/OwnableServiceTest.java index 79b87c0336..088524f6fc 100644 --- a/source/java/org/alfresco/repo/ownable/impl/OwnableServiceTest.java +++ b/source/java/org/alfresco/repo/ownable/impl/OwnableServiceTest.java @@ -141,6 +141,14 @@ public class OwnableServiceTest extends TestCase permissionService.setInheritParentPermissions(testNode, false); + + assertEquals(AccessStatus.DENIED, permissionService.hasPermission(rootNodeRef, PermissionService.TAKE_OWNERSHIP)); + assertEquals(AccessStatus.DENIED, permissionService.hasPermission(rootNodeRef, PermissionService.SET_OWNER)); + assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(testNode, PermissionService.TAKE_OWNERSHIP)); + assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(testNode, PermissionService.SET_OWNER)); + + permissionService.setPermission(rootNodeRef, "andy", PermissionService.WRITE_PROPERTIES, true); + assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(rootNodeRef, PermissionService.TAKE_OWNERSHIP)); assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(rootNodeRef, PermissionService.SET_OWNER)); assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(testNode, PermissionService.TAKE_OWNERSHIP)); diff --git a/source/java/org/alfresco/repo/policy/TransactionBehaviourQueue.java b/source/java/org/alfresco/repo/policy/TransactionBehaviourQueue.java index bf46e807aa..f317dd14ef 100644 --- a/source/java/org/alfresco/repo/policy/TransactionBehaviourQueue.java +++ b/source/java/org/alfresco/repo/policy/TransactionBehaviourQueue.java @@ -25,7 +25,6 @@ import java.util.Queue; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.policy.Policy.Arg; -import org.alfresco.repo.rule.RuleTransactionListener; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.TransactionListener; import org.alfresco.util.GUID; @@ -214,7 +213,7 @@ public class TransactionBehaviourQueue implements TransactionListener { return true; } - if (obj instanceof RuleTransactionListener) + if (obj instanceof TransactionBehaviourQueue) { TransactionBehaviourQueue that = (TransactionBehaviourQueue) obj; return (this.id.equals(that.id)); diff --git a/source/java/org/alfresco/repo/search/IndexerSPI.java b/source/java/org/alfresco/repo/search/IndexerSPI.java index 82a6e311ee..695c177901 100644 --- a/source/java/org/alfresco/repo/search/IndexerSPI.java +++ b/source/java/org/alfresco/repo/search/IndexerSPI.java @@ -22,6 +22,6 @@ public interface IndexerSPI extends Indexer { public void registerCallBack(FTSIndexerAware callBack); - public void updateFullTextSearch(int i); + public int updateFullTextSearch(int i); } diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ClosingIndexSearcher.java b/source/java/org/alfresco/repo/search/impl/lucene/ClosingIndexSearcher.java index 60e6753f28..85dc12fe66 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/ClosingIndexSearcher.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/ClosingIndexSearcher.java @@ -42,6 +42,11 @@ public class ClosingIndexSearcher extends IndexSearcher this.reader = r; } + /*package*/ IndexReader getReader() + { + return reader; + } + @Override public void close() throws IOException { diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAnalyser.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAnalyser.java index d810438117..593436647a 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAnalyser.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAnalyser.java @@ -29,13 +29,13 @@ import org.alfresco.service.namespace.QName; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.WhitespaceAnalyzer; -import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser; /** * Analyse properties according to the property definition. * * The default is to use the standard tokeniser. The tokeniser should not have - * been called when indexeing properties that require no tokenisation. (tokenise + * been called when indexing properties that require no tokenisation. (tokenise * should be set to false when adding the field to the document) * * @author andyh @@ -60,7 +60,7 @@ public class LuceneAnalyser extends Analyzer */ public LuceneAnalyser(DictionaryService dictionaryService) { - this(new StandardAnalyzer()); + this(new AlfrescoStandardAnalyser()); this.dictionaryService = dictionaryService; } diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneBase2.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneBase2.java index 38d0242659..681ce81354 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneBase2.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneBase2.java @@ -145,7 +145,7 @@ public abstract class LuceneBase2 } } - protected Searcher getSearcher(LuceneIndexer2 luceneIndexer) throws LuceneIndexException + protected ClosingIndexSearcher getSearcher(LuceneIndexer2 luceneIndexer) throws LuceneIndexException { // If we know the delta id we should do better diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl.java index fc1c41ec58..91310ecfcd 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl.java @@ -1696,13 +1696,13 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer return false; } - public void updateFullTextSearch(int size) throws LuceneIndexException + public int updateFullTextSearch(int size) throws LuceneIndexException { checkAbleToDoWork(true, false); if (!mainIndexExists()) { remainingCount = size; - return; + return 0; } try { @@ -1723,7 +1723,7 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer if(searcher == null) { remainingCount = size; - return; + return 0; } Hits hits; try @@ -1817,7 +1817,9 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer } } - remainingCount = count - writer.docCount(); + int done = writer.docCount(); + remainingCount = count - done; + return done; } catch (LuceneIndexException e) { @@ -1825,8 +1827,14 @@ public class LuceneIndexerImpl extends LuceneBase implements LuceneIndexer { closeDeltaWriter(); } + return 0; } } + else + { + return 0; + } + } catch (LuceneIndexException e) { diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl2.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl2.java index 8639fbf790..3ea070e565 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl2.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneIndexerImpl2.java @@ -43,7 +43,6 @@ import org.alfresco.repo.search.IndexerException; import org.alfresco.repo.search.impl.lucene.fts.FTSIndexerAware; import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer; import org.alfresco.repo.search.impl.lucene.index.TransactionStatus; -import org.alfresco.repo.search.impl.lucene.index.IndexInfo.LockWork; import org.alfresco.service.cmr.dictionary.AspectDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; @@ -1316,7 +1315,7 @@ public class LuceneIndexerImpl2 extends LuceneBase2 implements LuceneIndexer2 if (includeDirectoryDocuments) { - if (nodeTypeDef.getChildAssociations().size() > 0) + if (nodeTypeDef != null && nodeTypeDef.getChildAssociations().size() > 0) { if (directPaths.contains(pair.getFirst())) { @@ -1748,7 +1747,7 @@ public class LuceneIndexerImpl2 extends LuceneBase2 implements LuceneIndexer2 return false; } - public void updateFullTextSearch(int size) throws LuceneIndexException + public int updateFullTextSearch(int size) throws LuceneIndexException { checkAbleToDoWork(true, false); // if (!mainIndexExists()) @@ -1775,7 +1774,7 @@ public class LuceneIndexerImpl2 extends LuceneBase2 implements LuceneIndexer2 if (searcher == null) { remainingCount = size; - return; + return 0; } Hits hits; try @@ -1869,7 +1868,9 @@ public class LuceneIndexerImpl2 extends LuceneBase2 implements LuceneIndexer2 } } - remainingCount = count - writer.docCount(); + int done = writer.docCount(); + remainingCount = count - done; + return done; } catch (LuceneIndexException e) { @@ -1877,8 +1878,13 @@ public class LuceneIndexerImpl2 extends LuceneBase2 implements LuceneIndexer2 { closeDeltaWriter(); } + return 0; } } + else + { + return 0; + } } catch (IOException e) { diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneQueryParser.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneQueryParser.java index 8f2f6d70a4..aa7315956f 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneQueryParser.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneQueryParser.java @@ -156,7 +156,25 @@ public class LuceneQueryParser extends QueryParser } else if (field.equals("TYPE")) { - TypeDefinition target = dictionaryService.getType(QName.createQName(queryText)); + TypeDefinition target; + if(queryText.startsWith("{")) + { + target = dictionaryService.getType(QName.createQName(queryText)); + } + else + { + int colonPosition = queryText.indexOf(':'); + if (colonPosition == -1) + { + // use the default namespace + target = dictionaryService.getType(QName.createQName(namespacePrefixResolver.getNamespaceURI(""), queryText)); + } + else + { + // find the prefix + target = dictionaryService.getType(QName.createQName(namespacePrefixResolver.getNamespaceURI(queryText.substring(0, colonPosition)), queryText.substring(colonPosition + 1))); + } + } if (target == null) { throw new SearcherException("Invalid type: " + queryText); @@ -186,7 +204,26 @@ public class LuceneQueryParser extends QueryParser } else if (field.equals("ASPECT")) { - AspectDefinition target = dictionaryService.getAspect(QName.createQName(queryText)); + AspectDefinition target; + if(queryText.startsWith("{")) + { + target = dictionaryService.getAspect(QName.createQName(queryText)); + } + else + { + int colonPosition = queryText.indexOf(':'); + if (colonPosition == -1) + { + // use the default namespace + target = dictionaryService.getAspect(QName.createQName(namespacePrefixResolver.getNamespaceURI(""), queryText)); + } + else + { + // find the prefix + target = dictionaryService.getAspect(QName.createQName(namespacePrefixResolver.getNamespaceURI(queryText.substring(0, colonPosition)), queryText.substring(colonPosition + 1))); + } + } + QName targetQName = target.getName(); HashSet subclasses = new HashSet(); for (QName classRef : dictionaryService.getAllAspects()) diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneSearcherImpl2.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneSearcherImpl2.java index 193226c743..7a9b576895 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneSearcherImpl2.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneSearcherImpl2.java @@ -59,17 +59,13 @@ import org.saxpath.SAXPathException; import com.werken.saxpath.XPathReader; /** - * The Lucene implementation of Searcher At the moment we support only lucene - * based queries. - * - * TODO: Support for other query languages + * The Lucene implementation of Searcher At the moment we support only lucene based queries. TODO: Support for other query languages * * @author andyh - * */ public class LuceneSearcherImpl2 extends LuceneBase2 implements LuceneSearcher2 { - + /** * Default field name */ @@ -90,9 +86,7 @@ public class LuceneSearcherImpl2 extends LuceneBase2 implements LuceneSearcher2 */ /** - * Get an initialised searcher for the store and transaction Normally we do - * not search against a a store and delta. Currently only gets the searcher - * against the main index. + * Get an initialised searcher for the store and transaction Normally we do not search against a a store and delta. Currently only gets the searcher against the main index. * * @param storeRef * @param deltaId @@ -115,9 +109,7 @@ public class LuceneSearcherImpl2 extends LuceneBase2 implements LuceneSearcher2 } /** - * Get an intialised searcher for the store. No transactional ammendsmends - * are searched. - * + * Get an intialised searcher for the store. No transactional ammendsmends are searched. * * @param storeRef * @return @@ -134,7 +126,7 @@ public class LuceneSearcherImpl2 extends LuceneBase2 implements LuceneSearcher2 public boolean indexExists() { - //return mainIndexExists(); + // return mainIndexExists(); return true; } @@ -220,7 +212,7 @@ public class LuceneSearcherImpl2 extends LuceneBase2 implements LuceneSearcher2 Query query = LuceneQueryParser.parse(parameterisedQueryString, DEFAULT_FIELD, new LuceneAnalyser( dictionaryService), namespacePrefixResolver, dictionaryService, defaultOperator); - Searcher searcher = getSearcher(indexer); + ClosingIndexSearcher searcher = getSearcher(indexer); if (searcher == null) { // no index return an empty result set @@ -238,7 +230,14 @@ public class LuceneSearcherImpl2 extends LuceneBase2 implements LuceneSearcher2 switch (sd.getSortType()) { case FIELD: - fields[index++] = new SortField(sd.getField(), !sd.isAscending()); + if (searcher.getReader().getFieldNames().contains(sd.getField())) + { + fields[index++] = new SortField(sd.getField(), !sd.isAscending()); + } + else + { + fields[index++] = new SortField(null, SortField.DOC, !sd.isAscending()); + } break; case DOCUMENT: fields[index++] = new SortField(null, SortField.DOC, !sd.isAscending()); @@ -348,8 +347,7 @@ public class LuceneSearcherImpl2 extends LuceneBase2 implements LuceneSearcher2 } /** - * The definitions must provide a default value, or of not there must be a - * parameter to provide the value + * The definitions must provide a default value, or of not there must be a parameter to provide the value * * @param definition * @param queryParameters @@ -396,12 +394,9 @@ public class LuceneSearcherImpl2 extends LuceneBase2 implements LuceneSearcher2 } /* - * Parameterise the query string - not sure if it is required to escape - * lucence spacials chars The parameters could be used to build the query - - * the contents of parameters should alread have been escaped if required. - * ... mush better to provide the parameters and work out what to do TODO: - * conditional query escapement - may be we should have a parameter type - * that is not escaped + * Parameterise the query string - not sure if it is required to escape lucence spacials chars The parameters could be used to build the query - the contents of parameters + * should alread have been escaped if required. ... mush better to provide the parameters and work out what to do TODO: conditional query escapement - may be we should have a + * parameter type that is not escaped */ private String parameterise(String unparameterised, Map map, QueryParameter[] queryParameters, NamespacePrefixResolver nspr) throws QueryParameterisationException @@ -567,7 +562,6 @@ public class LuceneSearcherImpl2 extends LuceneBase2 implements LuceneSearcher2 /** * @return Returns true if the pattern is present, otherwise false. - * * @see #setIndexer(Indexer) * @see #setSearcher(SearchService) */ diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneTest2.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneTest2.java index 92a10d0ea9..52dfd3a918 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneTest2.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneTest2.java @@ -37,7 +37,9 @@ import junit.framework.TestCase; import org.alfresco.model.ContentModel; import org.alfresco.repo.dictionary.DictionaryDAO; +import org.alfresco.repo.dictionary.DictionaryNamespaceComponent; import org.alfresco.repo.dictionary.M2Model; +import org.alfresco.repo.dictionary.NamespaceDAOImpl; import org.alfresco.repo.node.BaseNodeServiceTest; import org.alfresco.repo.search.QueryParameterDefImpl; import org.alfresco.repo.search.QueryRegisterComponent; @@ -159,7 +161,7 @@ public class LuceneTest2 extends TestCase private QueryRegisterComponent queryRegisterComponent; - private NamespacePrefixResolver namespacePrefixResolver; + private DictionaryNamespaceComponent namespacePrefixResolver; private LuceneIndexerAndSearcher indexerAndSearcher; @@ -171,6 +173,8 @@ public class LuceneTest2 extends TestCase private NodeRef[] documentOrder; + private NamespaceDAOImpl namespaceDao; + public LuceneTest2() { super(); @@ -185,10 +189,13 @@ public class LuceneTest2 extends TestCase luceneFTS = (FullTextSearchIndexer) ctx.getBean("LuceneFullTextSearchIndexer"); contentService = (ContentService) ctx.getBean("contentService"); queryRegisterComponent = (QueryRegisterComponent) ctx.getBean("queryRegisterComponent"); - namespacePrefixResolver = (NamespacePrefixResolver) ctx.getBean("namespaceService"); + namespacePrefixResolver = (DictionaryNamespaceComponent) ctx.getBean("namespaceService"); indexerAndSearcher = (LuceneIndexerAndSearcher) ctx.getBean("luceneIndexerAndSearcherFactory"); transactionService = (TransactionService) ctx.getBean("transactionComponent"); serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); + + namespaceDao = (NamespaceDAOImpl) ctx.getBean("namespaceDAO"); + this.authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent"); @@ -208,7 +215,9 @@ public class LuceneTest2 extends TestCase assertNotNull(modelStream); M2Model model = M2Model.createModel(modelStream); dictionaryDAO.putModel(model); - + + namespaceDao.addPrefix("test", TEST_NAMESPACE); + StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis()); rootNodeRef = nodeService.getRootNode(storeRef); @@ -372,6 +381,10 @@ public class LuceneTest2 extends TestCase super(arg0); } + public void firstTest() throws Exception + { + testSort(); + } public void test0() throws Exception { @@ -1054,6 +1067,17 @@ public class LuceneTest2 extends TestCase results.close(); luceneFTS.resume(); + + + SearchParameters sp17 = new SearchParameters(); + sp17.addStore(rootNodeRef.getStoreRef()); + sp17.setLanguage(SearchService.LANGUAGE_LUCENE); + sp17.setQuery("PATH:\"//.\""); + sp17.addSort("cabbage", false); + results = searcher.query(sp17); + results.close(); + + luceneFTS.resume(); } public void test1() throws Exception @@ -1861,19 +1885,39 @@ public class LuceneTest2 extends TestCase null); assertEquals(1, results.length()); results.close(); + + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "TYPE:\"" + testType.toPrefixString(namespacePrefixResolver) + "\"", null, + null); + assertEquals(1, results.length()); + results.close(); results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "TYPE:\"" + testSuperType.toString() + "\"", null, null); assertEquals(13, results.length()); results.close(); + + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "TYPE:\"" + testSuperType.toPrefixString(namespacePrefixResolver) + "\"", + null, null); + assertEquals(13, results.length()); + results.close(); results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "ASPECT:\"" - + ISO9075.getXPathName(testAspect) + "\"", null, null); + + testAspect.toString() + "\"", null, null); + assertEquals(1, results.length()); + results.close(); + + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "ASPECT:\"" + + testAspect.toPrefixString(namespacePrefixResolver) + "\"", null, null); assertEquals(1, results.length()); results.close(); results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "ASPECT:\"" - + ISO9075.getXPathName(testSuperAspect) + "\"", null, null); + + testAspect.toString() + "\"", null, null); + assertEquals(1, results.length()); + results.close(); + + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "ASPECT:\"" + + testAspect.toPrefixString(namespacePrefixResolver) + "\"", null, null); assertEquals(1, results.length()); results.close(); diff --git a/source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardAnalyser.java b/source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardAnalyser.java new file mode 100644 index 0000000000..2f67d5567c --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardAnalyser.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.search.impl.lucene.analysis; + +import java.io.Reader; +import java.util.Set; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.LowerCaseFilter; +import org.apache.lucene.analysis.StopAnalyzer; +import org.apache.lucene.analysis.StopFilter; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.standard.StandardFilter; +import org.apache.lucene.analysis.standard.StandardTokenizer; + + +public class AlfrescoStandardAnalyser extends Analyzer +{ + private Set stopSet; + + /** + * An array containing some common English words that are usually not useful for searching. + */ + public static final String[] STOP_WORDS = StopAnalyzer.ENGLISH_STOP_WORDS; + + /** Builds an analyzer. */ + public AlfrescoStandardAnalyser() + { + this(STOP_WORDS); + } + + /** Builds an analyzer with the given stop words. */ + public AlfrescoStandardAnalyser(String[] stopWords) + { + stopSet = StopFilter.makeStopSet(stopWords); + } + + /** + * Constructs a {@link StandardTokenizer} filtered by a {@link StandardFilter}, a {@link LowerCaseFilter} and a {@link StopFilter}. + */ + public TokenStream tokenStream(String fieldName, Reader reader) + { + TokenStream result = new StandardTokenizer(reader); + result = new AlfrescoStandardFilter(result); + result = new LowerCaseFilter(result); + result = new StopFilter(result, stopSet); + return result; + } +} diff --git a/source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardFilter.java b/source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardFilter.java new file mode 100644 index 0000000000..6006e4442c --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/lucene/analysis/AlfrescoStandardFilter.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.search.impl.lucene.analysis; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.Stack; +import java.util.StringTokenizer; + +import org.apache.lucene.analysis.TokenFilter; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.standard.StandardTokenizerConstants; + +public class AlfrescoStandardFilter extends TokenFilter implements StandardTokenizerConstants +{ + + /** Construct filtering in. */ + public AlfrescoStandardFilter(TokenStream in) + { + super(in); + } + + private static final String APOSTROPHE_TYPE = tokenImage[APOSTROPHE]; + + private static final String ACRONYM_TYPE = tokenImage[ACRONYM]; + + private static final String HOST_TYPE = tokenImage[HOST]; + + private static final String ALPHANUM_TYPE = tokenImage[ALPHANUM]; + + private Queue hostTokens = null; + + /** + * Returns the next token in the stream, or null at EOS. + *

+ * Removes 's from the end of words. + *

+ * Removes dots from acronyms. + *

+ * Splits host names ... + */ + public final org.apache.lucene.analysis.Token next() throws java.io.IOException + { + if (hostTokens == null) + { + org.apache.lucene.analysis.Token t = input.next(); + + if (t == null) + return null; + + String text = t.termText(); + String type = t.type(); + + if (type == APOSTROPHE_TYPE && // remove 's + (text.endsWith("'s") || text.endsWith("'S"))) + { + return new org.apache.lucene.analysis.Token(text.substring(0, text.length() - 2), t.startOffset(), t + .endOffset(), type); + + } + else if (type == ACRONYM_TYPE) + { // remove dots + StringBuffer trimmed = new StringBuffer(); + for (int i = 0; i < text.length(); i++) + { + char c = text.charAt(i); + if (c != '.') + trimmed.append(c); + } + return new org.apache.lucene.analysis.Token(trimmed.toString(), t.startOffset(), t.endOffset(), type); + + } + else if (type == HOST_TYPE) + { + // ("." )+ > + // There must be at least two tokens .... + hostTokens = new LinkedList(); + StringTokenizer tokeniser = new StringTokenizer(text, "."); + int start = t.startOffset(); + int end; + while (tokeniser.hasMoreTokens()) + { + String token = tokeniser.nextToken(); + end = start + token.length(); + hostTokens.offer(new org.apache.lucene.analysis.Token(token, start, end, ALPHANUM_TYPE)); + start = end + 1; + } + // check if we have an acronym ..... yes a.b.c ends up here ... + + if (text.length() == hostTokens.size() * 2 - 1) + { + hostTokens = null; + // acronym + StringBuffer trimmed = new StringBuffer(); + for (int i = 0; i < text.length(); i++) + { + char c = text.charAt(i); + if (c != '.') + trimmed.append(c); + } + return new org.apache.lucene.analysis.Token(trimmed.toString(), t.startOffset(), t.endOffset(), + ALPHANUM_TYPE); + } + else + { + return hostTokens.remove(); + } + } + else + { + return t; + } + } + else + { + org.apache.lucene.analysis.Token token = hostTokens.remove(); + if (hostTokens.isEmpty()) + { + hostTokens = null; + } + return token; + } + } +} diff --git a/source/java/org/alfresco/repo/search/impl/lucene/fts/FullTextSearchIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/fts/FullTextSearchIndexerImpl.java index def19125b7..edce57ef06 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/fts/FullTextSearchIndexerImpl.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/fts/FullTextSearchIndexerImpl.java @@ -31,7 +31,8 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearchIndexer { - private enum State { + private enum State + { ACTIVE, PAUSING, PAUSED }; @@ -48,7 +49,7 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc public FullTextSearchIndexerImpl() { super(); - //System.out.println("Created id is "+this); + // System.out.println("Created id is "+this); } /* @@ -64,8 +65,7 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc /* * (non-Javadoc) * - * @see org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer#indexCompleted(org.alfresco.repo.ref.StoreRef, - * int, java.lang.Exception) + * @see org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer#indexCompleted(org.alfresco.repo.ref.StoreRef, int, java.lang.Exception) */ public synchronized void indexCompleted(StoreRef storeRef, int remaining, Exception e) { @@ -83,7 +83,7 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc } finally { - //System.out.println("..Index Complete: id is "+this); + // System.out.println("..Index Complete: id is "+this); this.notifyAll(); } } @@ -96,19 +96,19 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc public synchronized void pause() throws InterruptedException { pauseCount++; - //System.out.println("..Waiting "+pauseCount+" id is "+this); + // System.out.println("..Waiting "+pauseCount+" id is "+this); while ((indexing.size() > 0)) { - //System.out.println("Pause: Waiting with count of "+indexing.size()+" id is "+this); + // System.out.println("Pause: Waiting with count of "+indexing.size()+" id is "+this); this.wait(); } pauseCount--; - if(pauseCount == 0) + if (pauseCount == 0) { paused = true; this.notifyAll(); // only resumers } - //System.out.println("..Remaining "+pauseCount +" paused = "+paused+" id is "+this); + // System.out.println("..Remaining "+pauseCount +" paused = "+paused+" id is "+this); } /* @@ -118,16 +118,16 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc */ public synchronized void resume() throws InterruptedException { - if(pauseCount == 0) + if (pauseCount == 0) { - //System.out.println("Direct resume"+" id is "+this); + // System.out.println("Direct resume"+" id is "+this); paused = false; } - else + else { - while(pauseCount > 0) + while (pauseCount > 0) { - //System.out.println("Reusme waiting on "+pauseCount+" id is "+this); + // System.out.println("Reusme waiting on "+pauseCount+" id is "+this); this.wait(); } paused = false; @@ -136,13 +136,13 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc private synchronized boolean isPaused() throws InterruptedException { - if(pauseCount == 0) + if (pauseCount == 0) { - return paused; + return paused; } - else + else { - while(pauseCount > 0) + while (pauseCount > 0) { this.wait(); } @@ -160,17 +160,22 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc // Use the calling thread to index // Parallel indexing via multiple Quartz thread initiating indexing - StoreRef toIndex = getNextRef(); - if (toIndex != null) + int done = 0; + while (done == 0) { - //System.out.println("Indexing "+toIndex+" at "+(new java.util.Date())); - IndexerSPI indexer = luceneIndexerAndSearcherFactory.getIndexer(toIndex); - indexer.registerCallBack(this); - indexer.updateFullTextSearch(1000); - } - else - { - //System.out.println("Nothing to Indexing at "+(new java.util.Date())); + StoreRef toIndex = getNextRef(); + if (toIndex != null) + { + // System.out.println("Indexing "+toIndex+" at "+(new java.util.Date())); + IndexerSPI indexer = luceneIndexerAndSearcherFactory.getIndexer(toIndex); + indexer.registerCallBack(this); + done += indexer.updateFullTextSearch(1000); + } + else + { + break; + // System.out.println("Nothing to Indexing at "+(new java.util.Date())); + } } } @@ -178,7 +183,7 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc { if (paused || (pauseCount > 0)) { - //System.out.println("Indexing suspended"+" id is "+this); + // System.out.println("Indexing suspended"+" id is "+this); return null; } @@ -189,6 +194,8 @@ public class FullTextSearchIndexerImpl implements FTSIndexerAware, FullTextSearc if (!indexing.contains(ref)) { nextStoreRef = ref; + // FIFO + break; } } diff --git a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java index 0408317939..d049131c30 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfo.java @@ -52,7 +52,7 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.util.GUID; import org.apache.log4j.Logger; import org.apache.lucene.analysis.Analyzer; -import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser; import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; @@ -306,7 +306,7 @@ public class IndexInfo IndexWriter writer; try { - writer = new IndexWriter(oldIndex, new StandardAnalyzer(), false); + writer = new IndexWriter(oldIndex, new AlfrescoStandardAnalyser(), false); writer.setUseCompoundFile(writerUseCompoundFile); writer.minMergeDocs = writerMinMergeDocs; writer.mergeFactor = writerMergeFactor; @@ -442,7 +442,7 @@ public class IndexInfo IndexWriter writer; try { - writer = new IndexWriter(emptyIndex, new StandardAnalyzer(), true); + writer = new IndexWriter(emptyIndex, new AlfrescoStandardAnalyser(), true); writer.setUseCompoundFile(writerUseCompoundFile); writer.minMergeDocs = writerMinMergeDocs; writer.mergeFactor = writerMergeFactor; @@ -2424,11 +2424,11 @@ public class IndexInfo if (docCount < maxDocsForInMemoryMerge) { ramDirectory = new RAMDirectory(); - writer = new IndexWriter(ramDirectory, new StandardAnalyzer(), true); + writer = new IndexWriter(ramDirectory, new AlfrescoStandardAnalyser(), true); } else { - writer = new IndexWriter(location, new StandardAnalyzer(), true); + writer = new IndexWriter(location, new AlfrescoStandardAnalyser(), true); } writer.setUseCompoundFile(mergerUseCompoundFile); diff --git a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfoTest.java b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfoTest.java index 3770a4f39e..7f48f2748a 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfoTest.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/index/IndexInfoTest.java @@ -25,7 +25,7 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.util.GUID; import org.alfresco.util.TempFileProvider; -import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexReader; @@ -95,7 +95,7 @@ public static final String[] UPDATE_LIST_2 = { "alpha2", "bravo2", "charlie2", " String guid = GUID.generate(); ii.setStatus(guid, TransactionStatus.ACTIVE, null, null); - IndexWriter writer = ii.getDeltaIndexWriter(guid, new StandardAnalyzer()); + IndexWriter writer = ii.getDeltaIndexWriter(guid, new AlfrescoStandardAnalyser()); Document doc = new Document(); for (int k = 0; k < 15; k++) @@ -193,7 +193,7 @@ public static final String[] UPDATE_LIST_2 = { "alpha2", "bravo2", "charlie2", " String guid = GUID.generate(); ii.setStatus(guid, TransactionStatus.ACTIVE, null, null); - IndexWriter writer = ii.getDeltaIndexWriter(guid, new StandardAnalyzer()); + IndexWriter writer = ii.getDeltaIndexWriter(guid, new AlfrescoStandardAnalyser()); Document doc = new Document(); for (int k = 0; k < 15; k++) @@ -383,7 +383,7 @@ public static final String[] UPDATE_LIST_2 = { "alpha2", "bravo2", "charlie2", " String guid = GUID.generate(); ii.setStatus(guid, TransactionStatus.ACTIVE, null, null); - IndexWriter writer = ii.getDeltaIndexWriter(guid, new StandardAnalyzer()); + IndexWriter writer = ii.getDeltaIndexWriter(guid, new AlfrescoStandardAnalyser()); Document doc = new Document(); for (int k = 0; k < 15; k++) @@ -469,7 +469,7 @@ public static final String[] UPDATE_LIST_2 = { "alpha2", "bravo2", "charlie2", " String guid = GUID.generate(); ii.setStatus(guid, TransactionStatus.ACTIVE, null, null); - IndexWriter writer = ii.getDeltaIndexWriter(guid, new StandardAnalyzer()); + IndexWriter writer = ii.getDeltaIndexWriter(guid, new AlfrescoStandardAnalyser()); Document doc = new Document(); for (int k = 0; k < 15; k++) @@ -649,7 +649,7 @@ public static final String[] UPDATE_LIST_2 = { "alpha2", "bravo2", "charlie2", " String guid = GUID.generate(); ii.setStatus(guid, TransactionStatus.ACTIVE, null, null); - IndexWriter writer = ii.getDeltaIndexWriter(guid, new StandardAnalyzer()); + IndexWriter writer = ii.getDeltaIndexWriter(guid, new AlfrescoStandardAnalyser()); Document doc = new Document(); for (int k = 0; k < 15; k++) @@ -740,7 +740,7 @@ public static final String[] UPDATE_LIST_2 = { "alpha2", "bravo2", "charlie2", " String guid = GUID.generate(); ii.setStatus(guid, TransactionStatus.ACTIVE, null, null); - IndexWriter writer = ii.getDeltaIndexWriter(guid, new StandardAnalyzer()); + IndexWriter writer = ii.getDeltaIndexWriter(guid, new AlfrescoStandardAnalyser()); Document doc = new Document(); for (int k = 0; k < 15; k++) diff --git a/source/java/org/alfresco/repo/security/authentication/DefaultMutableAuthenticationDao.java b/source/java/org/alfresco/repo/security/authentication/DefaultMutableAuthenticationDao.java index 553c548ec2..c30669cc67 100644 --- a/source/java/org/alfresco/repo/security/authentication/DefaultMutableAuthenticationDao.java +++ b/source/java/org/alfresco/repo/security/authentication/DefaultMutableAuthenticationDao.java @@ -25,219 +25,359 @@ import org.alfresco.error.AlfrescoRuntimeException; import org.springframework.dao.DataAccessException; /** - * An authority DAO that has no implementation and should not be called. + * An authority DAO that has no implementation. + * + * By default it will throw an exception if any method is called. + * + * Any of the getter/setter methods can be enabled with a no action implementation. + * + * This can support deleting users via the UI for LDAP and NTLM. The Alfresco person object is deleted from the UI. + * The call to delete the user will return with no action. + * + * The following methods will always fail. + * + * getMD4HashedPassword(String userName) + * loadUserByUsername(String arg0) + * getSalt(UserDetails user) * * @author Andy Hind */ public class DefaultMutableAuthenticationDao implements MutableAuthenticationDao { - + private boolean allowCreateUser = false; + + private boolean allowUpdateUser = false; + + private boolean allowDeleteUser = false; + + private boolean allowSetEnabled = false; + + private boolean allowGetEnabled = false; + + private boolean allowSetAccountExpires = false; + + private boolean allowGetAccountHasExpired = false; + + private boolean allowSetCredentialsExpire = false; + + private boolean allowGetCredentialsExpire = false; + + private boolean allowGetCredentialsHaveExpired = false; + + private boolean allowSetAccountLocked = false; + + private boolean allowGetAccountLocked = false; + + private boolean allowSetAccountExpiryDate = false; + + private boolean allowGetAccountExpiryDate = false; + + private boolean allowSetCredentialsExpiryDate = false; + + private boolean allowGetCredentialsExpiryDate = false; /** * Create a user with the given userName and password * + * If enabled does nothing. + * * @param userName * @param rawPassword * @throws AuthenticationException */ public void createUser(String userName, char[] rawPassword) throws AuthenticationException { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowCreateUser) + { + throw new AlfrescoRuntimeException("Create User is not supported"); + } } - + /** * Update a user's password. * + * If enabled does nothing. + * * @param userName * @param rawPassword * @throws AuthenticationException */ public void updateUser(String userName, char[] rawPassword) throws AuthenticationException { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowUpdateUser) + { + throw new AlfrescoRuntimeException("Update user is not supported"); + } } - + /** * Delete a user. * + * If enabled does nothing. + * * @param userName * @throws AuthenticationException */ public void deleteUser(String userName) throws AuthenticationException { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowDeleteUser) + { + throw new AlfrescoRuntimeException("Delete user is not supported"); + } } - + /** * Check is a user exists. * + * If enabled returns true. + * * @param userName * @return */ public boolean userExists(String userName) { + // All users may exist return true; } - + /** * Enable/disable a user. * + * If enabled does nothing. + * * @param userName * @param enabled */ public void setEnabled(String userName, boolean enabled) { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowSetEnabled) + { + throw new AlfrescoRuntimeException("Set enabled is not supported"); + } } - + /** * Getter for user enabled * + * If enabled returns true. + * * @param userName * @return */ public boolean getEnabled(String userName) { - throw new AlfrescoRuntimeException("Not implemented"); - + if (!allowGetEnabled) + { + throw new AlfrescoRuntimeException("Get enabled is not supported"); + } + return true; } - + /** * Set if the account should expire * + * If enabled does nothing. + * * @param userName * @param expires */ public void setAccountExpires(String userName, boolean expires) { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowSetAccountExpires) + { + throw new AlfrescoRuntimeException("Set account expires is not supported"); + } } - + /** * Does the account expire? * + * If enabled returns false. + * * @param userName * @return */ - + public boolean getAccountExpires(String userName) { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowSetAccountExpires) + { + throw new AlfrescoRuntimeException("Get account expires is not supported"); + } + return false; } - + /** * Has the account expired? * + * If enabled returns false. + * * @param userName * @return */ public boolean getAccountHasExpired(String userName) { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowGetAccountHasExpired) + { + throw new AlfrescoRuntimeException("Get account has expired is not supported"); + } + return false; } - + /** * Set if the password expires. * + * If enabled does nothing. + * * @param userName * @param expires */ public void setCredentialsExpire(String userName, boolean expires) { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowSetCredentialsExpire) + { + throw new AlfrescoRuntimeException("Set credentials expire is not supported"); + } } - + /** * Do the credentials for the user expire? * + * If enabled returns false. + * * @param userName * @return */ public boolean getCredentialsExpire(String userName) { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowGetCredentialsExpire) + { + throw new AlfrescoRuntimeException("Get credentials expire is not supported"); + } + return false; } - + /** * Have the credentials for the user expired? * + * If enabled returns false. + * * @param userName * @return */ public boolean getCredentialsHaveExpired(String userName) { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowGetCredentialsHaveExpired) + { + throw new AlfrescoRuntimeException("Get credentials have expired is not supported"); + } + return false; } - + /** * Set if the account is locked. * + * If enabled does nothing. + * * @param userName * @param locked */ public void setLocked(String userName, boolean locked) { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowSetAccountLocked) + { + throw new AlfrescoRuntimeException("Set account locked is not supported"); + } } - + /** * Is the account locked? * + * If enabled returns false. + * * @param userName * @return */ public boolean getAccountlocked(String userName) { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowGetAccountLocked) + { + throw new AlfrescoRuntimeException("Get account locked is not supported"); + } + return false; } - + /** * Set the date on which the account expires * + * If enabled does nothing. + * * @param userName * @param exipryDate */ public void setAccountExpiryDate(String userName, Date exipryDate) { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowSetAccountExpiryDate) + { + throw new AlfrescoRuntimeException("Set account expiry date is not supported"); + } } - - /** + + /** * Get the date when this account expires. * + * If enabled returns null. + * * @param userName * @return */ public Date getAccountExpiryDate(String userName) { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowGetAccountExpiryDate) + { + throw new AlfrescoRuntimeException("Get account expiry date is not supported"); + } + return null; } - + /** * Set the date when credentials expire. * + * If enabled does nothing. + * * @param userName * @param exipryDate */ public void setCredentialsExpiryDate(String userName, Date exipryDate) { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowSetCredentialsExpiryDate) + { + throw new AlfrescoRuntimeException("Set credentials expiry date is not supported"); + } } - + /** * Get the date when the credentials/password expire. * + * If enabled returns null. + * * @param userName * @return */ public Date getCredentialsExpiryDate(String userName) { - throw new AlfrescoRuntimeException("Not implemented"); + if (!allowGetCredentialsExpiryDate) + { + throw new AlfrescoRuntimeException("Get credentials expiry date is not supported"); + } + return null; } - + /** * Get the MD4 password hash * + * Always throws an exception. + * * @param userName * @return */ @@ -249,7 +389,10 @@ public class DefaultMutableAuthenticationDao implements MutableAuthenticationDao /** * Return the user details for the specified user * - * @param user String + * Always throws an exception. + * + * @param user + * String * @return UserDetails * @exception UsernameNotFoundException * @exception DataAccessException @@ -262,11 +405,99 @@ public class DefaultMutableAuthenticationDao implements MutableAuthenticationDao /** * Return salt for user * - * @param user UserDetails + * Always throws an exception. + * + * @param user + * UserDetails * @return Object */ public Object getSalt(UserDetails user) { throw new AlfrescoRuntimeException("Not implemented"); } + + + // -------- // + // Bean IOC // + // -------- // + + public void setAllowCreateUser(boolean allowCreateUser) + { + this.allowCreateUser = allowCreateUser; + } + + public void setAllowDeleteUser(boolean allowDeleteUser) + { + this.allowDeleteUser = allowDeleteUser; + } + + public void setAllowGetAccountExpiryDate(boolean allowGetAccountExpiryDate) + { + this.allowGetAccountExpiryDate = allowGetAccountExpiryDate; + } + + public void setAllowGetAccountHasExpired(boolean allowGetAccountHasExpired) + { + this.allowGetAccountHasExpired = allowGetAccountHasExpired; + } + + public void setAllowGetAccountLocked(boolean allowGetAccountLocked) + { + this.allowGetAccountLocked = allowGetAccountLocked; + } + + public void setAllowGetCredentialsExpire(boolean allowGetCredentialsExpire) + { + this.allowGetCredentialsExpire = allowGetCredentialsExpire; + } + + public void setAllowGetCredentialsExpiryDate(boolean allowGetCredentialsExpiryDate) + { + this.allowGetCredentialsExpiryDate = allowGetCredentialsExpiryDate; + } + + public void setAllowGetCredentialsHaveExpired(boolean allowGetCredentialsHaveExpired) + { + this.allowGetCredentialsHaveExpired = allowGetCredentialsHaveExpired; + } + + public void setAllowGetEnabled(boolean allowGetEnabled) + { + this.allowGetEnabled = allowGetEnabled; + } + + public void setAllowSetAccountExpires(boolean allowSetAccountExpires) + { + this.allowSetAccountExpires = allowSetAccountExpires; + } + + public void setAllowSetAccountExpiryDate(boolean allowSetAccountExpiryDate) + { + this.allowSetAccountExpiryDate = allowSetAccountExpiryDate; + } + + public void setAllowSetAccountLocked(boolean allowSetAccountLocked) + { + this.allowSetAccountLocked = allowSetAccountLocked; + } + + public void setAllowSetCredentialsExpire(boolean allowSetCredentialsExpire) + { + this.allowSetCredentialsExpire = allowSetCredentialsExpire; + } + + public void setAllowSetCredentialsExpiryDate(boolean allowSetCredentialsExpiryDate) + { + this.allowSetCredentialsExpiryDate = allowSetCredentialsExpiryDate; + } + + public void setAllowSetEnabled(boolean allowSetEnabled) + { + this.allowSetEnabled = allowSetEnabled; + } + + public void setAllowUpdateUser(boolean allowUpdateUser) + { + this.allowUpdateUser = allowUpdateUser; + } } diff --git a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPGroupExportSource.java b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPGroupExportSource.java index 2f4b366cac..be0f3ad747 100644 --- a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPGroupExportSource.java +++ b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPGroupExportSource.java @@ -1,742 +1,790 @@ -/* - * Copyright (C) 2005-2006 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.security.authentication.ldap; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.Writer; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; - -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.Attribute; -import javax.naming.directory.Attributes; -import javax.naming.directory.InitialDirContext; -import javax.naming.directory.SearchControls; -import javax.naming.directory.SearchResult; -import javax.transaction.UserTransaction; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.importer.ExportSource; -import org.alfresco.repo.importer.ExportSourceImporterException; -import org.alfresco.repo.security.authority.AuthorityDAO; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.ApplicationContextHelper; -import org.alfresco.util.EqualsHelper; -import org.alfresco.util.GUID; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.dom4j.io.OutputFormat; -import org.dom4j.io.XMLWriter; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ApplicationContext; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.AttributesImpl; - -public class LDAPGroupExportSource implements ExportSource, InitializingBean -{ - private static Log s_logger = LogFactory.getLog(LDAPGroupExportSource.class); - - private String groupQuery = "(objectclass=groupOfNames)"; - - private String searchBase; - - private String groupIdAttributeName = "cn"; - - private String userIdAttributeName = "uid"; - - private String groupType = "groupOfNames"; - - private String personType = "inetOrgPerson"; - - private LDAPInitialDirContextFactory ldapInitialContextFactory; - - private NamespaceService namespaceService; - - private String memberAttribute = "member"; - - private boolean errorOnMissingMembers = false; - - private QName viewRef; - - private QName viewId; - - private QName viewAssociations; - - private QName childQName; - - private QName viewValueQName; - - private QName viewIdRef; - - private AuthorityDAO authorityDAO; - - public LDAPGroupExportSource() - { - super(); - } - - public void setGroupIdAttributeName(String groupIdAttributeName) - { - this.groupIdAttributeName = groupIdAttributeName; - } - - public void setGroupQuery(String groupQuery) - { - this.groupQuery = groupQuery; - } - - public void setGroupType(String groupType) - { - this.groupType = groupType; - } - - public void setLDAPInitialDirContextFactory(LDAPInitialDirContextFactory ldapInitialDirContextFactory) - { - this.ldapInitialContextFactory = ldapInitialDirContextFactory; - } - - public void setMemberAttribute(String memberAttribute) - { - this.memberAttribute = memberAttribute; - } - - public void setNamespaceService(NamespaceService namespaceService) - { - this.namespaceService = namespaceService; - } - - public void setPersonType(String personType) - { - this.personType = personType; - } - - public void setSearchBase(String searchBase) - { - this.searchBase = searchBase; - } - - public void setUserIdAttributeName(String userIdAttributeName) - { - this.userIdAttributeName = userIdAttributeName; - } - - public void setErrorOnMissingMembers(boolean errorOnMissingMembers) - { - this.errorOnMissingMembers = errorOnMissingMembers; - } - - public void setAuthorityDAO(AuthorityDAO authorityDAO) - { - this.authorityDAO = authorityDAO; - } - - public void generateExport(XMLWriter writer) - { - HashSet rootGroups = new HashSet(); - HashMap lookup = new HashMap(); - HashSet secondaryLinks = new HashSet(); - - buildGroupsAndRoots(rootGroups, lookup, secondaryLinks); - - buildXML(rootGroups, lookup, secondaryLinks, writer); - - } - - private void buildXML(HashSet rootGroups, HashMap lookup, - HashSet secondaryLinks, XMLWriter writer) - { - - Collection prefixes = namespaceService.getPrefixes(); - QName childQName = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "childName", namespaceService); - - try - { - AttributesImpl attrs = new AttributesImpl(); - attrs.addAttribute(NamespaceService.REPOSITORY_VIEW_1_0_URI, childQName.getLocalName(), childQName - .toPrefixString(), null, ContentModel.TYPE_PERSON.toPrefixString(namespaceService)); - - writer.startDocument(); - - for (String prefix : prefixes) - { - if (!prefix.equals("xml")) - { - String uri = namespaceService.getNamespaceURI(prefix); - writer.startPrefixMapping(prefix, uri); - } - } - - writer.startElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "view", - NamespaceService.REPOSITORY_VIEW_PREFIX + ":" + "view", new AttributesImpl()); - - // Create group structure - - for (Group group : rootGroups) - { - addRootGroup(lookup, group, writer); - } - - // Create secondary links. - - for (SecondaryLink sl : secondaryLinks) - { - addSecondarylink(lookup, sl, writer); - } - - for (String prefix : prefixes) - { - if (!prefix.equals("xml")) - { - writer.endPrefixMapping(prefix); - } - } - - writer.endElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "view", NamespaceService.REPOSITORY_VIEW_PREFIX - + ":" + "view"); - - writer.endDocument(); - } - catch (SAXException e) - { - throw new ExportSourceImporterException("Failed to create file for import.", e); - } - - } - - private void addSecondarylink(HashMap lookup, SecondaryLink sl, XMLWriter writer) - throws SAXException - { - - String fromId = lookup.get(sl.from).guid; - String toId = lookup.get(sl.to).guid; - - AttributesImpl attrs = new AttributesImpl(); - attrs.addAttribute(viewIdRef.getNamespaceURI(), viewIdRef.getLocalName(), viewIdRef.toPrefixString(), null, - fromId); - - writer.startElement(viewRef.getNamespaceURI(), viewRef.getLocalName(), - viewRef.toPrefixString(namespaceService), attrs); - - writer.startElement(viewAssociations.getNamespaceURI(), viewAssociations.getLocalName(), viewAssociations - .toPrefixString(namespaceService), new AttributesImpl()); - - writer.startElement(ContentModel.ASSOC_MEMBER.getNamespaceURI(), ContentModel.ASSOC_MEMBER.getLocalName(), - ContentModel.ASSOC_MEMBER.toPrefixString(namespaceService), new AttributesImpl()); - - AttributesImpl attrsRef = new AttributesImpl(); - attrsRef.addAttribute(viewIdRef.getNamespaceURI(), viewIdRef.getLocalName(), viewIdRef.toPrefixString(), null, - toId); - attrsRef.addAttribute(childQName.getNamespaceURI(), childQName.getLocalName(), childQName.toPrefixString(), - null, QName.createQName(ContentModel.USER_MODEL_URI, sl.to).toPrefixString(namespaceService)); - - writer.startElement(viewRef.getNamespaceURI(), viewRef.getLocalName(), - viewRef.toPrefixString(namespaceService), attrsRef); - - writer.endElement(viewRef.getNamespaceURI(), viewRef.getLocalName(), viewRef.toPrefixString(namespaceService)); - - writer.endElement(ContentModel.ASSOC_MEMBER.getNamespaceURI(), ContentModel.ASSOC_MEMBER.getLocalName(), - ContentModel.ASSOC_MEMBER.toPrefixString(namespaceService)); - - writer.endElement(viewAssociations.getNamespaceURI(), viewAssociations.getLocalName(), viewAssociations - .toPrefixString(namespaceService)); - - writer.endElement(viewRef.getNamespaceURI(), viewRef.getLocalName(), viewRef.toPrefixString(namespaceService)); - - } - - private void addRootGroup(HashMap lookup, Group group, XMLWriter writer) throws SAXException - { - QName nodeUUID = QName.createQName("sys:node-uuid", namespaceService); - - AttributesImpl attrs = new AttributesImpl(); - attrs.addAttribute(NamespaceService.REPOSITORY_VIEW_1_0_URI, childQName.getLocalName(), childQName - .toPrefixString(), null, QName.createQName(ContentModel.USER_MODEL_URI, group.gid).toPrefixString( - namespaceService)); - attrs.addAttribute(viewId.getNamespaceURI(), viewId.getLocalName(), viewId.toPrefixString(), null, group.guid); - - writer.startElement(ContentModel.TYPE_AUTHORITY_CONTAINER.getNamespaceURI(), - ContentModel.TYPE_AUTHORITY_CONTAINER.getLocalName(), ContentModel.TYPE_AUTHORITY_CONTAINER - .toPrefixString(namespaceService), attrs); - - if ((authorityDAO != null ) && authorityDAO.authorityExists(group.gid)) - { - NodeRef authNodeRef = authorityDAO.getAuthorityNodeRefOrNull(group.gid); - if (authNodeRef != null) - { - String uguid = authorityDAO.getAuthorityNodeRefOrNull(group.gid).getId(); - - writer.startElement(nodeUUID.getNamespaceURI(), nodeUUID.getLocalName(), nodeUUID - .toPrefixString(namespaceService), new AttributesImpl()); - - writer.characters(uguid.toCharArray(), 0, uguid.length()); - - writer.endElement(nodeUUID.getNamespaceURI(), nodeUUID.getLocalName(), nodeUUID - .toPrefixString(namespaceService)); - } - } - - writer.startElement(ContentModel.PROP_AUTHORITY_NAME.getNamespaceURI(), ContentModel.PROP_AUTHORITY_NAME - .getLocalName(), ContentModel.PROP_AUTHORITY_NAME.toPrefixString(namespaceService), - new AttributesImpl()); - - writer.characters(group.gid.toCharArray(), 0, group.gid.length()); - - writer.endElement(ContentModel.PROP_AUTHORITY_NAME.getNamespaceURI(), ContentModel.PROP_AUTHORITY_NAME - .getLocalName(), ContentModel.PROP_AUTHORITY_NAME.toPrefixString(namespaceService)); - - if (group.members.size() > 0) - { - writer.startElement(ContentModel.PROP_MEMBERS.getNamespaceURI(), ContentModel.PROP_MEMBERS.getLocalName(), - ContentModel.PROP_MEMBERS.toPrefixString(namespaceService), new AttributesImpl()); - - for (String member : group.members) - { - writer.startElement(viewValueQName.getNamespaceURI(), viewValueQName.getLocalName(), viewValueQName - .toPrefixString(namespaceService), new AttributesImpl()); - - writer.characters(member.toCharArray(), 0, member.length()); - - writer.endElement(viewValueQName.getNamespaceURI(), viewValueQName.getLocalName(), viewValueQName - .toPrefixString(namespaceService)); - } - - writer.endElement(ContentModel.PROP_MEMBERS.getNamespaceURI(), ContentModel.PROP_MEMBERS.getLocalName(), - ContentModel.PROP_MEMBERS.toPrefixString(namespaceService)); - } - - for (Group child : group.children) - { - addgroup(lookup, child, writer); - } - - if ((authorityDAO != null ) && authorityDAO.authorityExists(group.gid)) - { - NodeRef authNodeRef = authorityDAO.getAuthorityNodeRefOrNull(group.gid); - if (authNodeRef != null) - { - String uguid = authorityDAO.getAuthorityNodeRefOrNull(group.gid).getId(); - - writer.startElement(nodeUUID.getNamespaceURI(), nodeUUID.getLocalName(), nodeUUID - .toPrefixString(namespaceService), new AttributesImpl()); - - writer.characters(uguid.toCharArray(), 0, uguid.length()); - - writer.endElement(nodeUUID.getNamespaceURI(), nodeUUID.getLocalName(), nodeUUID - .toPrefixString(namespaceService)); - } - } - - writer.endElement(ContentModel.TYPE_AUTHORITY_CONTAINER.getNamespaceURI(), - ContentModel.TYPE_AUTHORITY_CONTAINER.getLocalName(), ContentModel.TYPE_AUTHORITY_CONTAINER - .toPrefixString(namespaceService)); - - } - - private void addgroup(HashMap lookup, Group group, XMLWriter writer) throws SAXException - { - AttributesImpl attrs = new AttributesImpl(); - - writer.startElement(ContentModel.ASSOC_MEMBER.getNamespaceURI(), ContentModel.ASSOC_MEMBER.getLocalName(), - ContentModel.ASSOC_MEMBER.toPrefixString(namespaceService), attrs); - - addRootGroup(lookup, group, writer); - - writer.endElement(ContentModel.ASSOC_MEMBER.getNamespaceURI(), ContentModel.ASSOC_MEMBER.getLocalName(), - ContentModel.ASSOC_MEMBER.toPrefixString(namespaceService)); - } - - private void buildGroupsAndRoots(HashSet rootGroups, HashMap lookup, - HashSet secondaryLinks) - { - InitialDirContext ctx = null; - try - { - ctx = ldapInitialContextFactory.getDefaultIntialDirContext(); - - SearchControls userSearchCtls = new SearchControls(); - userSearchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); - - NamingEnumeration searchResults = ctx.search(searchBase, groupQuery, userSearchCtls); - while (searchResults.hasMoreElements()) - { - SearchResult result = (SearchResult) searchResults.next(); - Attributes attributes = result.getAttributes(); - Attribute gidAttribute = attributes.get(groupIdAttributeName); - if (gidAttribute == null) - { - throw new ExportSourceImporterException( - "Group returned by group search does not have mandatory group id attribute " + attributes); - } - String gid = (String) gidAttribute.get(0); - - Group group = lookup.get(gid); - if (group == null) - { - group = new Group(gid); - lookup.put(group.gid, group); - rootGroups.add(group); - } - Attribute memAttribute = attributes.get(memberAttribute); - // check for null - if (memAttribute != null) - { - for (int i = 0; i < memAttribute.size(); i++) - { - String attribute = (String) memAttribute.get(i); - if (attribute != null) - { - group.distinguishedNames.add(attribute); - } - } - } - } - - if (s_logger.isDebugEnabled()) - { - s_logger.debug("Found " + lookup.size()); - } - - for (Group group : lookup.values()) - { - if (s_logger.isDebugEnabled()) - { - s_logger.debug("Linking " + group.gid); - } - for (String dn : group.distinguishedNames) - { - if (s_logger.isDebugEnabled()) - { - s_logger.debug("... " + dn); - } - String id; - Boolean isGroup = null; - - SearchControls memberSearchCtls = new SearchControls(); - memberSearchCtls.setSearchScope(SearchControls.OBJECT_SCOPE); - NamingEnumeration memberSearchResults; - try - { - memberSearchResults = ctx.search(dn, "(objectClass=*)", memberSearchCtls); - } - catch (NamingException e) - { - if (errorOnMissingMembers) - { - throw e; - } - s_logger.warn("Failed to resolve distinguished name: " + dn); - continue; - } - while (memberSearchResults.hasMoreElements()) - { - id = null; - - SearchResult result; - try - { - result = (SearchResult) memberSearchResults.next(); - } - catch (NamingException e) - { - if (errorOnMissingMembers) - { - throw e; - } - s_logger.warn("Failed to resolve distinguished name: " + dn); - continue; - } - Attributes attributes = result.getAttributes(); - Attribute objectclass = attributes.get("objectclass"); - if (objectclass == null) - { - throw new ExportSourceImporterException("Failed to find attribute objectclass for DN " + dn); - } - for (int i = 0; i < objectclass.size(); i++) - { - String testType; - try - { - testType = (String) objectclass.get(i); - } - catch (NamingException e) - { - if (errorOnMissingMembers) - { - throw e; - } - s_logger.warn("Failed to resolve object class attribute for distinguished name: " + dn); - continue; - } - if (testType.equals(groupType)) - { - isGroup = true; - try - { - Attribute groupIdAttribute = attributes.get(groupIdAttributeName); - if (groupIdAttribute == null) - { - throw new ExportSourceImporterException("Group missing group id attribute DN =" - + dn + " att = " + groupIdAttributeName); - } - id = (String) groupIdAttribute.get(0); - } - catch (NamingException e) - { - if (errorOnMissingMembers) - { - throw e; - } - s_logger.warn("Failed to resolve group identifier " - + groupIdAttributeName + " for distinguished name: " + dn); - id = "Unknown sub group"; - } - break; - } - else if (testType.equals(personType)) - { - isGroup = false; - try - { - Attribute userIdAttribute = attributes.get(userIdAttributeName); - if (userIdAttribute == null) - { - throw new ExportSourceImporterException("User missing user id attribute DN =" - + dn + " att = " + userIdAttributeName); - } - id = (String) userIdAttribute.get(0); - } - catch (NamingException e) - { - if (errorOnMissingMembers) - { - throw e; - } - s_logger.warn("Failed to resolve group identifier " - + userIdAttributeName + " for distinguished name: " + dn); - id = "Unknown member"; - } - break; - } - } - - if (id != null) - { - if (isGroup == null) - { - throw new ExportSourceImporterException("Type not recognised for DN" + dn); - } - else if (isGroup) - { - if (s_logger.isDebugEnabled()) - { - s_logger.debug("... is sub group"); - } - Group child = lookup.get("GROUP_" + id); - if (child == null) - { - throw new ExportSourceImporterException("Failed to find child group " + id); - } - if (rootGroups.contains(child)) - { - if (s_logger.isDebugEnabled()) - { - s_logger.debug("... Primary created from " - + group.gid + " to " + child.gid); - } - group.children.add(child); - rootGroups.remove(child); - } - else - { - if (s_logger.isDebugEnabled()) - { - s_logger.debug("... Secondary created from " - + group.gid + " to " + child.gid); - } - secondaryLinks.add(new SecondaryLink(group.gid, child.gid)); - } - } - else - { - if (s_logger.isDebugEnabled()) - { - s_logger.debug("... is member"); - } - group.members.add(id); - } - } - } - } - } - if (s_logger.isDebugEnabled()) - { - s_logger.debug("Top " + rootGroups.size()); - s_logger.debug("Secondary " + secondaryLinks.size()); - } - } - catch (NamingException e) - { - throw new ExportSourceImporterException("Failed to import people.", e); - } - finally - { - if (ctx != null) - { - try - { - ctx.close(); - } - catch (NamingException e) - { - throw new ExportSourceImporterException("Failed to import people.", e); - } - } - } - } - - private static class Group - { - String gid; - - String guid = GUID.generate(); - - HashSet children = new HashSet(); - - HashSet members = new HashSet(); - - HashSet distinguishedNames = new HashSet(); - - private Group(String gid) - { - this.gid = "GROUP_" + gid; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (!(o instanceof Group)) - { - return false; - } - Group g = (Group) o; - return this.gid.equals(g.gid); - } - - @Override - public int hashCode() - { - return gid.hashCode(); - } - } - - private static class SecondaryLink - { - String from; - - String to; - - private SecondaryLink(String from, String to) - { - this.from = from; - this.to = to; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (!(o instanceof Group)) - { - return false; - } - SecondaryLink l = (SecondaryLink) o; - return EqualsHelper.nullSafeEquals(this.from, l.from) && EqualsHelper.nullSafeEquals(this.to, l.to); - } - - @Override - public int hashCode() - { - int hashCode = 0; - if (from != null) - { - hashCode = hashCode * 37 + from.hashCode(); - } - if (to != null) - { - hashCode = hashCode * 37 + to.hashCode(); - } - return hashCode; - } - } - - public static void main(String[] args) throws Exception - { - ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); - ExportSource source = (ExportSource) ctx.getBean("ldapGroupExportSource"); - - TransactionService txs = (TransactionService) ctx.getBean("transactionComponent"); - UserTransaction tx = txs.getUserTransaction(); - tx.begin(); - - File file = new File(args[0]); - Writer writer = new BufferedWriter(new FileWriter(file)); - XMLWriter xmlWriter = createXMLExporter(writer); - source.generateExport(xmlWriter); - xmlWriter.close(); - - tx.commit(); - } - - private static XMLWriter createXMLExporter(Writer writer) - { - // Define output format - OutputFormat format = OutputFormat.createPrettyPrint(); - format.setNewLineAfterDeclaration(false); - format.setIndentSize(3); - format.setEncoding("UTF-8"); - - // Construct an XML Exporter - - XMLWriter xmlWriter = new XMLWriter(writer, format); - return xmlWriter; - } - - public void afterPropertiesSet() throws Exception - { - viewRef = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "reference", namespaceService); - viewId = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "id", namespaceService); - viewIdRef = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "idref", namespaceService); - viewAssociations = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "associations", namespaceService); - childQName = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "childName", namespaceService); - viewValueQName = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "value", namespaceService); - - } -} +/* + * Copyright (C) 2005-2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.security.authentication.ldap; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.Writer; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; + +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import javax.transaction.UserTransaction; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.importer.ExportSource; +import org.alfresco.repo.importer.ExportSourceImporterException; +import org.alfresco.repo.security.authority.AuthorityDAO; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.EqualsHelper; +import org.alfresco.util.GUID; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.XMLWriter; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +public class LDAPGroupExportSource implements ExportSource, InitializingBean +{ + private static Log s_logger = LogFactory.getLog(LDAPGroupExportSource.class); + + private String groupQuery = "(objectclass=groupOfNames)"; + + private String searchBase; + + private String groupIdAttributeName = "cn"; + + private String userIdAttributeName = "uid"; + + private String groupType = "groupOfNames"; + + private String personType = "inetOrgPerson"; + + private LDAPInitialDirContextFactory ldapInitialContextFactory; + + private NamespaceService namespaceService; + + private String memberAttribute = "member"; + + private boolean errorOnMissingMembers = false; + + private QName viewRef; + + private QName viewId; + + private QName viewAssociations; + + private QName childQName; + + private QName viewValueQName; + + private QName viewIdRef; + + private AuthorityDAO authorityDAO; + + private boolean errorOnMissingGID; + + private boolean errorOnMissingUID; + + public LDAPGroupExportSource() + { + super(); + } + + public void setGroupIdAttributeName(String groupIdAttributeName) + { + this.groupIdAttributeName = groupIdAttributeName; + } + + public void setGroupQuery(String groupQuery) + { + this.groupQuery = groupQuery; + } + + public void setGroupType(String groupType) + { + this.groupType = groupType; + } + + public void setLDAPInitialDirContextFactory(LDAPInitialDirContextFactory ldapInitialDirContextFactory) + { + this.ldapInitialContextFactory = ldapInitialDirContextFactory; + } + + public void setMemberAttribute(String memberAttribute) + { + this.memberAttribute = memberAttribute; + } + + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + public void setPersonType(String personType) + { + this.personType = personType; + } + + public void setSearchBase(String searchBase) + { + this.searchBase = searchBase; + } + + public void setUserIdAttributeName(String userIdAttributeName) + { + this.userIdAttributeName = userIdAttributeName; + } + + public void setErrorOnMissingMembers(boolean errorOnMissingMembers) + { + this.errorOnMissingMembers = errorOnMissingMembers; + } + + public void setErrorOnMissingGID(boolean errorOnMissingGID) + { + this.errorOnMissingGID = errorOnMissingGID; + } + + public void setErrorOnMissingUID(boolean errorOnMissingUID) + { + this.errorOnMissingUID = errorOnMissingUID; + } + + public void setAuthorityDAO(AuthorityDAO authorityDAO) + { + this.authorityDAO = authorityDAO; + } + + public void generateExport(XMLWriter writer) + { + HashSet rootGroups = new HashSet(); + HashMap lookup = new HashMap(); + HashSet secondaryLinks = new HashSet(); + + buildGroupsAndRoots(rootGroups, lookup, secondaryLinks); + + buildXML(rootGroups, lookup, secondaryLinks, writer); + + } + + private void buildXML(HashSet rootGroups, HashMap lookup, + HashSet secondaryLinks, XMLWriter writer) + { + + Collection prefixes = namespaceService.getPrefixes(); + QName childQName = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "childName", namespaceService); + + try + { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute(NamespaceService.REPOSITORY_VIEW_1_0_URI, childQName.getLocalName(), childQName + .toPrefixString(), null, ContentModel.TYPE_PERSON.toPrefixString(namespaceService)); + + writer.startDocument(); + + for (String prefix : prefixes) + { + if (!prefix.equals("xml")) + { + String uri = namespaceService.getNamespaceURI(prefix); + writer.startPrefixMapping(prefix, uri); + } + } + + writer.startElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "view", + NamespaceService.REPOSITORY_VIEW_PREFIX + ":" + "view", new AttributesImpl()); + + // Create group structure + + for (Group group : rootGroups) + { + addRootGroup(lookup, group, writer); + } + + // Create secondary links. + + for (SecondaryLink sl : secondaryLinks) + { + addSecondarylink(lookup, sl, writer); + } + + for (String prefix : prefixes) + { + if (!prefix.equals("xml")) + { + writer.endPrefixMapping(prefix); + } + } + + writer.endElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "view", NamespaceService.REPOSITORY_VIEW_PREFIX + + ":" + "view"); + + writer.endDocument(); + } + catch (SAXException e) + { + throw new ExportSourceImporterException("Failed to create file for import.", e); + } + + } + + private void addSecondarylink(HashMap lookup, SecondaryLink sl, XMLWriter writer) + throws SAXException + { + + String fromId = lookup.get(sl.from).guid; + String toId = lookup.get(sl.to).guid; + + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute(viewIdRef.getNamespaceURI(), viewIdRef.getLocalName(), viewIdRef.toPrefixString(), null, + fromId); + + writer.startElement(viewRef.getNamespaceURI(), viewRef.getLocalName(), + viewRef.toPrefixString(namespaceService), attrs); + + writer.startElement(viewAssociations.getNamespaceURI(), viewAssociations.getLocalName(), viewAssociations + .toPrefixString(namespaceService), new AttributesImpl()); + + writer.startElement(ContentModel.ASSOC_MEMBER.getNamespaceURI(), ContentModel.ASSOC_MEMBER.getLocalName(), + ContentModel.ASSOC_MEMBER.toPrefixString(namespaceService), new AttributesImpl()); + + AttributesImpl attrsRef = new AttributesImpl(); + attrsRef.addAttribute(viewIdRef.getNamespaceURI(), viewIdRef.getLocalName(), viewIdRef.toPrefixString(), null, + toId); + attrsRef.addAttribute(childQName.getNamespaceURI(), childQName.getLocalName(), childQName.toPrefixString(), + null, QName.createQName(ContentModel.USER_MODEL_URI, sl.to).toPrefixString(namespaceService)); + + writer.startElement(viewRef.getNamespaceURI(), viewRef.getLocalName(), + viewRef.toPrefixString(namespaceService), attrsRef); + + writer.endElement(viewRef.getNamespaceURI(), viewRef.getLocalName(), viewRef.toPrefixString(namespaceService)); + + writer.endElement(ContentModel.ASSOC_MEMBER.getNamespaceURI(), ContentModel.ASSOC_MEMBER.getLocalName(), + ContentModel.ASSOC_MEMBER.toPrefixString(namespaceService)); + + writer.endElement(viewAssociations.getNamespaceURI(), viewAssociations.getLocalName(), viewAssociations + .toPrefixString(namespaceService)); + + writer.endElement(viewRef.getNamespaceURI(), viewRef.getLocalName(), viewRef.toPrefixString(namespaceService)); + + } + + private void addRootGroup(HashMap lookup, Group group, XMLWriter writer) throws SAXException + { + QName nodeUUID = QName.createQName("sys:node-uuid", namespaceService); + + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute(NamespaceService.REPOSITORY_VIEW_1_0_URI, childQName.getLocalName(), childQName + .toPrefixString(), null, QName.createQName(ContentModel.USER_MODEL_URI, group.gid).toPrefixString( + namespaceService)); + attrs.addAttribute(viewId.getNamespaceURI(), viewId.getLocalName(), viewId.toPrefixString(), null, group.guid); + + writer.startElement(ContentModel.TYPE_AUTHORITY_CONTAINER.getNamespaceURI(), + ContentModel.TYPE_AUTHORITY_CONTAINER.getLocalName(), ContentModel.TYPE_AUTHORITY_CONTAINER + .toPrefixString(namespaceService), attrs); + + if ((authorityDAO != null) && authorityDAO.authorityExists(group.gid)) + { + NodeRef authNodeRef = authorityDAO.getAuthorityNodeRefOrNull(group.gid); + if (authNodeRef != null) + { + String uguid = authorityDAO.getAuthorityNodeRefOrNull(group.gid).getId(); + + writer.startElement(nodeUUID.getNamespaceURI(), nodeUUID.getLocalName(), nodeUUID + .toPrefixString(namespaceService), new AttributesImpl()); + + writer.characters(uguid.toCharArray(), 0, uguid.length()); + + writer.endElement(nodeUUID.getNamespaceURI(), nodeUUID.getLocalName(), nodeUUID + .toPrefixString(namespaceService)); + } + } + + writer.startElement(ContentModel.PROP_AUTHORITY_NAME.getNamespaceURI(), ContentModel.PROP_AUTHORITY_NAME + .getLocalName(), ContentModel.PROP_AUTHORITY_NAME.toPrefixString(namespaceService), + new AttributesImpl()); + + writer.characters(group.gid.toCharArray(), 0, group.gid.length()); + + writer.endElement(ContentModel.PROP_AUTHORITY_NAME.getNamespaceURI(), ContentModel.PROP_AUTHORITY_NAME + .getLocalName(), ContentModel.PROP_AUTHORITY_NAME.toPrefixString(namespaceService)); + + if (group.members.size() > 0) + { + writer.startElement(ContentModel.PROP_MEMBERS.getNamespaceURI(), ContentModel.PROP_MEMBERS.getLocalName(), + ContentModel.PROP_MEMBERS.toPrefixString(namespaceService), new AttributesImpl()); + + for (String member : group.members) + { + writer.startElement(viewValueQName.getNamespaceURI(), viewValueQName.getLocalName(), viewValueQName + .toPrefixString(namespaceService), new AttributesImpl()); + + writer.characters(member.toCharArray(), 0, member.length()); + + writer.endElement(viewValueQName.getNamespaceURI(), viewValueQName.getLocalName(), viewValueQName + .toPrefixString(namespaceService)); + } + + writer.endElement(ContentModel.PROP_MEMBERS.getNamespaceURI(), ContentModel.PROP_MEMBERS.getLocalName(), + ContentModel.PROP_MEMBERS.toPrefixString(namespaceService)); + } + + for (Group child : group.children) + { + addgroup(lookup, child, writer); + } + + writer.endElement(ContentModel.TYPE_AUTHORITY_CONTAINER.getNamespaceURI(), + ContentModel.TYPE_AUTHORITY_CONTAINER.getLocalName(), ContentModel.TYPE_AUTHORITY_CONTAINER + .toPrefixString(namespaceService)); + + } + + private void addgroup(HashMap lookup, Group group, XMLWriter writer) throws SAXException + { + AttributesImpl attrs = new AttributesImpl(); + + writer.startElement(ContentModel.ASSOC_MEMBER.getNamespaceURI(), ContentModel.ASSOC_MEMBER.getLocalName(), + ContentModel.ASSOC_MEMBER.toPrefixString(namespaceService), attrs); + + addRootGroup(lookup, group, writer); + + writer.endElement(ContentModel.ASSOC_MEMBER.getNamespaceURI(), ContentModel.ASSOC_MEMBER.getLocalName(), + ContentModel.ASSOC_MEMBER.toPrefixString(namespaceService)); + } + + private void buildGroupsAndRoots(HashSet rootGroups, HashMap lookup, + HashSet secondaryLinks) + { + InitialDirContext ctx = null; + try + { + ctx = ldapInitialContextFactory.getDefaultIntialDirContext(); + + SearchControls userSearchCtls = new SearchControls(); + userSearchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); + + NamingEnumeration searchResults = ctx.search(searchBase, groupQuery, userSearchCtls); + while (searchResults.hasMoreElements()) + { + SearchResult result = (SearchResult) searchResults.next(); + Attributes attributes = result.getAttributes(); + Attribute gidAttribute = attributes.get(groupIdAttributeName); + if (gidAttribute == null) + { + if (errorOnMissingGID) + { + throw new ExportSourceImporterException( + "Group returned by group search does not have mandatory group id attribute " + + attributes); + } + else + { + s_logger.warn("Missing GID on " + attributes); + continue; + } + } + String gid = (String) gidAttribute.get(0); + + Group group = lookup.get(gid); + if (group == null) + { + group = new Group(gid); + lookup.put(group.gid, group); + rootGroups.add(group); + } + Attribute memAttribute = attributes.get(memberAttribute); + // check for null + if (memAttribute != null) + { + for (int i = 0; i < memAttribute.size(); i++) + { + String attribute = (String) memAttribute.get(i); + if (attribute != null) + { + group.distinguishedNames.add(attribute); + } + } + } + } + + if (s_logger.isDebugEnabled()) + { + s_logger.debug("Found " + lookup.size()); + } + + for (Group group : lookup.values()) + { + if (s_logger.isDebugEnabled()) + { + s_logger.debug("Linking " + group.gid); + } + for (String dn : group.distinguishedNames) + { + if (s_logger.isDebugEnabled()) + { + s_logger.debug("... " + dn); + } + String id; + Boolean isGroup = null; + + SearchControls memberSearchCtls = new SearchControls(); + memberSearchCtls.setSearchScope(SearchControls.OBJECT_SCOPE); + NamingEnumeration memberSearchResults; + try + { + memberSearchResults = ctx.search(dn, "(objectClass=*)", memberSearchCtls); + } + catch (NamingException e) + { + if (errorOnMissingMembers) + { + throw e; + } + s_logger.warn("Failed to resolve distinguished name: " + dn); + continue; + } + while (memberSearchResults.hasMoreElements()) + { + id = null; + + SearchResult result; + try + { + result = (SearchResult) memberSearchResults.next(); + } + catch (NamingException e) + { + if (errorOnMissingMembers) + { + throw e; + } + s_logger.warn("Failed to resolve distinguished name: " + dn); + continue; + } + Attributes attributes = result.getAttributes(); + Attribute objectclass = attributes.get("objectclass"); + if (objectclass == null) + { + if (errorOnMissingMembers) + { + throw new ExportSourceImporterException("Failed to find attribute objectclass for DN " + + dn); + } + else + { + continue; + } + } + for (int i = 0; i < objectclass.size(); i++) + { + String testType; + try + { + testType = (String) objectclass.get(i); + } + catch (NamingException e) + { + if (errorOnMissingMembers) + { + throw e; + } + s_logger.warn("Failed to resolve object class attribute for distinguished name: " + dn); + continue; + } + if (testType.equals(groupType)) + { + isGroup = true; + try + { + Attribute groupIdAttribute = attributes.get(groupIdAttributeName); + if (groupIdAttribute == null) + { + if (errorOnMissingGID) + { + throw new ExportSourceImporterException( + "Group missing group id attribute DN =" + + dn + " att = " + groupIdAttributeName); + } + else + { + s_logger.warn("Group missing group id attribute DN =" + + dn + " att = " + groupIdAttributeName); + continue; + } + } + id = (String) groupIdAttribute.get(0); + } + catch (NamingException e) + { + if (errorOnMissingMembers) + { + throw e; + } + s_logger.warn("Failed to resolve group identifier " + + groupIdAttributeName + " for distinguished name: " + dn); + id = "Unknown sub group"; + } + break; + } + else if (testType.equals(personType)) + { + isGroup = false; + try + { + Attribute userIdAttribute = attributes.get(userIdAttributeName); + if (userIdAttribute == null) + { + if (errorOnMissingUID) + { + throw new ExportSourceImporterException( + "User missing user id attribute DN =" + + dn + " att = " + userIdAttributeName); + } + else + { + s_logger.warn("User missing user id attribute DN =" + + dn + " att = " + userIdAttributeName); + continue; + } + } + id = (String) userIdAttribute.get(0); + } + catch (NamingException e) + { + if (errorOnMissingMembers) + { + throw e; + } + s_logger.warn("Failed to resolve group identifier " + + userIdAttributeName + " for distinguished name: " + dn); + id = "Unknown member"; + } + break; + } + } + + if (id != null) + { + if (isGroup == null) + { + if (errorOnMissingMembers) + { + throw new ExportSourceImporterException("Type not recognised for DN" + dn); + } + else + { + continue; + } + } + else if (isGroup) + { + if (s_logger.isDebugEnabled()) + { + s_logger.debug("... is sub group"); + } + Group child = lookup.get("GROUP_" + id); + if (child == null) + { + if (errorOnMissingMembers) + { + throw new ExportSourceImporterException("Failed to find child group " + id); + } + else + { + continue; + } + } + if (rootGroups.contains(child)) + { + if (s_logger.isDebugEnabled()) + { + s_logger.debug("... Primary created from " + + group.gid + " to " + child.gid); + } + group.children.add(child); + rootGroups.remove(child); + } + else + { + if (s_logger.isDebugEnabled()) + { + s_logger.debug("... Secondary created from " + + group.gid + " to " + child.gid); + } + secondaryLinks.add(new SecondaryLink(group.gid, child.gid)); + } + } + else + { + if (s_logger.isDebugEnabled()) + { + s_logger.debug("... is member"); + } + group.members.add(id); + } + } + } + } + } + if (s_logger.isDebugEnabled()) + { + s_logger.debug("Top " + rootGroups.size()); + s_logger.debug("Secondary " + secondaryLinks.size()); + } + } + catch (NamingException e) + { + throw new ExportSourceImporterException("Failed to import people.", e); + } + finally + { + if (ctx != null) + { + try + { + ctx.close(); + } + catch (NamingException e) + { + throw new ExportSourceImporterException("Failed to import people.", e); + } + } + } + } + + private static class Group + { + String gid; + + String guid = GUID.generate(); + + HashSet children = new HashSet(); + + HashSet members = new HashSet(); + + HashSet distinguishedNames = new HashSet(); + + private Group(String gid) + { + this.gid = "GROUP_" + gid; + } + + @Override + public boolean equals(Object o) + { + if (this == o) + { + return true; + } + if (!(o instanceof Group)) + { + return false; + } + Group g = (Group) o; + return this.gid.equals(g.gid); + } + + @Override + public int hashCode() + { + return gid.hashCode(); + } + } + + private static class SecondaryLink + { + String from; + + String to; + + private SecondaryLink(String from, String to) + { + this.from = from; + this.to = to; + } + + @Override + public boolean equals(Object o) + { + if (this == o) + { + return true; + } + if (!(o instanceof Group)) + { + return false; + } + SecondaryLink l = (SecondaryLink) o; + return EqualsHelper.nullSafeEquals(this.from, l.from) && EqualsHelper.nullSafeEquals(this.to, l.to); + } + + @Override + public int hashCode() + { + int hashCode = 0; + if (from != null) + { + hashCode = hashCode * 37 + from.hashCode(); + } + if (to != null) + { + hashCode = hashCode * 37 + to.hashCode(); + } + return hashCode; + } + } + + public static void main(String[] args) throws Exception + { + ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + ExportSource source = (ExportSource) ctx.getBean("ldapGroupExportSource"); + + TransactionService txs = (TransactionService) ctx.getBean("transactionComponent"); + UserTransaction tx = txs.getUserTransaction(); + tx.begin(); + + File file = new File(args[0]); + Writer writer = new BufferedWriter(new FileWriter(file)); + XMLWriter xmlWriter = createXMLExporter(writer); + source.generateExport(xmlWriter); + xmlWriter.close(); + + tx.commit(); + } + + private static XMLWriter createXMLExporter(Writer writer) + { + // Define output format + OutputFormat format = OutputFormat.createPrettyPrint(); + format.setNewLineAfterDeclaration(false); + format.setIndentSize(3); + format.setEncoding("UTF-8"); + + // Construct an XML Exporter + + XMLWriter xmlWriter = new XMLWriter(writer, format); + return xmlWriter; + } + + public void afterPropertiesSet() throws Exception + { + viewRef = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "reference", namespaceService); + viewId = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "id", namespaceService); + viewIdRef = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "idref", namespaceService); + viewAssociations = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "associations", namespaceService); + childQName = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "childName", namespaceService); + viewValueQName = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "value", namespaceService); + + } +} diff --git a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java index af6c4612de..302ea2f178 100644 --- a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java +++ b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPInitialDirContextFactoryImpl.java @@ -30,17 +30,22 @@ import javax.naming.directory.InitialDirContext; import org.alfresco.repo.security.authentication.AuthenticationException; import org.alfresco.util.ApplicationContextHelper; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; -public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFactory +public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFactory, InitializingBean { + private static final Log logger = LogFactory.getLog(LDAPInitialDirContextFactoryImpl.class); + private Map initialDirContextEnvironment = Collections. emptyMap(); static { System.setProperty("javax.security.auth.useSubjectCredentialsOnly", "false"); } - + public LDAPInitialDirContextFactoryImpl() { super(); @@ -87,11 +92,22 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa { throw new AuthenticationException("Null user name provided."); } + + if (principal.length() == 0) + { + throw new AuthenticationException("Empty user name provided."); + } if (credentials == null) { throw new AuthenticationException("No credentials provided."); } + + if (credentials.length() == 0) + { + throw new AuthenticationException("Empty credentials provided."); + } + Hashtable env = new Hashtable(initialDirContextEnvironment.size()); env.putAll(initialDirContextEnvironment); env.put(Context.SECURITY_PRINCIPAL, principal); @@ -187,4 +203,108 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa } + public void afterPropertiesSet() throws Exception + { + // Check Anonymous bind + + Hashtable env = new Hashtable(initialDirContextEnvironment.size()); + env.putAll(initialDirContextEnvironment); + env.remove(Context.SECURITY_PRINCIPAL); + env.remove(Context.SECURITY_CREDENTIALS); + try + { + new InitialDirContext(env); + + logger.warn("LDAP server supports anonymous bind " + env.get(Context.PROVIDER_URL)); + } + catch (javax.naming.AuthenticationException ax) + { + + } + catch (NamingException nx) + { + throw new AuthenticationException("Unable to connect to LDAP Server; check LDAP configuration", nx); + } + + // Simple DN and password + + env = new Hashtable(initialDirContextEnvironment.size()); + env.putAll(initialDirContextEnvironment); + env.put(Context.SECURITY_PRINCIPAL, "daftAsABrush"); + env.put(Context.SECURITY_CREDENTIALS, "daftAsABrush"); + try + { + + new InitialDirContext(env); + + throw new AuthenticationException( + "The ldap server at " + + env.get(Context.PROVIDER_URL) + + " falls back to use anonymous bind if invalid security credentials are presented. This is not supported."); + } + catch (javax.naming.AuthenticationException ax) + { + logger.info("LDAP server does not fall back to anonymous bind for a string uid and password at " + env.get(Context.PROVIDER_URL)); + } + catch (NamingException nx) + { + logger.info("LDAP server does not support simple string user ids and invalid credentials at "+ env.get(Context.PROVIDER_URL)); + } + + // DN and password + + env = new Hashtable(initialDirContextEnvironment.size()); + env.putAll(initialDirContextEnvironment); + env.put(Context.SECURITY_PRINCIPAL, "cn=daftAsABrush,dc=woof"); + env.put(Context.SECURITY_CREDENTIALS, "daftAsABrush"); + try + { + + new InitialDirContext(env); + + throw new AuthenticationException( + "The ldap server at " + + env.get(Context.PROVIDER_URL) + + " falls back to use anonymous bind if invalid security credentials are presented. This is not supported."); + } + catch (javax.naming.AuthenticationException ax) + { + logger.info("LDAP server does not fall back to anonymous bind for a simple dn and password at " + env.get(Context.PROVIDER_URL)); + } + catch (NamingException nx) + { + logger.info("LDAP server does not support simple DN and invalid password at "+ env.get(Context.PROVIDER_URL)); + } + + // Check more if we have a real principal we expect to work + + env = new Hashtable(initialDirContextEnvironment.size()); + env.putAll(initialDirContextEnvironment); + if(env.get(Context.SECURITY_PRINCIPAL) != null) + { + // Correct principal invalid password + + env = new Hashtable(initialDirContextEnvironment.size()); + env.putAll(initialDirContextEnvironment); + env.put(Context.SECURITY_CREDENTIALS, "sdasdasdasdasd123123123"); + try + { + + new InitialDirContext(env); + + throw new AuthenticationException( + "The ldap server at " + + env.get(Context.PROVIDER_URL) + + " falls back to use anonymous bind for a known principal if invalid security credentials are presented. This is not supported."); + } + catch (javax.naming.AuthenticationException ax) + { + logger.info("LDAP server does not fall back to anonymous bind for known principal and invalid credentials at " + env.get(Context.PROVIDER_URL)); + } + catch (NamingException nx) + { + // already donw + } + } + } } diff --git a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java index 422871d5ae..c9b929183f 100644 --- a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java +++ b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java @@ -1,334 +1,342 @@ -/* - * Copyright (C) 2005-2006 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.security.authentication.ldap; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.Writer; -import java.util.Collection; -import java.util.Map; - -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.Attribute; -import javax.naming.directory.Attributes; -import javax.naming.directory.InitialDirContext; -import javax.naming.directory.SearchControls; -import javax.naming.directory.SearchResult; -import javax.transaction.UserTransaction; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.importer.ExportSource; -import org.alfresco.repo.importer.ExportSourceImporterException; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.ApplicationContextHelper; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.dom4j.io.OutputFormat; -import org.dom4j.io.XMLWriter; -import org.springframework.context.ApplicationContext; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.AttributesImpl; - -public class LDAPPersonExportSource implements ExportSource -{ - private static Log s_logger = LogFactory.getLog(LDAPPersonExportSource.class); - - private String personQuery = "(objectclass=inetOrgPerson)"; - - private String searchBase; - - private String userIdAttributeName; - - private LDAPInitialDirContextFactory ldapInitialContextFactory; - - private PersonService personService; - - private Map attributeMapping; - - private NamespaceService namespaceService; - - private String defaultHomeFolder; - - public LDAPPersonExportSource() - { - super(); - } - - public void setPersonQuery(String personQuery) - { - this.personQuery = personQuery; - } - - public void setSearchBase(String searchBase) - { - this.searchBase = searchBase; - } - - public void setUserIdAttributeName(String userIdAttributeName) - { - this.userIdAttributeName = userIdAttributeName; - } - - public void setLDAPInitialDirContextFactory(LDAPInitialDirContextFactory ldapInitialDirContextFactory) - { - this.ldapInitialContextFactory = ldapInitialDirContextFactory; - } - - public void setPersonService(PersonService personService) - { - this.personService = personService; - } - - public void setDefaultHomeFolder(String defaultHomeFolder) - { - this.defaultHomeFolder = defaultHomeFolder; - } - - public void setNamespaceService(NamespaceService namespaceService) - { - this.namespaceService = namespaceService; - } - - public void setAttributeMapping(Map attributeMapping) - { - this.attributeMapping = attributeMapping; - } - - public void generateExport(XMLWriter writer) - { - QName nodeUUID = QName.createQName("sys:node-uuid", namespaceService); - - Collection prefixes = namespaceService.getPrefixes(); - QName childQName = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "childName", namespaceService); - - try - { - AttributesImpl attrs = new AttributesImpl(); - attrs.addAttribute(NamespaceService.REPOSITORY_VIEW_1_0_URI, childQName.getLocalName(), childQName - .toPrefixString(), null, ContentModel.TYPE_PERSON.toPrefixString(namespaceService)); - - writer.startDocument(); - - for (String prefix : prefixes) - { - if (!prefix.equals("xml")) - { - String uri = namespaceService.getNamespaceURI(prefix); - writer.startPrefixMapping(prefix, uri); - } - } - - writer.startElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "view", - NamespaceService.REPOSITORY_VIEW_PREFIX + ":" + "view", new AttributesImpl()); - - InitialDirContext ctx = null; - try - { - ctx = ldapInitialContextFactory.getDefaultIntialDirContext(); - - // Authentication has been successful. - // Set the current user, they are now authenticated. - - SearchControls userSearchCtls = new SearchControls(); - userSearchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); - - userSearchCtls.setCountLimit(Integer.MAX_VALUE); - - NamingEnumeration searchResults = ctx.search(searchBase, personQuery, userSearchCtls); - while (searchResults.hasMoreElements()) - { - SearchResult result = (SearchResult) searchResults.next(); - Attributes attributes = result.getAttributes(); - Attribute uidAttribute = attributes.get(userIdAttributeName); - if (uidAttribute == null) - { - throw new ExportSourceImporterException( - "User returned by user search does not have mandatory user id attribute " + attributes); - } - String uid = (String) uidAttribute.get(0); - - if (s_logger.isDebugEnabled()) - { - s_logger.debug("Adding user for " + uid); - } - - - writer.startElement(ContentModel.TYPE_PERSON.getNamespaceURI(), ContentModel.TYPE_PERSON - .getLocalName(), ContentModel.TYPE_PERSON.toPrefixString(namespaceService), attrs); - - // permissions - - // owner - - writer.startElement(ContentModel.ASPECT_OWNABLE.getNamespaceURI(), ContentModel.ASPECT_OWNABLE - .getLocalName(), ContentModel.ASPECT_OWNABLE.toPrefixString(namespaceService), - new AttributesImpl()); - - writer.endElement(ContentModel.ASPECT_OWNABLE.getNamespaceURI(), ContentModel.ASPECT_OWNABLE - .getLocalName(), ContentModel.ASPECT_OWNABLE.toPrefixString(namespaceService)); - - writer.startElement(ContentModel.PROP_OWNER.getNamespaceURI(), ContentModel.PROP_OWNER - .getLocalName(), ContentModel.PROP_OWNER.toPrefixString(namespaceService), - new AttributesImpl()); - - writer.characters(uid.toCharArray(), 0, uid.length()); - - writer.endElement(ContentModel.PROP_OWNER.getNamespaceURI(), - ContentModel.PROP_OWNER.getLocalName(), ContentModel.PROP_OWNER - .toPrefixString(namespaceService)); - - for (String key : attributeMapping.keySet()) - { - QName keyQName = QName.createQName(key, namespaceService); - - writer.startElement(keyQName.getNamespaceURI(), keyQName.getLocalName(), keyQName - .toPrefixString(namespaceService), new AttributesImpl()); - - // cater for null - String attributeName = attributeMapping.get(key); - if (attributeName != null) - { - Attribute attribute = attributes.get(attributeName); - if (attribute != null) - { - String value = (String) attribute.get(0); - if (value != null) - { - writer.characters(value.toCharArray(), 0, value.length()); - } - } - } - - writer.endElement(keyQName.getNamespaceURI(), keyQName.getLocalName(), keyQName - .toPrefixString(namespaceService)); - } - - // Default home folder - - if (!(attributeMapping.keySet().contains(ContentModel.PROP_HOMEFOLDER.toString()) || attributeMapping - .keySet().contains(ContentModel.PROP_HOMEFOLDER.toPrefixString(namespaceService)))) - { - // Only if we are creating the person for the first time - if (!personService.personExists(uid)) - { - writer.startElement(ContentModel.PROP_HOMEFOLDER.getNamespaceURI(), - ContentModel.PROP_HOMEFOLDER.getLocalName(), ContentModel.PROP_HOMEFOLDER - .toPrefixString(namespaceService), new AttributesImpl()); - - if (defaultHomeFolder != null) - { - writer.characters(defaultHomeFolder.toCharArray(), 0, defaultHomeFolder.length()); - } - - writer.endElement(ContentModel.PROP_HOMEFOLDER.getNamespaceURI(), - ContentModel.PROP_HOMEFOLDER.getLocalName(), ContentModel.PROP_HOMEFOLDER - .toPrefixString(namespaceService)); - } - } - - if (personService.personExists(uid)) - { - String uguid = personService.getPerson(uid).getId(); - - writer.startElement(nodeUUID.getNamespaceURI(), nodeUUID.getLocalName(), nodeUUID - .toPrefixString(namespaceService), new AttributesImpl()); - - writer.characters(uguid.toCharArray(), 0, uguid.length()); - - writer.endElement(nodeUUID.getNamespaceURI(), nodeUUID.getLocalName(), nodeUUID - .toPrefixString(namespaceService)); - } - writer.endElement(ContentModel.TYPE_PERSON.getNamespaceURI(), ContentModel.TYPE_PERSON - .getLocalName(), ContentModel.TYPE_PERSON.toPrefixString(namespaceService)); - - } - - } - catch (NamingException e) - { - throw new ExportSourceImporterException("Failed to import people.", e); - } - finally - { - if (ctx != null) - { - try - { - ctx.close(); - } - catch (NamingException e) - { - throw new ExportSourceImporterException("Failed to import people.", e); - } - } - } - - for (String prefix : prefixes) - { - if (!prefix.equals("xml")) - { - writer.endPrefixMapping(prefix); - } - } - - writer.endElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "view", NamespaceService.REPOSITORY_VIEW_PREFIX - + ":" + "view"); - - writer.endDocument(); - } - catch (SAXException e) - { - throw new ExportSourceImporterException("Failed to create file for import.", e); - } - } - - public static void main(String[] args) throws Exception - { - ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); - ExportSource source = (ExportSource) ctx.getBean("ldapPeopleExportSource"); - TransactionService txs = (TransactionService) ctx.getBean("transactionComponent"); - UserTransaction tx = txs.getUserTransaction(); - tx.begin(); - - File file = new File(args[0]); - Writer writer = new BufferedWriter(new FileWriter(file)); - XMLWriter xmlWriter = createXMLExporter(writer); - source.generateExport(xmlWriter); - xmlWriter.close(); - - tx.commit(); - } - - private static XMLWriter createXMLExporter(Writer writer) - { - // Define output format - OutputFormat format = OutputFormat.createPrettyPrint(); - format.setNewLineAfterDeclaration(false); - format.setIndentSize(3); - format.setEncoding("UTF-8"); - - // Construct an XML Exporter - - XMLWriter xmlWriter = new XMLWriter(writer, format); - return xmlWriter; - } -} \ No newline at end of file +/* + * Copyright (C) 2005-2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.security.authentication.ldap; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.Writer; +import java.util.Collection; +import java.util.Map; + +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import javax.transaction.UserTransaction; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.importer.ExportSource; +import org.alfresco.repo.importer.ExportSourceImporterException; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.XMLWriter; +import org.springframework.context.ApplicationContext; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +public class LDAPPersonExportSource implements ExportSource +{ + private static Log s_logger = LogFactory.getLog(LDAPPersonExportSource.class); + + private String personQuery = "(objectclass=inetOrgPerson)"; + + private String searchBase; + + private String userIdAttributeName; + + private LDAPInitialDirContextFactory ldapInitialContextFactory; + + private PersonService personService; + + private Map attributeMapping; + + private NamespaceService namespaceService; + + private Map attributeDefaults; + + private boolean errorOnMissingUID; + + public LDAPPersonExportSource() + { + super(); + } + + public void setPersonQuery(String personQuery) + { + this.personQuery = personQuery; + } + + public void setSearchBase(String searchBase) + { + this.searchBase = searchBase; + } + + public void setUserIdAttributeName(String userIdAttributeName) + { + this.userIdAttributeName = userIdAttributeName; + } + + public void setLDAPInitialDirContextFactory(LDAPInitialDirContextFactory ldapInitialDirContextFactory) + { + this.ldapInitialContextFactory = ldapInitialDirContextFactory; + } + + public void setPersonService(PersonService personService) + { + this.personService = personService; + } + + public void setAttributeDefaults(Map attributeDefaults) + { + this.attributeDefaults = attributeDefaults; + } + + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + public void setAttributeMapping(Map attributeMapping) + { + this.attributeMapping = attributeMapping; + } + + public void setErrorOnMissingUID(boolean errorOnMissingUID) + { + this.errorOnMissingUID = errorOnMissingUID; + } + + public void generateExport(XMLWriter writer) + { + QName nodeUUID = QName.createQName("sys:node-uuid", namespaceService); + + Collection prefixes = namespaceService.getPrefixes(); + QName childQName = QName.createQName(NamespaceService.REPOSITORY_VIEW_PREFIX, "childName", namespaceService); + + try + { + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute(NamespaceService.REPOSITORY_VIEW_1_0_URI, childQName.getLocalName(), childQName + .toPrefixString(), null, ContentModel.TYPE_PERSON.toPrefixString(namespaceService)); + + writer.startDocument(); + + for (String prefix : prefixes) + { + if (!prefix.equals("xml")) + { + String uri = namespaceService.getNamespaceURI(prefix); + writer.startPrefixMapping(prefix, uri); + } + } + + writer.startElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "view", + NamespaceService.REPOSITORY_VIEW_PREFIX + ":" + "view", new AttributesImpl()); + + InitialDirContext ctx = null; + try + { + ctx = ldapInitialContextFactory.getDefaultIntialDirContext(); + + // Authentication has been successful. + // Set the current user, they are now authenticated. + + SearchControls userSearchCtls = new SearchControls(); + userSearchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); + + userSearchCtls.setCountLimit(Integer.MAX_VALUE); + + NamingEnumeration searchResults = ctx.search(searchBase, personQuery, userSearchCtls); + while (searchResults.hasMoreElements()) + { + SearchResult result = (SearchResult) searchResults.next(); + Attributes attributes = result.getAttributes(); + Attribute uidAttribute = attributes.get(userIdAttributeName); + if (uidAttribute == null) + { + if(errorOnMissingUID) + { + throw new ExportSourceImporterException( + "User returned by user search does not have mandatory user id attribute " + attributes); + } + else + { + s_logger.warn("User returned by user search does not have mandatory user id attribute " + attributes); + continue; + } + } + String uid = (String) uidAttribute.get(0); + + if (s_logger.isDebugEnabled()) + { + s_logger.debug("Adding user for " + uid); + } + + + writer.startElement(ContentModel.TYPE_PERSON.getNamespaceURI(), ContentModel.TYPE_PERSON + .getLocalName(), ContentModel.TYPE_PERSON.toPrefixString(namespaceService), attrs); + + // permissions + + // owner + + writer.startElement(ContentModel.ASPECT_OWNABLE.getNamespaceURI(), ContentModel.ASPECT_OWNABLE + .getLocalName(), ContentModel.ASPECT_OWNABLE.toPrefixString(namespaceService), + new AttributesImpl()); + + writer.endElement(ContentModel.ASPECT_OWNABLE.getNamespaceURI(), ContentModel.ASPECT_OWNABLE + .getLocalName(), ContentModel.ASPECT_OWNABLE.toPrefixString(namespaceService)); + + writer.startElement(ContentModel.PROP_OWNER.getNamespaceURI(), ContentModel.PROP_OWNER + .getLocalName(), ContentModel.PROP_OWNER.toPrefixString(namespaceService), + new AttributesImpl()); + + writer.characters(uid.toCharArray(), 0, uid.length()); + + writer.endElement(ContentModel.PROP_OWNER.getNamespaceURI(), + ContentModel.PROP_OWNER.getLocalName(), ContentModel.PROP_OWNER + .toPrefixString(namespaceService)); + + for (String key : attributeMapping.keySet()) + { + QName keyQName = QName.createQName(key, namespaceService); + + writer.startElement(keyQName.getNamespaceURI(), keyQName.getLocalName(), keyQName + .toPrefixString(namespaceService), new AttributesImpl()); + + // cater for null + String attributeName = attributeMapping.get(key); + if (attributeName != null) + { + Attribute attribute = attributes.get(attributeName); + if (attribute != null) + { + String value = (String) attribute.get(0); + if (value != null) + { + writer.characters(value.toCharArray(), 0, value.length()); + } + } + else + { + String defaultValue = attributeDefaults.get(key); + if(defaultValue != null) + { + writer.characters(defaultValue.toCharArray(), 0, defaultValue.length()); + } + } + } + else + { + String defaultValue = attributeDefaults.get(key); + if(defaultValue != null) + { + writer.characters(defaultValue.toCharArray(), 0, defaultValue.length()); + } + } + + writer.endElement(keyQName.getNamespaceURI(), keyQName.getLocalName(), keyQName + .toPrefixString(namespaceService)); + } + + if (personService.personExists(uid)) + { + String uguid = personService.getPerson(uid).getId(); + + writer.startElement(nodeUUID.getNamespaceURI(), nodeUUID.getLocalName(), nodeUUID + .toPrefixString(namespaceService), new AttributesImpl()); + + writer.characters(uguid.toCharArray(), 0, uguid.length()); + + writer.endElement(nodeUUID.getNamespaceURI(), nodeUUID.getLocalName(), nodeUUID + .toPrefixString(namespaceService)); + } + writer.endElement(ContentModel.TYPE_PERSON.getNamespaceURI(), ContentModel.TYPE_PERSON + .getLocalName(), ContentModel.TYPE_PERSON.toPrefixString(namespaceService)); + + } + + } + catch (NamingException e) + { + throw new ExportSourceImporterException("Failed to import people.", e); + } + finally + { + if (ctx != null) + { + try + { + ctx.close(); + } + catch (NamingException e) + { + throw new ExportSourceImporterException("Failed to import people.", e); + } + } + } + + for (String prefix : prefixes) + { + if (!prefix.equals("xml")) + { + writer.endPrefixMapping(prefix); + } + } + + writer.endElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "view", NamespaceService.REPOSITORY_VIEW_PREFIX + + ":" + "view"); + + writer.endDocument(); + } + catch (SAXException e) + { + throw new ExportSourceImporterException("Failed to create file for import.", e); + } + } + + public static void main(String[] args) throws Exception + { + ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + ExportSource source = (ExportSource) ctx.getBean("ldapPeopleExportSource"); + TransactionService txs = (TransactionService) ctx.getBean("transactionComponent"); + UserTransaction tx = txs.getUserTransaction(); + tx.begin(); + + File file = new File(args[0]); + Writer writer = new BufferedWriter(new FileWriter(file)); + XMLWriter xmlWriter = createXMLExporter(writer); + source.generateExport(xmlWriter); + xmlWriter.close(); + + tx.commit(); + } + + private static XMLWriter createXMLExporter(Writer writer) + { + // Define output format + OutputFormat format = OutputFormat.createPrettyPrint(); + format.setNewLineAfterDeclaration(false); + format.setIndentSize(3); + format.setEncoding("UTF-8"); + + // Construct an XML Exporter + + XMLWriter xmlWriter = new XMLWriter(writer, format); + return xmlWriter; + } +} diff --git a/source/java/org/alfresco/repo/security/authentication/ntlm/NTLMAuthenticationComponentImpl.java b/source/java/org/alfresco/repo/security/authentication/ntlm/NTLMAuthenticationComponentImpl.java index 7bdbbf5b5d..9ee09959c9 100644 --- a/source/java/org/alfresco/repo/security/authentication/ntlm/NTLMAuthenticationComponentImpl.java +++ b/source/java/org/alfresco/repo/security/authentication/ntlm/NTLMAuthenticationComponentImpl.java @@ -531,6 +531,9 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo authSess = m_passthruServers.openSession(); + if ( authSess == null) + throw new AuthenticationException("Failed to open session to passthru server"); + // Authenticate using the credentials supplied authenticateLocal(ntlmToken, authSess); @@ -748,6 +751,11 @@ public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationCompo authSess = m_passthruServers.openSession(); + // Check if the session was opened to the passthru server + + if ( authSess == null) + throw new AuthenticationServiceException("Failed to open passthru auth session"); + ntlmToken.setAuthenticationExpireTime(System.currentTimeMillis() + getSessionTimeout()); // Get the challenge from the initial session negotiate stage diff --git a/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthority.java b/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthority.java index f952d5dd2b..1549425147 100644 --- a/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthority.java +++ b/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthority.java @@ -26,30 +26,34 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.security.PermissionService; import org.springframework.beans.factory.InitializingBean; - +/** + * LockOwnerDynamicAuthority + */ public class LockOwnerDynamicAuthority implements DynamicAuthority, InitializingBean { - private LockService lockService; private NodeService nodeService; - - public LockOwnerDynamicAuthority() - { - super(); - } - + public boolean hasAuthority(NodeRef nodeRef, String userName) { - if(lockService.getLockStatus(nodeRef) == LockStatus.LOCK_OWNER) + if (lockService.getLockStatus(nodeRef) == LockStatus.LOCK_OWNER) { return true; } - if(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY)) + if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY)) { - NodeRef originial = DefaultTypeConverter.INSTANCE.convert(NodeRef.class, nodeService.getProperty(nodeRef, ContentModel.PROP_COPY_REFERENCE)); - return (lockService.getLockStatus(originial) == LockStatus.LOCK_OWNER); + NodeRef original = DefaultTypeConverter.INSTANCE.convert( + NodeRef.class, nodeService.getProperty(nodeRef, ContentModel.PROP_COPY_REFERENCE)); + if (nodeService.exists(original)) + { + return (lockService.getLockStatus(original) == LockStatus.LOCK_OWNER); + } + else + { + return false; + } } else { @@ -80,12 +84,8 @@ public class LockOwnerDynamicAuthority implements DynamicAuthority, Initializing this.lockService = lockService; } - public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; } - - - } diff --git a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java index db1725cab5..eb07041b43 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java @@ -1,1132 +1,1132 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.security.permissions.impl; - -import java.io.Serializable; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import net.sf.acegisecurity.Authentication; -import net.sf.acegisecurity.GrantedAuthority; -import net.sf.acegisecurity.providers.dao.User; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.cache.SimpleCache; -import org.alfresco.repo.policy.JavaBehaviour; -import org.alfresco.repo.policy.PolicyComponent; -import org.alfresco.repo.security.authentication.AuthenticationComponent; -import org.alfresco.repo.security.permissions.DynamicAuthority; -import org.alfresco.repo.security.permissions.NodePermissionEntry; -import org.alfresco.repo.security.permissions.PermissionEntry; -import org.alfresco.repo.security.permissions.PermissionReference; -import org.alfresco.repo.security.permissions.PermissionServiceSPI; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.security.AccessPermission; -import org.alfresco.service.cmr.security.AccessStatus; -import org.alfresco.service.cmr.security.AuthorityService; -import org.alfresco.service.cmr.security.AuthorityType; -import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.EqualsHelper; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.InitializingBean; - -/** - * The Alfresco implementation of a permissions service against our APIs for the - * permissions model and permissions persistence. - * - * @author andyh - */ -public class PermissionServiceImpl implements PermissionServiceSPI, InitializingBean -{ - - static SimplePermissionReference OLD_ALL_PERMISSIONS_REFERENCE = new SimplePermissionReference( - QName.createQName("", PermissionService.ALL_PERMISSIONS), - PermissionService.ALL_PERMISSIONS); - - private static Log log = LogFactory.getLog(PermissionServiceImpl.class); - - /** a transactionally-safe cache to be injected */ - private SimpleCache accessCache; - - /* - * Access to the model - */ - private ModelDAO modelDAO; - - /* - * Access to permissions - */ - private PermissionsDaoComponent permissionsDaoComponent; - - /* - * Access to the node service - */ - private NodeService nodeService; - - /* - * Access to the data dictionary - */ - private DictionaryService dictionaryService; - - /* - * Access to the authentication component - */ - private AuthenticationComponent authenticationComponent; - - /* - * Access to the authority component - */ - private AuthorityService authorityService; - - /* - * Dynamic authorities providers - */ - private List dynamicAuthorities; - - private PolicyComponent policyComponent; - - /* - * Standard spring construction. - */ - public PermissionServiceImpl() - { - super(); - } - - // - // Inversion of control - // - - public void setDictionaryService(DictionaryService dictionaryService) - { - this.dictionaryService = dictionaryService; - } - - public void setModelDAO(ModelDAO modelDAO) - { - this.modelDAO = modelDAO; - } - - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - public void setPermissionsDaoComponent(PermissionsDaoComponent permissionsDaoComponent) - { - this.permissionsDaoComponent = permissionsDaoComponent; - } - - public void setAuthenticationComponent(AuthenticationComponent authenticationComponent) - { - this.authenticationComponent = authenticationComponent; - } - - public void setAuthorityService(AuthorityService authorityService) - { - this.authorityService = authorityService; - } - - public void setDynamicAuthorities(List dynamicAuthorities) - { - this.dynamicAuthorities = dynamicAuthorities; - } - - /** - * Set the permissions access cache. - * - * @param accessCache - * a transactionally safe cache - */ - public void setAccessCache(SimpleCache accessCache) - { - this.accessCache = accessCache; - } - - public void setPolicyComponent(PolicyComponent policyComponent) - { - this.policyComponent = policyComponent; - } - - public void onMoveNode(ChildAssociationRef oldChildAssocRef, ChildAssociationRef newChildAssocRef) - { - accessCache.clear(); - } - - public void afterPropertiesSet() throws Exception - { - if (dictionaryService == null) - { - throw new IllegalArgumentException("Property 'dictionaryService' has not been set"); - } - if (modelDAO == null) - { - throw new IllegalArgumentException("Property 'modelDAO' has not been set"); - } - if (nodeService == null) - { - throw new IllegalArgumentException("Property 'nodeService' has not been set"); - } - if (permissionsDaoComponent == null) - { - throw new IllegalArgumentException("Property 'permissionsDAO' has not been set"); - } - if (authenticationComponent == null) - { - throw new IllegalArgumentException("Property 'authenticationComponent' has not been set"); - } - if(authorityService == null) - { - throw new IllegalArgumentException("Property 'authorityService' has not been set"); - } - if (accessCache == null) - { - throw new IllegalArgumentException("Property 'accessCache' has not been set"); - } - if (policyComponent == null) - { - throw new IllegalArgumentException("Property 'policyComponent' has not been set"); - } - - policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onMoveNode"), ContentModel.ASPECT_AUDITABLE, new JavaBehaviour(this, "onMoveNode")); - - } - - // - // Permissions Service - // - - public String getOwnerAuthority() - { - return OWNER_AUTHORITY; - } - - public String getAllAuthorities() - { - return ALL_AUTHORITIES; - } - - public String getAllPermission() - { - return ALL_PERMISSIONS; - } - - public Set getPermissions(NodeRef nodeRef) - { - return getAllPermissionsImpl(nodeRef, true, true); - } - - public Set getAllSetPermissions(NodeRef nodeRef) - { - HashSet accessPermissions = new HashSet(); - NodePermissionEntry nodePremissionEntry = getSetPermissions(nodeRef); - for (PermissionEntry pe : nodePremissionEntry.getPermissionEntries()) - { - accessPermissions.add(new AccessPermissionImpl(getPermission(pe.getPermissionReference()), pe - .getAccessStatus(), pe.getAuthority())); - } - return accessPermissions; - } - - private Set getAllPermissionsImpl(NodeRef nodeRef, boolean includeTrue, boolean includeFalse) - { - String userName = authenticationComponent.getCurrentUserName(); - HashSet accessPermissions = new HashSet(); - for (PermissionReference pr : getSettablePermissionReferences(nodeRef)) - { - if (hasPermission(nodeRef, pr) == AccessStatus.ALLOWED) - { - accessPermissions.add(new AccessPermissionImpl(getPermission(pr), AccessStatus.ALLOWED, userName)); - } - else - { - if (includeFalse) - { - accessPermissions.add(new AccessPermissionImpl(getPermission(pr), AccessStatus.DENIED, userName)); - } - } - } - return accessPermissions; - } - - private class AccessPermissionImpl implements AccessPermission - { - private String permission; - - private AccessStatus accessStatus; - - private String authority; - - private AuthorityType authorityType; - - AccessPermissionImpl(String permission, AccessStatus accessStatus, String authority) - { - this.permission = permission; - this.accessStatus = accessStatus; - this.authority = authority; - this.authorityType = AuthorityType.getAuthorityType(authority); - } - - public String getPermission() - { - return permission; - } - - public AccessStatus getAccessStatus() - { - return accessStatus; - } - - public String getAuthority() - { - return authority; - } - - public AuthorityType getAuthorityType() - { - return authorityType; - } - - @Override - public String toString() - { - return accessStatus + " " + this.permission + " - " + - this.authority + " (" + this.authorityType + ")"; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (!(o instanceof AccessPermissionImpl)) - { - return false; - } - AccessPermissionImpl other = (AccessPermissionImpl) o; - return this.getPermission().equals(other.getPermission()) - && (this.getAccessStatus() == other.getAccessStatus() && (this.getAccessStatus().equals(other - .getAccessStatus()))); - } - - @Override - public int hashCode() - { - return ((authority.hashCode() * 37) + permission.hashCode()) * 37 + accessStatus.hashCode(); - } - } - - public Set getSettablePermissions(NodeRef nodeRef) - { - Set settable = getSettablePermissionReferences(nodeRef); - Set strings = new HashSet(settable.size()); - for (PermissionReference pr : settable) - { - strings.add(getPermission(pr)); - } - return strings; - } - - public Set getSettablePermissions(QName type) - { - Set settable = getSettablePermissionReferences(type); - Set strings = new LinkedHashSet(settable.size()); - for (PermissionReference pr : settable) - { - strings.add(getPermission(pr)); - } - return strings; - } - - public NodePermissionEntry getSetPermissions(NodeRef nodeRef) - { - return permissionsDaoComponent.getPermissions(nodeRef); - } - - public AccessStatus hasPermission(NodeRef nodeRef, PermissionReference perm) - { - // If the node ref is null there is no sensible test to do - and there - // must be no permissions - // - so we allow it - if (nodeRef == null) - { - return AccessStatus.ALLOWED; - } - - // If the permission is null we deny - if (perm == null) - { - return AccessStatus.DENIED; - } - - // Allow permissions for nodes that do not exist - if (!nodeService.exists(nodeRef)) - { - return AccessStatus.ALLOWED; - } - - // Get the current authentications - // Use the smart authentication cache to improve permissions performance - Authentication auth = authenticationComponent.getCurrentAuthentication(); - Set authorisations = getAuthorisations(auth, nodeRef); - Serializable key = generateKey( - authorisations, - nodeRef, - perm); - AccessStatus status = accessCache.get(key); - if (status != null) - { - return status; - } - - // If the node does not support the given permission there is no point - // doing the test - Set available = modelDAO.getAllPermissions(nodeRef); - available.add(getAllPermissionReference()); - available.add(OLD_ALL_PERMISSIONS_REFERENCE); - - if (!(available.contains(perm))) - { - accessCache.put(key, AccessStatus.DENIED); - return AccessStatus.DENIED; - } - - // - // TODO: Dynamic permissions via evaluators - // - - /* - * Does the current authentication have the supplied permission on the - * given node. - */ - - QName typeQname = nodeService.getType(nodeRef); - Set aspectQNames = nodeService.getAspects(nodeRef); - - if (perm.equals(OLD_ALL_PERMISSIONS_REFERENCE)) - { - perm = getAllPermissionReference(); - } - NodeTest nt = new NodeTest(perm, typeQname, aspectQNames); - boolean result = nt.evaluate(authorisations, nodeRef); - if (log.isDebugEnabled()) - { - log.debug("Permission <" - + perm + "> is " + (result ? "allowed" : "denied") + " for " - + authenticationComponent.getCurrentUserName() + " on node " + nodeService.getPath(nodeRef)); - } - - status = result ? AccessStatus.ALLOWED : AccessStatus.DENIED; - accessCache.put(key, status); - return status; - } - - /** - * Key for a cache object is built from all the known Authorities (which can - * change dynamically so they must all be used) the NodeRef ID and the - * permission reference itself. This gives a unique key for each permission - * test. - */ - static Serializable generateKey(Set auths, NodeRef nodeRef, PermissionReference perm) - { - LinkedHashSet key = new LinkedHashSet(); - key.add(perm.toString()); - key.addAll(auths); - key.add(nodeRef); - return key; - } - - /** - * Get the authorisations for the currently authenticated user - * - * @param auth - * @return - */ - private Set getAuthorisations(Authentication auth, NodeRef nodeRef) - { - HashSet auths = new HashSet(); - // No authenticated user then no permissions - if (auth == null) - { - return auths; - } - // TODO: Refactor and use the authentication service for this. - User user = (User) auth.getPrincipal(); - auths.add(user.getUsername()); - for (GrantedAuthority authority : auth.getAuthorities()) - { - auths.add(authority.getAuthority()); - } - if (dynamicAuthorities != null) - { - for (DynamicAuthority da : dynamicAuthorities) - { - if (da.hasAuthority(nodeRef, user.getUsername())) - { - auths.add(da.getAuthority()); - } - } - } - auths.addAll(authorityService.getAuthorities()); - return auths; - } - - public NodePermissionEntry explainPermission(NodeRef nodeRef, PermissionReference perm) - { - // TODO Auto-generated method stub - return null; - } - - public void deletePermissions(NodeRef nodeRef) - { - permissionsDaoComponent.deletePermissions(nodeRef); - accessCache.clear(); - } - - public void deletePermissions(NodePermissionEntry nodePermissionEntry) - { - permissionsDaoComponent.deletePermissions(nodePermissionEntry.getNodeRef()); - accessCache.clear(); - } - - /** - * @see #deletePermission(NodeRef, String, PermissionReference) - */ - public void deletePermission(PermissionEntry permissionEntry) - { - NodeRef nodeRef = permissionEntry.getNodeRef(); - String authority = permissionEntry.getAuthority(); - PermissionReference permission = permissionEntry.getPermissionReference(); - deletePermission(nodeRef, authority, permission); - } - - public void deletePermission(NodeRef nodeRef, String authority, PermissionReference perm) - { - permissionsDaoComponent.deletePermission(nodeRef, authority, perm); - accessCache.clear(); - } - - public void clearPermission(NodeRef nodeRef, String authority) - { - permissionsDaoComponent.deletePermissions(nodeRef, authority); - accessCache.clear(); - } - - public void setPermission(NodeRef nodeRef, String authority, PermissionReference perm, boolean allow) - { - permissionsDaoComponent.setPermission(nodeRef, authority, perm, allow); - accessCache.clear(); - } - - public void setPermission(PermissionEntry permissionEntry) - { - permissionsDaoComponent.setPermission(permissionEntry); - accessCache.clear(); - } - - public void setPermission(NodePermissionEntry nodePermissionEntry) - { - permissionsDaoComponent.setPermission(nodePermissionEntry); - accessCache.clear(); - } - - public void setInheritParentPermissions(NodeRef nodeRef, boolean inheritParentPermissions) - { - permissionsDaoComponent.setInheritParentPermissions(nodeRef, inheritParentPermissions); - accessCache.clear(); - } - - /** - * @see org.alfresco.service.cmr.security.PermissionService#getInheritParentPermissions(org.alfresco.service.cmr.repository.NodeRef) - */ - public boolean getInheritParentPermissions(NodeRef nodeRef) - { - return permissionsDaoComponent.getInheritParentPermissions(nodeRef); - } - - - public PermissionReference getPermissionReference(QName qname, String permissionName) - { - return modelDAO.getPermissionReference(qname, permissionName); - } - - public PermissionReference getAllPermissionReference() - { - return getPermissionReference(ALL_PERMISSIONS); - } - - public String getPermission(PermissionReference permissionReference) - { - if (modelDAO.isUnique(permissionReference)) - { - return permissionReference.getName(); - } - else - { - return permissionReference.toString(); - } - } - - public PermissionReference getPermissionReference(String permissionName) - { - return modelDAO.getPermissionReference(null, permissionName); - } - - public Set getSettablePermissionReferences(QName type) - { - return modelDAO.getExposedPermissions(type); - } - - public Set getSettablePermissionReferences(NodeRef nodeRef) - { - return modelDAO.getExposedPermissions(nodeRef); - } - - public void deletePermission(NodeRef nodeRef, String authority, String perm) - { - deletePermission(nodeRef, authority, getPermissionReference(perm)); - } - - public AccessStatus hasPermission(NodeRef nodeRef, String perm) - { - return hasPermission(nodeRef, getPermissionReference(perm)); - } - - public void setPermission(NodeRef nodeRef, String authority, String perm, boolean allow) - { - setPermission(nodeRef, authority, getPermissionReference(perm), allow); - } - - public void deletePermissions(String recipient) - { - permissionsDaoComponent.deletePermissions(recipient); - accessCache.clear(); - } - - // - // SUPPORT CLASSES - // - - /** - * Support class to test the permission on a node. - * - * @author Andy Hind - */ - private class NodeTest - { - /* - * The required permission. - */ - PermissionReference required; - - /* - * Granters of the permission - */ - Set granters; - - /* - * The additional permissions required at the node level. - */ - Set nodeRequirements = new HashSet(); - - /* - * The additional permissions required on the parent. - */ - Set parentRequirements = new HashSet(); - - /* - * The permissions required on all children . - */ - Set childrenRequirements = new HashSet(); - - /* - * The type name of the node. - */ - QName typeQName; - - /* - * The aspects set on the node. - */ - Set aspectQNames; - - /* - * Constructor just gets the additional requirements - */ - NodeTest(PermissionReference required, QName typeQName, Set aspectQNames) - { - this.required = required; - this.typeQName = typeQName; - this.aspectQNames = aspectQNames; - - // Set the required node permissions - nodeRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, - RequiredPermission.On.NODE); - - parentRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, - RequiredPermission.On.PARENT); - - childrenRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, - RequiredPermission.On.CHILDREN); - - // Find all the permissions that grant the allowed permission - // All permissions are treated specially. - granters = modelDAO.getGrantingPermissions(required); - granters.add(getAllPermissionReference()); - granters.add(OLD_ALL_PERMISSIONS_REFERENCE); - } - - /** - * External hook point - * - * @param authorisations - * @param nodeRef - * @return - */ - boolean evaluate(Set authorisations, NodeRef nodeRef) - { - Set> denied = new HashSet>(); - return evaluate(authorisations, nodeRef, denied, null); - } - - /** - * Internal hook point for recursion - * - * @param authorisations - * @param nodeRef - * @param denied - * @param recursiveIn - * @return - */ - boolean evaluate(Set authorisations, NodeRef nodeRef, Set> denied, - MutableBoolean recursiveIn) - { - // Do we defer our required test to a parent (yes if not null) - MutableBoolean recursiveOut = null; - - Set> locallyDenied = new HashSet>(); - locallyDenied.addAll(denied); - locallyDenied.addAll(getDenied(nodeRef)); - - // Start out true and "and" all other results - boolean success = true; - - // Check the required permissions but not for sets they rely on - // their underlying permissions - if (required.equals(getPermissionReference(ALL_PERMISSIONS)) || modelDAO.checkPermission(required)) - { - if (parentRequirements.contains(required)) - { - if (checkGlobalPermissions(authorisations) || checkRequired(authorisations, nodeRef, locallyDenied)) - { - // No need to do the recursive test as it has been found - recursiveOut = null; - if (recursiveIn != null) - { - recursiveIn.setValue(true); - } - } - else - { - // Much cheaper to do this as we go then check all the - // stack values for each parent - recursiveOut = new MutableBoolean(false); - } - } - else - { - // We have to do the test as no parent will help us out - success &= hasSinglePermission(authorisations, nodeRef); - } - if (!success) - { - return false; - } - } - - // Check the other permissions required on the node - for (PermissionReference pr : nodeRequirements) - { - // Build a new test - NodeTest nt = new NodeTest(pr, typeQName, aspectQNames); - success &= nt.evaluate(authorisations, nodeRef, locallyDenied, null); - if (!success) - { - return false; - } - } - - // Check the permission required of the parent - - if (success) - { - ChildAssociationRef car = nodeService.getPrimaryParent(nodeRef); - if (car.getParentRef() != null) - { - - NodePermissionEntry nodePermissions = permissionsDaoComponent.getPermissions(car.getChildRef()); - if ((nodePermissions == null) || (nodePermissions.inheritPermissions())) - { - - locallyDenied.addAll(getDenied(car.getParentRef())); - for (PermissionReference pr : parentRequirements) - { - if (pr.equals(required)) - { - // Recursive permission - success &= this.evaluate(authorisations, car.getParentRef(), locallyDenied, - recursiveOut); - if ((recursiveOut != null) && recursiveOut.getValue()) - { - if (recursiveIn != null) - { - recursiveIn.setValue(true); - } - } - } - else - { - NodeTest nt = new NodeTest(pr, typeQName, aspectQNames); - success &= nt.evaluate(authorisations, car.getParentRef(), locallyDenied, null); - } - - if (!success) - { - return false; - } - } - } - } - } - - if ((recursiveOut != null) && (!recursiveOut.getValue())) - { - // The required authentication was not resolved in recursion - return false; - } - - // Check permissions required of children - if (childrenRequirements.size() > 0) - { - List childAssocRefs = nodeService.getChildAssocs(nodeRef); - for (PermissionReference pr : childrenRequirements) - { - for (ChildAssociationRef child : childAssocRefs) - { - success &= (hasPermission(child.getChildRef(), pr) == AccessStatus.ALLOWED); - if (!success) - { - return false; - } - } - } - } - - return success; - } - - public boolean hasSinglePermission(Set authorisations, NodeRef nodeRef) - { - // Check global permission - - if (checkGlobalPermissions(authorisations)) - { - return true; - } - - Set> denied = new HashSet>(); - - // Keep track of permission that are denied - - // Permissions are only evaluated up the primary parent chain - // TODO: Do not ignore non primary permissions - ChildAssociationRef car = nodeService.getPrimaryParent(nodeRef); - // Work up the parent chain evaluating permissions. - while (car != null) - { - // Add any denied permission to the denied list - these can not - // then - // be used to given authentication. - // A -> B -> C - // If B denies all permissions to any - allowing all permissions - // to - // andy at node A has no effect - - denied.addAll(getDenied(car.getChildRef())); - - // If the current node allows the permission we are done - // The test includes any parent or ancestor requirements - if (checkRequired(authorisations, car.getChildRef(), denied)) - { - return true; - } - - // Build the next element of the evaluation chain - if (car.getParentRef() != null) - { - NodePermissionEntry nodePermissions = permissionsDaoComponent.getPermissions(car.getChildRef()); - if ((nodePermissions == null) || (nodePermissions.inheritPermissions())) - { - car = nodeService.getPrimaryParent(car.getParentRef()); - } - else - { - car = null; - } - } - else - { - car = null; - } - - } - - // TODO: Support meta data permissions on the root node? - - return false; - - } - - /** - * Check if we have a global permission - * - * @param authorisations - * @return - */ - private boolean checkGlobalPermissions(Set authorisations) - { - for (PermissionEntry pe : modelDAO.getGlobalPermissionEntries()) - { - if (isGranted(pe, authorisations, null)) - { - return true; - } - } - return false; - } - - /** - * Get the list of permissions denied for this node. - * - * @param nodeRef - * @return - */ - Set> getDenied(NodeRef nodeRef) - { - Set> deniedSet = new HashSet>(); - - // Loop over all denied permissions - NodePermissionEntry nodeEntry = permissionsDaoComponent.getPermissions(nodeRef); - if (nodeEntry != null) - { - for (PermissionEntry pe : nodeEntry.getPermissionEntries()) - { - if (pe.isDenied()) - { - // All the sets that grant this permission must be - // denied - // Note that granters includes the orginal permission - Set granters = modelDAO - .getGrantingPermissions(pe.getPermissionReference()); - for (PermissionReference granter : granters) - { - deniedSet.add(new Pair(pe.getAuthority(), granter)); - } - - // All the things granted by this permission must be - // denied - Set grantees = modelDAO.getGranteePermissions(pe.getPermissionReference()); - for (PermissionReference grantee : grantees) - { - deniedSet.add(new Pair(pe.getAuthority(), grantee)); - } - - // All permission excludes all permissions available for - // the node. - if (pe.getPermissionReference().equals(getAllPermissionReference()) || pe.getPermissionReference().equals(OLD_ALL_PERMISSIONS_REFERENCE)) - { - for (PermissionReference deny : modelDAO.getAllPermissions(nodeRef)) - { - deniedSet.add(new Pair(pe.getAuthority(), deny)); - } - } - } - } - } - return deniedSet; - } - - /** - * Check that a given authentication is available on a node - * - * @param authorisations - * @param nodeRef - * @param denied - * @return - */ - boolean checkRequired(Set authorisations, NodeRef nodeRef, Set> denied) - { - NodePermissionEntry nodeEntry = permissionsDaoComponent.getPermissions(nodeRef); - - // No permissions set - short cut to deny - if (nodeEntry == null) - { - return false; - } - - // Check if each permission allows - the first wins. - // We could have other voting style mechanisms here - for (PermissionEntry pe : nodeEntry.getPermissionEntries()) - { - if (isGranted(pe, authorisations, denied)) - { - return true; - } - } - return false; - } - - /** - * Is a permission granted - * - * @param pe - - * the permissions entry to consider - * @param granters - - * the set of granters - * @param authorisations - - * the set of authorities - * @param denied - - * the set of denied permissions/authority pais - * @return - */ - private boolean isGranted(PermissionEntry pe, Set authorisations, - Set> denied) - { - // If the permission entry denies then we just deny - if (pe.isDenied()) - { - return false; - } - - // The permission is allowed but we deny it as it is in the denied - // set - if (denied != null) - { - Pair specific = new Pair(pe.getAuthority(), - required); - if (denied.contains(specific)) - { - return false; - } - } - - // If the permission has a match in both the authorities and - // granters list it is allowed - // It applies to the current user and it is granted - if (authorisations.contains(pe.getAuthority()) && granters.contains(pe.getPermissionReference())) - { - { - return true; - } - } - - // Default deny - return false; - } - - } - - /** - * Helper class to store a pair of objects which may be null - * - * @author Andy Hind - */ - private static class Pair - { - A a; - - B b; - - Pair(A a, B b) - { - this.a = a; - this.b = b; - } - - A getA() - { - return a; - } - - B getB() - { - return b; - } - - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (!(this instanceof Pair)) - { - return false; - } - Pair other = (Pair) o; - return EqualsHelper.nullSafeEquals(this.getA(), other.getA()) - && EqualsHelper.nullSafeEquals(this.getB(), other.getB()); - } - - @Override - public int hashCode() - { - return (((a == null) ? 0 : a.hashCode()) * 37) + ((b == null) ? 0 : b.hashCode()); - } - - } - - private static class MutableBoolean - { - private boolean value; - - MutableBoolean(boolean value) - { - this.value = value; - } - - void setValue(boolean value) - { - this.value = value; - } - - boolean getValue() - { - return value; - } - } -} +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.security.permissions.impl; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import net.sf.acegisecurity.Authentication; +import net.sf.acegisecurity.GrantedAuthority; +import net.sf.acegisecurity.providers.dao.User; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.policy.JavaBehaviour; +import org.alfresco.repo.policy.PolicyComponent; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.security.permissions.DynamicAuthority; +import org.alfresco.repo.security.permissions.NodePermissionEntry; +import org.alfresco.repo.security.permissions.PermissionEntry; +import org.alfresco.repo.security.permissions.PermissionReference; +import org.alfresco.repo.security.permissions.PermissionServiceSPI; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.AccessPermission; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.AuthorityType; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.EqualsHelper; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.InitializingBean; + +/** + * The Alfresco implementation of a permissions service against our APIs for the + * permissions model and permissions persistence. + * + * @author andyh + */ +public class PermissionServiceImpl implements PermissionServiceSPI, InitializingBean +{ + + static SimplePermissionReference OLD_ALL_PERMISSIONS_REFERENCE = new SimplePermissionReference( + QName.createQName("", PermissionService.ALL_PERMISSIONS), + PermissionService.ALL_PERMISSIONS); + + private static Log log = LogFactory.getLog(PermissionServiceImpl.class); + + /** a transactionally-safe cache to be injected */ + private SimpleCache accessCache; + + /* + * Access to the model + */ + private ModelDAO modelDAO; + + /* + * Access to permissions + */ + private PermissionsDaoComponent permissionsDaoComponent; + + /* + * Access to the node service + */ + private NodeService nodeService; + + /* + * Access to the data dictionary + */ + private DictionaryService dictionaryService; + + /* + * Access to the authentication component + */ + private AuthenticationComponent authenticationComponent; + + /* + * Access to the authority component + */ + private AuthorityService authorityService; + + /* + * Dynamic authorities providers + */ + private List dynamicAuthorities; + + private PolicyComponent policyComponent; + + /* + * Standard spring construction. + */ + public PermissionServiceImpl() + { + super(); + } + + // + // Inversion of control + // + + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + + public void setModelDAO(ModelDAO modelDAO) + { + this.modelDAO = modelDAO; + } + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + public void setPermissionsDaoComponent(PermissionsDaoComponent permissionsDaoComponent) + { + this.permissionsDaoComponent = permissionsDaoComponent; + } + + public void setAuthenticationComponent(AuthenticationComponent authenticationComponent) + { + this.authenticationComponent = authenticationComponent; + } + + public void setAuthorityService(AuthorityService authorityService) + { + this.authorityService = authorityService; + } + + public void setDynamicAuthorities(List dynamicAuthorities) + { + this.dynamicAuthorities = dynamicAuthorities; + } + + /** + * Set the permissions access cache. + * + * @param accessCache + * a transactionally safe cache + */ + public void setAccessCache(SimpleCache accessCache) + { + this.accessCache = accessCache; + } + + public void setPolicyComponent(PolicyComponent policyComponent) + { + this.policyComponent = policyComponent; + } + + public void onMoveNode(ChildAssociationRef oldChildAssocRef, ChildAssociationRef newChildAssocRef) + { + accessCache.clear(); + } + + public void afterPropertiesSet() throws Exception + { + if (dictionaryService == null) + { + throw new IllegalArgumentException("Property 'dictionaryService' has not been set"); + } + if (modelDAO == null) + { + throw new IllegalArgumentException("Property 'modelDAO' has not been set"); + } + if (nodeService == null) + { + throw new IllegalArgumentException("Property 'nodeService' has not been set"); + } + if (permissionsDaoComponent == null) + { + throw new IllegalArgumentException("Property 'permissionsDAO' has not been set"); + } + if (authenticationComponent == null) + { + throw new IllegalArgumentException("Property 'authenticationComponent' has not been set"); + } + if(authorityService == null) + { + throw new IllegalArgumentException("Property 'authorityService' has not been set"); + } + if (accessCache == null) + { + throw new IllegalArgumentException("Property 'accessCache' has not been set"); + } + if (policyComponent == null) + { + throw new IllegalArgumentException("Property 'policyComponent' has not been set"); + } + + policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onMoveNode"), ContentModel.TYPE_BASE, new JavaBehaviour(this, "onMoveNode")); + + } + + // + // Permissions Service + // + + public String getOwnerAuthority() + { + return OWNER_AUTHORITY; + } + + public String getAllAuthorities() + { + return ALL_AUTHORITIES; + } + + public String getAllPermission() + { + return ALL_PERMISSIONS; + } + + public Set getPermissions(NodeRef nodeRef) + { + return getAllPermissionsImpl(nodeRef, true, true); + } + + public Set getAllSetPermissions(NodeRef nodeRef) + { + HashSet accessPermissions = new HashSet(); + NodePermissionEntry nodePremissionEntry = getSetPermissions(nodeRef); + for (PermissionEntry pe : nodePremissionEntry.getPermissionEntries()) + { + accessPermissions.add(new AccessPermissionImpl(getPermission(pe.getPermissionReference()), pe + .getAccessStatus(), pe.getAuthority())); + } + return accessPermissions; + } + + private Set getAllPermissionsImpl(NodeRef nodeRef, boolean includeTrue, boolean includeFalse) + { + String userName = authenticationComponent.getCurrentUserName(); + HashSet accessPermissions = new HashSet(); + for (PermissionReference pr : getSettablePermissionReferences(nodeRef)) + { + if (hasPermission(nodeRef, pr) == AccessStatus.ALLOWED) + { + accessPermissions.add(new AccessPermissionImpl(getPermission(pr), AccessStatus.ALLOWED, userName)); + } + else + { + if (includeFalse) + { + accessPermissions.add(new AccessPermissionImpl(getPermission(pr), AccessStatus.DENIED, userName)); + } + } + } + return accessPermissions; + } + + private class AccessPermissionImpl implements AccessPermission + { + private String permission; + + private AccessStatus accessStatus; + + private String authority; + + private AuthorityType authorityType; + + AccessPermissionImpl(String permission, AccessStatus accessStatus, String authority) + { + this.permission = permission; + this.accessStatus = accessStatus; + this.authority = authority; + this.authorityType = AuthorityType.getAuthorityType(authority); + } + + public String getPermission() + { + return permission; + } + + public AccessStatus getAccessStatus() + { + return accessStatus; + } + + public String getAuthority() + { + return authority; + } + + public AuthorityType getAuthorityType() + { + return authorityType; + } + + @Override + public String toString() + { + return accessStatus + " " + this.permission + " - " + + this.authority + " (" + this.authorityType + ")"; + } + + @Override + public boolean equals(Object o) + { + if (this == o) + { + return true; + } + if (!(o instanceof AccessPermissionImpl)) + { + return false; + } + AccessPermissionImpl other = (AccessPermissionImpl) o; + return this.getPermission().equals(other.getPermission()) + && (this.getAccessStatus() == other.getAccessStatus() && (this.getAccessStatus().equals(other + .getAccessStatus()))); + } + + @Override + public int hashCode() + { + return ((authority.hashCode() * 37) + permission.hashCode()) * 37 + accessStatus.hashCode(); + } + } + + public Set getSettablePermissions(NodeRef nodeRef) + { + Set settable = getSettablePermissionReferences(nodeRef); + Set strings = new HashSet(settable.size()); + for (PermissionReference pr : settable) + { + strings.add(getPermission(pr)); + } + return strings; + } + + public Set getSettablePermissions(QName type) + { + Set settable = getSettablePermissionReferences(type); + Set strings = new LinkedHashSet(settable.size()); + for (PermissionReference pr : settable) + { + strings.add(getPermission(pr)); + } + return strings; + } + + public NodePermissionEntry getSetPermissions(NodeRef nodeRef) + { + return permissionsDaoComponent.getPermissions(nodeRef); + } + + public AccessStatus hasPermission(NodeRef nodeRef, PermissionReference perm) + { + // If the node ref is null there is no sensible test to do - and there + // must be no permissions + // - so we allow it + if (nodeRef == null) + { + return AccessStatus.ALLOWED; + } + + // If the permission is null we deny + if (perm == null) + { + return AccessStatus.DENIED; + } + + // Allow permissions for nodes that do not exist + if (!nodeService.exists(nodeRef)) + { + return AccessStatus.ALLOWED; + } + + // Get the current authentications + // Use the smart authentication cache to improve permissions performance + Authentication auth = authenticationComponent.getCurrentAuthentication(); + Set authorisations = getAuthorisations(auth, nodeRef); + Serializable key = generateKey( + authorisations, + nodeRef, + perm); + AccessStatus status = accessCache.get(key); + if (status != null) + { + return status; + } + + // If the node does not support the given permission there is no point + // doing the test + Set available = modelDAO.getAllPermissions(nodeRef); + available.add(getAllPermissionReference()); + available.add(OLD_ALL_PERMISSIONS_REFERENCE); + + if (!(available.contains(perm))) + { + accessCache.put(key, AccessStatus.DENIED); + return AccessStatus.DENIED; + } + + // + // TODO: Dynamic permissions via evaluators + // + + /* + * Does the current authentication have the supplied permission on the + * given node. + */ + + QName typeQname = nodeService.getType(nodeRef); + Set aspectQNames = nodeService.getAspects(nodeRef); + + if (perm.equals(OLD_ALL_PERMISSIONS_REFERENCE)) + { + perm = getAllPermissionReference(); + } + NodeTest nt = new NodeTest(perm, typeQname, aspectQNames); + boolean result = nt.evaluate(authorisations, nodeRef); + if (log.isDebugEnabled()) + { + log.debug("Permission <" + + perm + "> is " + (result ? "allowed" : "denied") + " for " + + authenticationComponent.getCurrentUserName() + " on node " + nodeService.getPath(nodeRef)); + } + + status = result ? AccessStatus.ALLOWED : AccessStatus.DENIED; + accessCache.put(key, status); + return status; + } + + /** + * Key for a cache object is built from all the known Authorities (which can + * change dynamically so they must all be used) the NodeRef ID and the + * permission reference itself. This gives a unique key for each permission + * test. + */ + static Serializable generateKey(Set auths, NodeRef nodeRef, PermissionReference perm) + { + LinkedHashSet key = new LinkedHashSet(); + key.add(perm.toString()); + key.addAll(auths); + key.add(nodeRef); + return key; + } + + /** + * Get the authorisations for the currently authenticated user + * + * @param auth + * @return + */ + private Set getAuthorisations(Authentication auth, NodeRef nodeRef) + { + HashSet auths = new HashSet(); + // No authenticated user then no permissions + if (auth == null) + { + return auths; + } + // TODO: Refactor and use the authentication service for this. + User user = (User) auth.getPrincipal(); + auths.add(user.getUsername()); + for (GrantedAuthority authority : auth.getAuthorities()) + { + auths.add(authority.getAuthority()); + } + if (dynamicAuthorities != null) + { + for (DynamicAuthority da : dynamicAuthorities) + { + if (da.hasAuthority(nodeRef, user.getUsername())) + { + auths.add(da.getAuthority()); + } + } + } + auths.addAll(authorityService.getAuthorities()); + return auths; + } + + public NodePermissionEntry explainPermission(NodeRef nodeRef, PermissionReference perm) + { + // TODO Auto-generated method stub + return null; + } + + public void deletePermissions(NodeRef nodeRef) + { + permissionsDaoComponent.deletePermissions(nodeRef); + accessCache.clear(); + } + + public void deletePermissions(NodePermissionEntry nodePermissionEntry) + { + permissionsDaoComponent.deletePermissions(nodePermissionEntry.getNodeRef()); + accessCache.clear(); + } + + /** + * @see #deletePermission(NodeRef, String, PermissionReference) + */ + public void deletePermission(PermissionEntry permissionEntry) + { + NodeRef nodeRef = permissionEntry.getNodeRef(); + String authority = permissionEntry.getAuthority(); + PermissionReference permission = permissionEntry.getPermissionReference(); + deletePermission(nodeRef, authority, permission); + } + + public void deletePermission(NodeRef nodeRef, String authority, PermissionReference perm) + { + permissionsDaoComponent.deletePermission(nodeRef, authority, perm); + accessCache.clear(); + } + + public void clearPermission(NodeRef nodeRef, String authority) + { + permissionsDaoComponent.deletePermissions(nodeRef, authority); + accessCache.clear(); + } + + public void setPermission(NodeRef nodeRef, String authority, PermissionReference perm, boolean allow) + { + permissionsDaoComponent.setPermission(nodeRef, authority, perm, allow); + accessCache.clear(); + } + + public void setPermission(PermissionEntry permissionEntry) + { + permissionsDaoComponent.setPermission(permissionEntry); + accessCache.clear(); + } + + public void setPermission(NodePermissionEntry nodePermissionEntry) + { + permissionsDaoComponent.setPermission(nodePermissionEntry); + accessCache.clear(); + } + + public void setInheritParentPermissions(NodeRef nodeRef, boolean inheritParentPermissions) + { + permissionsDaoComponent.setInheritParentPermissions(nodeRef, inheritParentPermissions); + accessCache.clear(); + } + + /** + * @see org.alfresco.service.cmr.security.PermissionService#getInheritParentPermissions(org.alfresco.service.cmr.repository.NodeRef) + */ + public boolean getInheritParentPermissions(NodeRef nodeRef) + { + return permissionsDaoComponent.getInheritParentPermissions(nodeRef); + } + + + public PermissionReference getPermissionReference(QName qname, String permissionName) + { + return modelDAO.getPermissionReference(qname, permissionName); + } + + public PermissionReference getAllPermissionReference() + { + return getPermissionReference(ALL_PERMISSIONS); + } + + public String getPermission(PermissionReference permissionReference) + { + if (modelDAO.isUnique(permissionReference)) + { + return permissionReference.getName(); + } + else + { + return permissionReference.toString(); + } + } + + public PermissionReference getPermissionReference(String permissionName) + { + return modelDAO.getPermissionReference(null, permissionName); + } + + public Set getSettablePermissionReferences(QName type) + { + return modelDAO.getExposedPermissions(type); + } + + public Set getSettablePermissionReferences(NodeRef nodeRef) + { + return modelDAO.getExposedPermissions(nodeRef); + } + + public void deletePermission(NodeRef nodeRef, String authority, String perm) + { + deletePermission(nodeRef, authority, getPermissionReference(perm)); + } + + public AccessStatus hasPermission(NodeRef nodeRef, String perm) + { + return hasPermission(nodeRef, getPermissionReference(perm)); + } + + public void setPermission(NodeRef nodeRef, String authority, String perm, boolean allow) + { + setPermission(nodeRef, authority, getPermissionReference(perm), allow); + } + + public void deletePermissions(String recipient) + { + permissionsDaoComponent.deletePermissions(recipient); + accessCache.clear(); + } + + // + // SUPPORT CLASSES + // + + /** + * Support class to test the permission on a node. + * + * @author Andy Hind + */ + private class NodeTest + { + /* + * The required permission. + */ + PermissionReference required; + + /* + * Granters of the permission + */ + Set granters; + + /* + * The additional permissions required at the node level. + */ + Set nodeRequirements = new HashSet(); + + /* + * The additional permissions required on the parent. + */ + Set parentRequirements = new HashSet(); + + /* + * The permissions required on all children . + */ + Set childrenRequirements = new HashSet(); + + /* + * The type name of the node. + */ + QName typeQName; + + /* + * The aspects set on the node. + */ + Set aspectQNames; + + /* + * Constructor just gets the additional requirements + */ + NodeTest(PermissionReference required, QName typeQName, Set aspectQNames) + { + this.required = required; + this.typeQName = typeQName; + this.aspectQNames = aspectQNames; + + // Set the required node permissions + nodeRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, + RequiredPermission.On.NODE); + + parentRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, + RequiredPermission.On.PARENT); + + childrenRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, + RequiredPermission.On.CHILDREN); + + // Find all the permissions that grant the allowed permission + // All permissions are treated specially. + granters = modelDAO.getGrantingPermissions(required); + granters.add(getAllPermissionReference()); + granters.add(OLD_ALL_PERMISSIONS_REFERENCE); + } + + /** + * External hook point + * + * @param authorisations + * @param nodeRef + * @return + */ + boolean evaluate(Set authorisations, NodeRef nodeRef) + { + Set> denied = new HashSet>(); + return evaluate(authorisations, nodeRef, denied, null); + } + + /** + * Internal hook point for recursion + * + * @param authorisations + * @param nodeRef + * @param denied + * @param recursiveIn + * @return + */ + boolean evaluate(Set authorisations, NodeRef nodeRef, Set> denied, + MutableBoolean recursiveIn) + { + // Do we defer our required test to a parent (yes if not null) + MutableBoolean recursiveOut = null; + + Set> locallyDenied = new HashSet>(); + locallyDenied.addAll(denied); + locallyDenied.addAll(getDenied(nodeRef)); + + // Start out true and "and" all other results + boolean success = true; + + // Check the required permissions but not for sets they rely on + // their underlying permissions + if (required.equals(getPermissionReference(ALL_PERMISSIONS)) || modelDAO.checkPermission(required)) + { + if (parentRequirements.contains(required)) + { + if (checkGlobalPermissions(authorisations) || checkRequired(authorisations, nodeRef, locallyDenied)) + { + // No need to do the recursive test as it has been found + recursiveOut = null; + if (recursiveIn != null) + { + recursiveIn.setValue(true); + } + } + else + { + // Much cheaper to do this as we go then check all the + // stack values for each parent + recursiveOut = new MutableBoolean(false); + } + } + else + { + // We have to do the test as no parent will help us out + success &= hasSinglePermission(authorisations, nodeRef); + } + if (!success) + { + return false; + } + } + + // Check the other permissions required on the node + for (PermissionReference pr : nodeRequirements) + { + // Build a new test + NodeTest nt = new NodeTest(pr, typeQName, aspectQNames); + success &= nt.evaluate(authorisations, nodeRef, locallyDenied, null); + if (!success) + { + return false; + } + } + + // Check the permission required of the parent + + if (success) + { + ChildAssociationRef car = nodeService.getPrimaryParent(nodeRef); + if (car.getParentRef() != null) + { + + NodePermissionEntry nodePermissions = permissionsDaoComponent.getPermissions(car.getChildRef()); + if ((nodePermissions == null) || (nodePermissions.inheritPermissions())) + { + + locallyDenied.addAll(getDenied(car.getParentRef())); + for (PermissionReference pr : parentRequirements) + { + if (pr.equals(required)) + { + // Recursive permission + success &= this.evaluate(authorisations, car.getParentRef(), locallyDenied, + recursiveOut); + if ((recursiveOut != null) && recursiveOut.getValue()) + { + if (recursiveIn != null) + { + recursiveIn.setValue(true); + } + } + } + else + { + NodeTest nt = new NodeTest(pr, typeQName, aspectQNames); + success &= nt.evaluate(authorisations, car.getParentRef(), locallyDenied, null); + } + + if (!success) + { + return false; + } + } + } + } + } + + if ((recursiveOut != null) && (!recursiveOut.getValue())) + { + // The required authentication was not resolved in recursion + return false; + } + + // Check permissions required of children + if (childrenRequirements.size() > 0) + { + List childAssocRefs = nodeService.getChildAssocs(nodeRef); + for (PermissionReference pr : childrenRequirements) + { + for (ChildAssociationRef child : childAssocRefs) + { + success &= (hasPermission(child.getChildRef(), pr) == AccessStatus.ALLOWED); + if (!success) + { + return false; + } + } + } + } + + return success; + } + + public boolean hasSinglePermission(Set authorisations, NodeRef nodeRef) + { + // Check global permission + + if (checkGlobalPermissions(authorisations)) + { + return true; + } + + Set> denied = new HashSet>(); + + // Keep track of permission that are denied + + // Permissions are only evaluated up the primary parent chain + // TODO: Do not ignore non primary permissions + ChildAssociationRef car = nodeService.getPrimaryParent(nodeRef); + // Work up the parent chain evaluating permissions. + while (car != null) + { + // Add any denied permission to the denied list - these can not + // then + // be used to given authentication. + // A -> B -> C + // If B denies all permissions to any - allowing all permissions + // to + // andy at node A has no effect + + denied.addAll(getDenied(car.getChildRef())); + + // If the current node allows the permission we are done + // The test includes any parent or ancestor requirements + if (checkRequired(authorisations, car.getChildRef(), denied)) + { + return true; + } + + // Build the next element of the evaluation chain + if (car.getParentRef() != null) + { + NodePermissionEntry nodePermissions = permissionsDaoComponent.getPermissions(car.getChildRef()); + if ((nodePermissions == null) || (nodePermissions.inheritPermissions())) + { + car = nodeService.getPrimaryParent(car.getParentRef()); + } + else + { + car = null; + } + } + else + { + car = null; + } + + } + + // TODO: Support meta data permissions on the root node? + + return false; + + } + + /** + * Check if we have a global permission + * + * @param authorisations + * @return + */ + private boolean checkGlobalPermissions(Set authorisations) + { + for (PermissionEntry pe : modelDAO.getGlobalPermissionEntries()) + { + if (isGranted(pe, authorisations, null)) + { + return true; + } + } + return false; + } + + /** + * Get the list of permissions denied for this node. + * + * @param nodeRef + * @return + */ + Set> getDenied(NodeRef nodeRef) + { + Set> deniedSet = new HashSet>(); + + // Loop over all denied permissions + NodePermissionEntry nodeEntry = permissionsDaoComponent.getPermissions(nodeRef); + if (nodeEntry != null) + { + for (PermissionEntry pe : nodeEntry.getPermissionEntries()) + { + if (pe.isDenied()) + { + // All the sets that grant this permission must be + // denied + // Note that granters includes the orginal permission + Set granters = modelDAO + .getGrantingPermissions(pe.getPermissionReference()); + for (PermissionReference granter : granters) + { + deniedSet.add(new Pair(pe.getAuthority(), granter)); + } + + // All the things granted by this permission must be + // denied + Set grantees = modelDAO.getGranteePermissions(pe.getPermissionReference()); + for (PermissionReference grantee : grantees) + { + deniedSet.add(new Pair(pe.getAuthority(), grantee)); + } + + // All permission excludes all permissions available for + // the node. + if (pe.getPermissionReference().equals(getAllPermissionReference()) || pe.getPermissionReference().equals(OLD_ALL_PERMISSIONS_REFERENCE)) + { + for (PermissionReference deny : modelDAO.getAllPermissions(nodeRef)) + { + deniedSet.add(new Pair(pe.getAuthority(), deny)); + } + } + } + } + } + return deniedSet; + } + + /** + * Check that a given authentication is available on a node + * + * @param authorisations + * @param nodeRef + * @param denied + * @return + */ + boolean checkRequired(Set authorisations, NodeRef nodeRef, Set> denied) + { + NodePermissionEntry nodeEntry = permissionsDaoComponent.getPermissions(nodeRef); + + // No permissions set - short cut to deny + if (nodeEntry == null) + { + return false; + } + + // Check if each permission allows - the first wins. + // We could have other voting style mechanisms here + for (PermissionEntry pe : nodeEntry.getPermissionEntries()) + { + if (isGranted(pe, authorisations, denied)) + { + return true; + } + } + return false; + } + + /** + * Is a permission granted + * + * @param pe - + * the permissions entry to consider + * @param granters - + * the set of granters + * @param authorisations - + * the set of authorities + * @param denied - + * the set of denied permissions/authority pais + * @return + */ + private boolean isGranted(PermissionEntry pe, Set authorisations, + Set> denied) + { + // If the permission entry denies then we just deny + if (pe.isDenied()) + { + return false; + } + + // The permission is allowed but we deny it as it is in the denied + // set + if (denied != null) + { + Pair specific = new Pair(pe.getAuthority(), + required); + if (denied.contains(specific)) + { + return false; + } + } + + // If the permission has a match in both the authorities and + // granters list it is allowed + // It applies to the current user and it is granted + if (authorisations.contains(pe.getAuthority()) && granters.contains(pe.getPermissionReference())) + { + { + return true; + } + } + + // Default deny + return false; + } + + } + + /** + * Helper class to store a pair of objects which may be null + * + * @author Andy Hind + */ + private static class Pair + { + A a; + + B b; + + Pair(A a, B b) + { + this.a = a; + this.b = b; + } + + A getA() + { + return a; + } + + B getB() + { + return b; + } + + @Override + public boolean equals(Object o) + { + if (this == o) + { + return true; + } + if (!(this instanceof Pair)) + { + return false; + } + Pair other = (Pair) o; + return EqualsHelper.nullSafeEquals(this.getA(), other.getA()) + && EqualsHelper.nullSafeEquals(this.getB(), other.getB()); + } + + @Override + public int hashCode() + { + return (((a == null) ? 0 : a.hashCode()) * 37) + ((b == null) ? 0 : b.hashCode()); + } + + } + + private static class MutableBoolean + { + private boolean value; + + MutableBoolean(boolean value) + { + this.value = value; + } + + void setValue(boolean value) + { + this.value = value; + } + + boolean getValue() + { + return value; + } + } +} diff --git a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java index 4a620b9173..d03bc09118 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java @@ -1,1825 +1,1839 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.security.permissions.impl; - -import java.util.HashSet; -import java.util.Set; - -import net.sf.acegisecurity.Authentication; -import net.sf.acegisecurity.GrantedAuthority; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.security.permissions.PermissionEntry; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.security.AccessPermission; -import org.alfresco.service.cmr.security.AccessStatus; -import org.alfresco.service.cmr.security.AuthorityType; -import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.namespace.QName; - -public class PermissionServiceTest extends AbstractPermissionTest -{ - private SimplePermissionEntry denyAndyAll; - - private SimplePermissionEntry allowAndyAll; - - private SimplePermissionEntry denyAndyRead; - - private SimplePermissionEntry allowAndyRead; - - private SimplePermissionEntry denyAndyReadProperties; - - private SimplePermissionEntry allowAndyReadProperties; - - private SimplePermissionEntry allowAndyReadChildren; - - public PermissionServiceTest() - { - super(); - // TODO Auto-generated constructor stub - } - - public void testAuthenticatedRoleIsPresent() - { - runAs("andy"); - Authentication auth = authenticationComponent.getCurrentAuthentication(); - for (GrantedAuthority authority : auth.getAuthorities()) - { - if (authority.getAuthority().equals(ROLE_AUTHENTICATED)) { return; } - } - fail("Missing role ROLE_AUTHENTICATED "); - } - - @Override - protected void onSetUpInTransaction() throws Exception - { - super.onSetUpInTransaction(); - denyAndyAll = new SimplePermissionEntry(rootNodeRef, permissionService.getAllPermissionReference(), "andy", - AccessStatus.DENIED); - allowAndyAll = new SimplePermissionEntry(rootNodeRef, permissionService.getAllPermissionReference(), "andy", - AccessStatus.ALLOWED); - denyAndyRead = new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), "andy", - AccessStatus.DENIED); - allowAndyRead = new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), "andy", - AccessStatus.ALLOWED); - denyAndyReadProperties = new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.DENIED); - allowAndyReadProperties = new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED); - allowAndyReadChildren = new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ_CHILDREN), - "andy", AccessStatus.ALLOWED); - } - - public void testGetAllSetPermissions() - { - runAs("andy"); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.DELETE), - "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.DELETE), - "GROUP_GREEN", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - "GROUP_RED", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(systemNodeRef, - getPermission(PermissionService.DELETE), "andy", AccessStatus.DENIED)); - permissionService.setPermission(new SimplePermissionEntry(systemNodeRef, - getPermission(PermissionService.DELETE), "GROUP_GREEN", AccessStatus.DENIED)); - - NodeRef current = systemNodeRef; - Set setPermissions = new HashSet(); - while (current != null) - { - Set morePermissions = permissionService.getAllSetPermissions(current); - for (AccessPermission toTest : morePermissions) - { - if (toTest.getAuthorityType() == AuthorityType.GROUP) - { - boolean add = true; - for (AccessPermission existing : setPermissions) - { - if (add - && existing.getAuthority().equals(toTest.getAuthority()) - && existing.getPermission().equals(toTest.getPermission())) - { - add = false; - } - - } - if (add) - { - setPermissions.add(toTest); - } - } - } - if (permissionService.getInheritParentPermissions(current)) - { - current = nodeService.getPrimaryParent(current).getParentRef(); - } - else - { - current = null; - } - } - assertEquals(2, setPermissions.size()); - - } - - public void testPermissionCacheOnMove() - { - runAs("admin"); - - NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, - QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef n2 = nodeService.createNode(n1, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}two"), - ContentModel.TYPE_FOLDER).getChildRef(); - - permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ), "andy", - AccessStatus.ALLOWED)); - - runAs("andy"); - - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - - runAs("admin"); - nodeService.moveNode(n2, rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}oneMoved")); - - runAs("andy"); - - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.DENIED); - } - - public void testSetInheritFalse() - { - runAs("andy"); - permissionService.setInheritParentPermissions(rootNodeRef, false); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertFalse(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(0, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - } - - public void testSetInheritTrue() - { - runAs("andy"); - permissionService.setInheritParentPermissions(rootNodeRef, true); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(0, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - permissionService.deletePermissions(permissionService.getSetPermissions(rootNodeRef)); - } - - public void testAlterInherit() - { - runAs("andy"); - testSetInheritFalse(); - testSetInheritTrue(); - testSetInheritFalse(); - testSetInheritTrue(); - - permissionService.deletePermissions(rootNodeRef); - // testUnset(); - } - - public void testSetNodePermissionEntry() - { - runAs("andy"); - Set entries = new HashSet(); - entries.add(new SimplePermissionEntry(rootNodeRef, new SimplePermissionReference(QName.createQName("A", "B"), - "C"), "user-one", AccessStatus.ALLOWED)); - entries.add(new SimplePermissionEntry(rootNodeRef, permissionService.getAllPermissionReference(), "user-two", - AccessStatus.ALLOWED)); - entries.add(new SimplePermissionEntry(rootNodeRef, new SimplePermissionReference(QName.createQName("D", "E"), - "F"), permissionService.getAllAuthorities(), AccessStatus.ALLOWED)); - entries.add(new SimplePermissionEntry(rootNodeRef, permissionService.getAllPermissionReference(), - permissionService.getAllAuthorities(), AccessStatus.DENIED)); - - SimpleNodePermissionEntry entry = new SimpleNodePermissionEntry(rootNodeRef, false, entries); - - permissionService.setPermission(entry); - - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertFalse(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(4, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - } - - public void testSetNodePermissionEntry2() - { - Set entries = new HashSet(); - entries.add(new SimplePermissionEntry(rootNodeRef, permissionService.getAllPermissionReference(), - permissionService.getAllAuthorities(), AccessStatus.ALLOWED)); - - SimpleNodePermissionEntry entry = new SimpleNodePermissionEntry(rootNodeRef, false, entries); - - permissionService.setPermission(entry); - - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertFalse(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - } - - public void testAlterNodePermissions() - { - testSetNodePermissionEntry(); - testSetNodePermissionEntry2(); - testSetNodePermissionEntry(); - testSetNodePermissionEntry2(); - } - - public void testDoubleSetAllowDeny() - { - Set permissionEntries = null; - // add-remove andy-all - permissionService.setPermission(rootNodeRef, "andy", permissionService.getAllPermission(), true); - permissionService.setPermission(rootNodeRef, "andy", permissionService.getAllPermission(), false); - permissionService.deletePermission(rootNodeRef, "andy", permissionService.getAllPermission()); - permissionEntries = permissionService.getSetPermissions(rootNodeRef).getPermissionEntries(); - assertEquals(0, permissionEntries.size()); - // add-remove andy-read - permissionService.setPermission(rootNodeRef, "andy", PermissionService.READ, true); - permissionService.setPermission(rootNodeRef, "andy", PermissionService.READ, false); - permissionService.deletePermission(rootNodeRef, "andy", PermissionService.READ); - permissionEntries = permissionService.getSetPermissions(rootNodeRef).getPermissionEntries(); - assertEquals(0, permissionEntries.size()); - } - - public void testSetPermissionEntryElements() - { - // add andy-all (allow) - permissionService.setPermission(rootNodeRef, "andy", permissionService.getAllPermission(), true); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - for (PermissionEntry pe : permissionService.getSetPermissions(rootNodeRef).getPermissionEntries()) - { - assertEquals("andy", pe.getAuthority()); - assertTrue(pe.isAllowed()); - assertTrue(pe.getPermissionReference().getQName().equals( - permissionService.getAllPermissionReference().getQName())); - assertTrue(pe.getPermissionReference().getName().equals( - permissionService.getAllPermissionReference().getName())); - assertEquals(rootNodeRef, pe.getNodeRef()); - } - - // add andy-all (allow) - permissionService.setPermission(rootNodeRef, "andy", permissionService.getAllPermission(), true); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - // add other-all (allow) - permissionService.setPermission(rootNodeRef, "other", permissionService.getAllPermission(), true); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(2, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - // add andy-all (deny) - permissionService.setPermission(rootNodeRef, "andy", permissionService.getAllPermission(), false); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(2, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - // add andy-read (deny) - permissionService.setPermission(rootNodeRef, "andy", PermissionService.READ, false); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(3, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - // remove andy-read - permissionService.deletePermission(rootNodeRef, "andy", PermissionService.READ); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(2, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - // remove andy-all - permissionService.deletePermission(rootNodeRef, "andy", permissionService.getAllPermission()); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - // remove other-all - permissionService.deletePermission(rootNodeRef, "other", permissionService.getAllPermission()); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(0, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - } - - public void testSetPermissionEntry() - { - permissionService.setPermission(allowAndyAll); - permissionService.setPermission(rootNodeRef, "andy", permissionService.getAllPermission(), true); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - for (PermissionEntry pe : permissionService.getSetPermissions(rootNodeRef).getPermissionEntries()) - { - assertEquals("andy", pe.getAuthority()); - assertTrue(pe.isAllowed()); - assertTrue(pe.getPermissionReference().getQName().equals( - permissionService.getAllPermissionReference().getQName())); - assertTrue(pe.getPermissionReference().getName().equals( - permissionService.getAllPermissionReference().getName())); - assertEquals(rootNodeRef, pe.getNodeRef()); - } - - // Set duplicate - - permissionService.setPermission(allowAndyAll); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - // Set new - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, permissionService - .getAllPermissionReference(), "other", AccessStatus.ALLOWED)); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(2, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - // Deny - - permissionService.setPermission(denyAndyAll); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(2, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - // new - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, new SimplePermissionReference(QName - .createQName("A", "B"), "C"), "andy", AccessStatus.DENIED)); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(3, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, new SimplePermissionReference(QName - .createQName("A", "B"), "C"), "andy", AccessStatus.DENIED)); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(2, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - permissionService.deletePermission(denyAndyAll); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, permissionService - .getAllPermissionReference(), "other", AccessStatus.ALLOWED)); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(0, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - - // delete when we know there's nothing do delete - permissionService.deletePermission(allowAndyAll); - assertNotNull(permissionService.getSetPermissions(rootNodeRef)); - assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); - assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); - assertEquals(0, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); - } - - public void testGetSettablePermissionsForType() - { - Set answer = permissionService.getSettablePermissions(QName.createQName("sys", "base", - namespacePrefixResolver)); - assertEquals(21, answer.size()); - - answer = permissionService.getSettablePermissions(QName.createQName("cm", "ownable", namespacePrefixResolver)); - assertEquals(0, answer.size()); - - answer = permissionService.getSettablePermissions(QName.createQName("cm", "content", namespacePrefixResolver)); - assertEquals(5, answer.size()); - - answer = permissionService.getSettablePermissions(QName.createQName("cm", "folder", namespacePrefixResolver)); - assertEquals(5, answer.size()); - } - - public void testGetSettablePermissionsForNode() - { - QName ownable = QName.createQName("cm", "ownable", namespacePrefixResolver); - - Set answer = permissionService.getSettablePermissions(rootNodeRef); - assertEquals(25, answer.size()); - - nodeService.addAspect(rootNodeRef, ownable, null); - answer = permissionService.getSettablePermissions(rootNodeRef); - assertEquals(25, answer.size()); - - nodeService.removeAspect(rootNodeRef, ownable); - answer = permissionService.getSettablePermissions(rootNodeRef); - assertEquals(25, answer.size()); - } - - public void testSimplePermissionOnRoot() - { - runAs("andy"); - - assertEquals(25, permissionService.getPermissions(rootNodeRef).size()); - assertEquals(0, countGranted(permissionService.getPermissions(rootNodeRef))); - assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); - - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); - assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); - runAs("andy"); - - assertEquals(25, permissionService.getPermissions(rootNodeRef).size()); - assertEquals(1, countGranted(permissionService.getPermissions(rootNodeRef))); - - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.DENIED)); - assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); - assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - - permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.DENIED)); - assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - - permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); - assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - } - - private int countGranted(Set permissions) - { - int count = 0; - for (AccessPermission ap : permissions) - { - if (ap.getAccessStatus() == AccessStatus.ALLOWED) - { - count++; - } - } - return count; - } - - public void testGlobalPermissionsForAdmin() - { - runAs("admin"); - NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, - QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); - - NodeRef n2 = nodeService.createNode(n1, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}two"), - ContentModel.TYPE_CONTENT).getChildRef(); - - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - "admin", AccessStatus.DENIED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_PROPERTIES), "admin", AccessStatus.DENIED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_CHILDREN), "admin", AccessStatus.DENIED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_CONTENT), "admin", AccessStatus.DENIED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.ALL_PERMISSIONS), "admin", AccessStatus.DENIED)); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - } - - public void testPermissionGroupOnRoot() - { - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); - permissionService.setPermission(allowAndyRead); - runAs("andy"); - - assertEquals(25, permissionService.getPermissions(rootNodeRef).size()); - assertEquals(4, countGranted(permissionService.getPermissions(rootNodeRef))); - assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); - - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(denyAndyRead); - runAs("andy"); - assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.deletePermission(allowAndyRead); - runAs("andy"); - assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("andy"); - } - - public void testSimplePermissionSimpleInheritance() - { - runAs("admin"); - - NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, - QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); - - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - - assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); - permissionService.setPermission(allowAndyReadProperties); - runAs("andy"); - assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - // Changed ny not enfocing READ - // assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - // assertFalse(permissionService.hasPermission(n1, - // getPermission(PermissionService.READ_PROPERTIES)) == - // AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - - permissionService.setPermission(allowAndyReadChildren); - assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - - permissionService.setPermission(denyAndyReadProperties); - assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - - permissionService.deletePermission(allowAndyReadChildren); - assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - - permissionService.deletePermission(allowAndyReadProperties); - assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - } - - public void testPermissionGroupSimpleInheritance() - { - runAs("admin"); - - NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, - QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); - - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(allowAndyRead); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(denyAndyRead); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.deletePermission(allowAndyRead); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - } - - public void testDenySimplePermisionOnRootNode() - { - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - - permissionService.setPermission(allowAndyReadProperties); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - - permissionService.setPermission(denyAndyReadProperties); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - - permissionService.deletePermission(allowAndyReadProperties); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - } - - public void testDenyPermissionOnRootNOde() - { - - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(allowAndyRead); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(denyAndyRead); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.deletePermission(allowAndyRead); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - } - - public void testComplexDenyOnRootNode() - { - - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(allowAndyRead); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(denyAndyReadProperties); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(allowAndyReadChildren); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(denyAndyRead); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - } - - public void testPerf() throws Exception - { - runAs("admin"); - - // TransactionService transactionService = serviceRegistry.getTransactionService(); - // UserTransaction tx = transactionService.getUserTransaction(); - // tx.begin(); - - NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, - QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef n2 = nodeService.createNode(n1, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}two"), - ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef n3 = nodeService.createNode(n2, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}three"), - ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef n4 = nodeService.createNode(n3, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}four"), - ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef n5 = nodeService.createNode(n4, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}five"), - ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef n6 = nodeService.createNode(n5, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}six"), - ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef n7 = nodeService.createNode(n6, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}seven"), - ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef n8 = nodeService.createNode(n7, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}eight"), - ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef n9 = nodeService.createNode(n8, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}nine"), - ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef n10 = nodeService.createNode(n9, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}ten"), - ContentModel.TYPE_FOLDER).getChildRef(); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - "andy", AccessStatus.ALLOWED)); - // permissionService.setPermission(new SimplePermissionEntry(n9, - // getPermission(PermissionService.READ), - // "andy", AccessStatus.ALLOWED)); - // permissionService.setPermission(new SimplePermissionEntry(n10, - // getPermission(PermissionService.READ), - // "andy", AccessStatus.ALLOWED)); - - long start; - long end; - long time = 0; - for (int i = 0; i < 1000; i++) - { - getSession().flush(); - // getSession().clear(); - start = System.nanoTime(); - assertTrue(permissionService.hasPermission(n10, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - end = System.nanoTime(); - time += (end - start); - } - System.out.println("Time is " + (time / 1000000000.0)); - // assertTrue((time / 1000000000.0) < 60.0); - - time = 0; - for (int i = 0; i < 1000; i++) - { - start = System.nanoTime(); - assertTrue(permissionService.hasPermission(n10, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - end = System.nanoTime(); - time += (end - start); - } - System.out.println("Time is " + (time / 1000000000.0)); - // assertTrue((time / 1000000000.0) < 2.0); - - // tx.rollback(); - } - - public void testAllPermissions() - { - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); - - permissionService.setPermission(allowAndyAll); - assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(denyAndyRead); - runAs("andy"); - assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(denyAndyAll); - assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - } - - public void testOldAllPermissions() - { - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE, "andy", AccessStatus.ALLOWED)); - assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(denyAndyRead); - runAs("andy"); - assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(denyAndyAll); - assertEquals(3, permissionService.getAllSetPermissions(rootNodeRef).size()); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - } - - public void testAuthenticatedAuthority() - { - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - ROLE_AUTHENTICATED, AccessStatus.ALLOWED)); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - ROLE_AUTHENTICATED, AccessStatus.DENIED)); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ), ROLE_AUTHENTICATED, AccessStatus.ALLOWED)); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - } - - public void testAllAuthorities() - { - - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - permissionService.getAllAuthorities(), AccessStatus.ALLOWED)); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - permissionService.getAllAuthorities(), AccessStatus.DENIED)); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ), permissionService.getAllAuthorities(), AccessStatus.ALLOWED)); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - } - - public void testAllPermissionsAllAuthorities() - { - - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, permissionService - .getAllPermissionReference(), permissionService.getAllAuthorities(), AccessStatus.ALLOWED)); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - permissionService.getAllAuthorities(), AccessStatus.DENIED)); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, permissionService - .getAllPermissionReference(), permissionService.getAllAuthorities(), AccessStatus.DENIED)); - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - } - - public void testGroupAndUserInteraction() - { - - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - "andy", AccessStatus.ALLOWED)); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - ROLE_AUTHENTICATED, AccessStatus.ALLOWED)); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.DENIED)); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - "andy", AccessStatus.DENIED)); - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - } - - public void testInheritPermissions() - { - runAs("admin"); - NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, - QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef n2 = nodeService.createNode(n1, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}two"), - ContentModel.TYPE_FOLDER).getChildRef(); - - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ), "andy", - AccessStatus.ALLOWED)); - - runAs("andy"); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setInheritParentPermissions(n2, false); - - runAs("andy"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setInheritParentPermissions(n2, true); - - runAs("andy"); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - } - - public void testAncestorRequirementAndInheritance() - { - runAs("admin"); - - NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, - QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef n2 = nodeService.createNode(n1, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}two"), - ContentModel.TYPE_FOLDER).getChildRef(); - - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ_CHILDREN), - "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_PROPERTIES), - "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_CONTENT), - "andy", AccessStatus.ALLOWED)); - - runAs("andy"); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ_CHILDREN), - "andy", AccessStatus.DENIED)); - permissionService.setInheritParentPermissions(n2, false); - - runAs("andy"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setInheritParentPermissions(n2, true); - - runAs("andy"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - // Changed by removing permission read parents access - // assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - } - - public void testPermissionCase() - { - - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_CHILDREN), "Andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_PROPERTIES), "ANDY", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_CONTENT), "AnDy", AccessStatus.ALLOWED)); - - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - -// permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, -// getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); -// permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, -// getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); -// permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, -// getPermission(PermissionService.READ_CONTENT), "andy", AccessStatus.ALLOWED)); -// -// -// runAs("andy"); -// assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); -// assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); -// assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); -// assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); -// runAs("lemur"); -// assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); -// assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); -// assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); -// assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - } - - public void testEffectiveComposite() - { - - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_CONTENT), "andy", AccessStatus.ALLOWED)); - - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - } - - public void testContentPermissions() - { - runAs("admin"); - - NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, - QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); - NodeRef n2 = nodeService.createNode(n1, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}two"), - ContentModel.TYPE_CONTENT).getChildRef(); - - runAs("andy"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ_CHILDREN), - "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_CHILDREN), - "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_PROPERTIES), - "andy", AccessStatus.ALLOWED)); - - runAs("andy"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_CONTENT), - "andy", AccessStatus.ALLOWED)); - - runAs("andy"); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.deletePermission(new SimplePermissionEntry(n2, - getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); - permissionService.deletePermission(new SimplePermissionEntry(n2, - getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); - permissionService.deletePermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_CONTENT), - "andy", AccessStatus.ALLOWED)); - - runAs("andy"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ), "andy", - AccessStatus.ALLOWED)); - - runAs("andy"); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - } - - public void testAllPermissionSet() - { - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.FULL_CONTROL), "andy", AccessStatus.ALLOWED)); - - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.FULL_CONTROL), "andy", AccessStatus.DENIED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); - - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.FULL_CONTROL), "andy", AccessStatus.DENIED)); - - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); - - } - - public void testChildrenRequirements() - { - if (!personService.createMissingPeople()) - { - assertEquals(1, nodeService.getChildAssocs(rootNodeRef).size()); - } - runAs("andy"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - "andy", AccessStatus.ALLOWED)); - - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.DELETE), - "andy", AccessStatus.ALLOWED)); - - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); - - runAs("andy"); - assertTrue(permissionService.hasPermission(systemNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(systemNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(systemNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(systemNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(systemNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(systemNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); - - permissionService.setPermission(new SimplePermissionEntry(systemNodeRef, - getPermission(PermissionService.DELETE), "andy", AccessStatus.DENIED)); - - runAs("andy"); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); - // The following are now true as we have no cascade delete check - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); - assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); - runAs("lemur"); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); - assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); - - } - - public void testClearPermission() - { - assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - "andy", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); - assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), - "lemur", AccessStatus.ALLOWED)); - permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, - getPermission(PermissionService.READ_CHILDREN), "lemur", AccessStatus.ALLOWED)); - assertEquals(4, permissionService.getAllSetPermissions(rootNodeRef).size()); - - permissionService.clearPermission(rootNodeRef, "andy"); - assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); - permissionService.clearPermission(rootNodeRef, "lemur"); - assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); - - } - - // TODO: Test permissions on missing nodes - -} +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.security.permissions.impl; + +import java.util.HashSet; +import java.util.Set; + +import net.sf.acegisecurity.Authentication; +import net.sf.acegisecurity.GrantedAuthority; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.permissions.PermissionEntry; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.security.AccessPermission; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.AuthorityType; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.QName; + +public class PermissionServiceTest extends AbstractPermissionTest +{ + private SimplePermissionEntry denyAndyAll; + + private SimplePermissionEntry allowAndyAll; + + private SimplePermissionEntry denyAndyRead; + + private SimplePermissionEntry allowAndyRead; + + private SimplePermissionEntry denyAndyReadProperties; + + private SimplePermissionEntry allowAndyReadProperties; + + private SimplePermissionEntry allowAndyReadChildren; + + public PermissionServiceTest() + { + super(); + // TODO Auto-generated constructor stub + } + + public void testAuthenticatedRoleIsPresent() + { + runAs("andy"); + Authentication auth = authenticationComponent.getCurrentAuthentication(); + for (GrantedAuthority authority : auth.getAuthorities()) + { + if (authority.getAuthority().equals(ROLE_AUTHENTICATED)) { return; } + } + fail("Missing role ROLE_AUTHENTICATED "); + } + + @Override + protected void onSetUpInTransaction() throws Exception + { + super.onSetUpInTransaction(); + denyAndyAll = new SimplePermissionEntry(rootNodeRef, permissionService.getAllPermissionReference(), "andy", + AccessStatus.DENIED); + allowAndyAll = new SimplePermissionEntry(rootNodeRef, permissionService.getAllPermissionReference(), "andy", + AccessStatus.ALLOWED); + denyAndyRead = new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), "andy", + AccessStatus.DENIED); + allowAndyRead = new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), "andy", + AccessStatus.ALLOWED); + denyAndyReadProperties = new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.DENIED); + allowAndyReadProperties = new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED); + allowAndyReadChildren = new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ_CHILDREN), + "andy", AccessStatus.ALLOWED); + } + + public void testWeSetConsumerOnRootIsNotSupportedByHasPermisssionAsItIsTheWrongType() + { + runAs("andy"); + assertEquals(0, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.CONSUMER), + "andy", AccessStatus.ALLOWED)); + assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + assertEquals(permissionService.hasPermission(rootNodeRef, (PermissionService.CONSUMER)), AccessStatus.DENIED); + } + + public void testGetAllSetPermissions() + { + runAs("andy"); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.DELETE), + "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.DELETE), + "GROUP_GREEN", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + "GROUP_RED", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(systemNodeRef, + getPermission(PermissionService.DELETE), "andy", AccessStatus.DENIED)); + permissionService.setPermission(new SimplePermissionEntry(systemNodeRef, + getPermission(PermissionService.DELETE), "GROUP_GREEN", AccessStatus.DENIED)); + + NodeRef current = systemNodeRef; + Set setPermissions = new HashSet(); + while (current != null) + { + Set morePermissions = permissionService.getAllSetPermissions(current); + for (AccessPermission toTest : morePermissions) + { + if (toTest.getAuthorityType() == AuthorityType.GROUP) + { + boolean add = true; + for (AccessPermission existing : setPermissions) + { + if (add + && existing.getAuthority().equals(toTest.getAuthority()) + && existing.getPermission().equals(toTest.getPermission())) + { + add = false; + } + + } + if (add) + { + setPermissions.add(toTest); + } + } + } + if (permissionService.getInheritParentPermissions(current)) + { + current = nodeService.getPrimaryParent(current).getParentRef(); + } + else + { + current = null; + } + } + assertEquals(2, setPermissions.size()); + + } + + public void testPermissionCacheOnMove() + { + runAs("admin"); + + NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, + QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n2 = nodeService.createNode(n1, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}two"), + ContentModel.TYPE_FOLDER).getChildRef(); + + permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ), "andy", + AccessStatus.ALLOWED)); + + runAs("andy"); + + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + + runAs("admin"); + nodeService.moveNode(n2, rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}oneMoved")); + + runAs("andy"); + + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.DENIED); + } + + public void testSetInheritFalse() + { + runAs("andy"); + permissionService.setInheritParentPermissions(rootNodeRef, false); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertFalse(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(0, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + } + + public void testSetInheritTrue() + { + runAs("andy"); + permissionService.setInheritParentPermissions(rootNodeRef, true); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(0, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + permissionService.deletePermissions(permissionService.getSetPermissions(rootNodeRef)); + } + + public void testAlterInherit() + { + runAs("andy"); + testSetInheritFalse(); + testSetInheritTrue(); + testSetInheritFalse(); + testSetInheritTrue(); + + permissionService.deletePermissions(rootNodeRef); + // testUnset(); + } + + public void testSetNodePermissionEntry() + { + runAs("andy"); + Set entries = new HashSet(); + entries.add(new SimplePermissionEntry(rootNodeRef, new SimplePermissionReference(QName.createQName("A", "B"), + "C"), "user-one", AccessStatus.ALLOWED)); + entries.add(new SimplePermissionEntry(rootNodeRef, permissionService.getAllPermissionReference(), "user-two", + AccessStatus.ALLOWED)); + entries.add(new SimplePermissionEntry(rootNodeRef, new SimplePermissionReference(QName.createQName("D", "E"), + "F"), permissionService.getAllAuthorities(), AccessStatus.ALLOWED)); + entries.add(new SimplePermissionEntry(rootNodeRef, permissionService.getAllPermissionReference(), + permissionService.getAllAuthorities(), AccessStatus.DENIED)); + + SimpleNodePermissionEntry entry = new SimpleNodePermissionEntry(rootNodeRef, false, entries); + + permissionService.setPermission(entry); + + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertFalse(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(4, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + } + + public void testSetNodePermissionEntry2() + { + Set entries = new HashSet(); + entries.add(new SimplePermissionEntry(rootNodeRef, permissionService.getAllPermissionReference(), + permissionService.getAllAuthorities(), AccessStatus.ALLOWED)); + + SimpleNodePermissionEntry entry = new SimpleNodePermissionEntry(rootNodeRef, false, entries); + + permissionService.setPermission(entry); + + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertFalse(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + } + + public void testAlterNodePermissions() + { + testSetNodePermissionEntry(); + testSetNodePermissionEntry2(); + testSetNodePermissionEntry(); + testSetNodePermissionEntry2(); + } + + public void testDoubleSetAllowDeny() + { + Set permissionEntries = null; + // add-remove andy-all + permissionService.setPermission(rootNodeRef, "andy", permissionService.getAllPermission(), true); + permissionService.setPermission(rootNodeRef, "andy", permissionService.getAllPermission(), false); + permissionService.deletePermission(rootNodeRef, "andy", permissionService.getAllPermission()); + permissionEntries = permissionService.getSetPermissions(rootNodeRef).getPermissionEntries(); + assertEquals(0, permissionEntries.size()); + // add-remove andy-read + permissionService.setPermission(rootNodeRef, "andy", PermissionService.READ, true); + permissionService.setPermission(rootNodeRef, "andy", PermissionService.READ, false); + permissionService.deletePermission(rootNodeRef, "andy", PermissionService.READ); + permissionEntries = permissionService.getSetPermissions(rootNodeRef).getPermissionEntries(); + assertEquals(0, permissionEntries.size()); + } + + public void testSetPermissionEntryElements() + { + // add andy-all (allow) + permissionService.setPermission(rootNodeRef, "andy", permissionService.getAllPermission(), true); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + for (PermissionEntry pe : permissionService.getSetPermissions(rootNodeRef).getPermissionEntries()) + { + assertEquals("andy", pe.getAuthority()); + assertTrue(pe.isAllowed()); + assertTrue(pe.getPermissionReference().getQName().equals( + permissionService.getAllPermissionReference().getQName())); + assertTrue(pe.getPermissionReference().getName().equals( + permissionService.getAllPermissionReference().getName())); + assertEquals(rootNodeRef, pe.getNodeRef()); + } + + // add andy-all (allow) + permissionService.setPermission(rootNodeRef, "andy", permissionService.getAllPermission(), true); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + // add other-all (allow) + permissionService.setPermission(rootNodeRef, "other", permissionService.getAllPermission(), true); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(2, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + // add andy-all (deny) + permissionService.setPermission(rootNodeRef, "andy", permissionService.getAllPermission(), false); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(2, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + // add andy-read (deny) + permissionService.setPermission(rootNodeRef, "andy", PermissionService.READ, false); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(3, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + // remove andy-read + permissionService.deletePermission(rootNodeRef, "andy", PermissionService.READ); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(2, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + // remove andy-all + permissionService.deletePermission(rootNodeRef, "andy", permissionService.getAllPermission()); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + // remove other-all + permissionService.deletePermission(rootNodeRef, "other", permissionService.getAllPermission()); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(0, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + } + + public void testSetPermissionEntry() + { + permissionService.setPermission(allowAndyAll); + permissionService.setPermission(rootNodeRef, "andy", permissionService.getAllPermission(), true); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + for (PermissionEntry pe : permissionService.getSetPermissions(rootNodeRef).getPermissionEntries()) + { + assertEquals("andy", pe.getAuthority()); + assertTrue(pe.isAllowed()); + assertTrue(pe.getPermissionReference().getQName().equals( + permissionService.getAllPermissionReference().getQName())); + assertTrue(pe.getPermissionReference().getName().equals( + permissionService.getAllPermissionReference().getName())); + assertEquals(rootNodeRef, pe.getNodeRef()); + } + + // Set duplicate + + permissionService.setPermission(allowAndyAll); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + // Set new + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, permissionService + .getAllPermissionReference(), "other", AccessStatus.ALLOWED)); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(2, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + // Deny + + permissionService.setPermission(denyAndyAll); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(2, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + // new + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, new SimplePermissionReference(QName + .createQName("A", "B"), "C"), "andy", AccessStatus.DENIED)); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(3, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, new SimplePermissionReference(QName + .createQName("A", "B"), "C"), "andy", AccessStatus.DENIED)); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(2, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + permissionService.deletePermission(denyAndyAll); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(1, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, permissionService + .getAllPermissionReference(), "other", AccessStatus.ALLOWED)); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(0, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + + // delete when we know there's nothing do delete + permissionService.deletePermission(allowAndyAll); + assertNotNull(permissionService.getSetPermissions(rootNodeRef)); + assertTrue(permissionService.getSetPermissions(rootNodeRef).inheritPermissions()); + assertEquals(rootNodeRef, permissionService.getSetPermissions(rootNodeRef).getNodeRef()); + assertEquals(0, permissionService.getSetPermissions(rootNodeRef).getPermissionEntries().size()); + } + + public void testGetSettablePermissionsForType() + { + Set answer = permissionService.getSettablePermissions(QName.createQName("sys", "base", + namespacePrefixResolver)); + assertEquals(36, answer.size()); + + answer = permissionService.getSettablePermissions(QName.createQName("cm", "ownable", namespacePrefixResolver)); + assertEquals(0, answer.size()); + + answer = permissionService.getSettablePermissions(QName.createQName("cm", "content", namespacePrefixResolver)); + assertEquals(5, answer.size()); + + answer = permissionService.getSettablePermissions(QName.createQName("cm", "folder", namespacePrefixResolver)); + assertEquals(5, answer.size()); + + answer = permissionService.getSettablePermissions(QName.createQName("cm", "monkey", namespacePrefixResolver)); + assertEquals(0, answer.size()); + } + + + public void testGetSettablePermissionsForNode() + { + QName ownable = QName.createQName("cm", "ownable", namespacePrefixResolver); + + Set answer = permissionService.getSettablePermissions(rootNodeRef); + assertEquals(42, answer.size()); + + nodeService.addAspect(rootNodeRef, ownable, null); + answer = permissionService.getSettablePermissions(rootNodeRef); + assertEquals(42, answer.size()); + + nodeService.removeAspect(rootNodeRef, ownable); + answer = permissionService.getSettablePermissions(rootNodeRef); + assertEquals(42, answer.size()); + } + + public void testSimplePermissionOnRoot() + { + runAs("andy"); + + assertEquals(42, permissionService.getPermissions(rootNodeRef).size()); + assertEquals(0, countGranted(permissionService.getPermissions(rootNodeRef))); + assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); + + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); + assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); + runAs("andy"); + + assertEquals(42, permissionService.getPermissions(rootNodeRef).size()); + assertEquals(2, countGranted(permissionService.getPermissions(rootNodeRef))); + + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.DENIED)); + assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); + assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + + permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.DENIED)); + assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + + permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); + assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + } + + private int countGranted(Set permissions) + { + int count = 0; + for (AccessPermission ap : permissions) + { + if (ap.getAccessStatus() == AccessStatus.ALLOWED) + { + count++; + } + } + return count; + } + + public void testGlobalPermissionsForAdmin() + { + runAs("admin"); + NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, + QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + + NodeRef n2 = nodeService.createNode(n1, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}two"), + ContentModel.TYPE_CONTENT).getChildRef(); + + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + "admin", AccessStatus.DENIED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_PROPERTIES), "admin", AccessStatus.DENIED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_CHILDREN), "admin", AccessStatus.DENIED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_CONTENT), "admin", AccessStatus.DENIED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.ALL_PERMISSIONS), "admin", AccessStatus.DENIED)); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + } + + public void testPermissionGroupOnRoot() + { + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); + permissionService.setPermission(allowAndyRead); + runAs("andy"); + + assertEquals(42, permissionService.getPermissions(rootNodeRef).size()); + assertEquals(7, countGranted(permissionService.getPermissions(rootNodeRef))); + assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); + + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(denyAndyRead); + runAs("andy"); + assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.deletePermission(allowAndyRead); + runAs("andy"); + assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("andy"); + } + + public void testSimplePermissionSimpleInheritance() + { + runAs("admin"); + + NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, + QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + + assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); + permissionService.setPermission(allowAndyReadProperties); + runAs("andy"); + assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + // Changed ny not enfocing READ + // assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + // assertFalse(permissionService.hasPermission(n1, + // getPermission(PermissionService.READ_PROPERTIES)) == + // AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + + permissionService.setPermission(allowAndyReadChildren); + assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + + permissionService.setPermission(denyAndyReadProperties); + assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + + permissionService.deletePermission(allowAndyReadChildren); + assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + + permissionService.deletePermission(allowAndyReadProperties); + assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + } + + public void testPermissionGroupSimpleInheritance() + { + runAs("admin"); + + NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, + QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(allowAndyRead); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(denyAndyRead); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.deletePermission(allowAndyRead); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n1, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + } + + public void testDenySimplePermisionOnRootNode() + { + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + + permissionService.setPermission(allowAndyReadProperties); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + + permissionService.setPermission(denyAndyReadProperties); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + + permissionService.deletePermission(allowAndyReadProperties); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + } + + public void testDenyPermissionOnRootNOde() + { + + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(allowAndyRead); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(denyAndyRead); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.deletePermission(allowAndyRead); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + } + + public void testComplexDenyOnRootNode() + { + + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(allowAndyRead); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(denyAndyReadProperties); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(allowAndyReadChildren); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(denyAndyRead); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + } + + public void testPerf() throws Exception + { + runAs("admin"); + + // TransactionService transactionService = serviceRegistry.getTransactionService(); + // UserTransaction tx = transactionService.getUserTransaction(); + // tx.begin(); + + NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, + QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n2 = nodeService.createNode(n1, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}two"), + ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n3 = nodeService.createNode(n2, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}three"), + ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n4 = nodeService.createNode(n3, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}four"), + ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n5 = nodeService.createNode(n4, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}five"), + ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n6 = nodeService.createNode(n5, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}six"), + ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n7 = nodeService.createNode(n6, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}seven"), + ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n8 = nodeService.createNode(n7, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}eight"), + ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n9 = nodeService.createNode(n8, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}nine"), + ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n10 = nodeService.createNode(n9, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}ten"), + ContentModel.TYPE_FOLDER).getChildRef(); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + "andy", AccessStatus.ALLOWED)); + // permissionService.setPermission(new SimplePermissionEntry(n9, + // getPermission(PermissionService.READ), + // "andy", AccessStatus.ALLOWED)); + // permissionService.setPermission(new SimplePermissionEntry(n10, + // getPermission(PermissionService.READ), + // "andy", AccessStatus.ALLOWED)); + + long start; + long end; + long time = 0; + for (int i = 0; i < 1000; i++) + { + getSession().flush(); + // getSession().clear(); + start = System.nanoTime(); + assertTrue(permissionService.hasPermission(n10, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + end = System.nanoTime(); + time += (end - start); + } + System.out.println("Time is " + (time / 1000000000.0)); + // assertTrue((time / 1000000000.0) < 60.0); + + time = 0; + for (int i = 0; i < 1000; i++) + { + start = System.nanoTime(); + assertTrue(permissionService.hasPermission(n10, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + end = System.nanoTime(); + time += (end - start); + } + System.out.println("Time is " + (time / 1000000000.0)); + // assertTrue((time / 1000000000.0) < 2.0); + + // tx.rollback(); + } + + public void testAllPermissions() + { + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); + + permissionService.setPermission(allowAndyAll); + assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(denyAndyRead); + runAs("andy"); + assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(denyAndyAll); + assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + } + + public void testOldAllPermissions() + { + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE, "andy", AccessStatus.ALLOWED)); + assertEquals(1, permissionService.getAllSetPermissions(rootNodeRef).size()); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(denyAndyRead); + runAs("andy"); + assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(denyAndyAll); + assertEquals(3, permissionService.getAllSetPermissions(rootNodeRef).size()); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.ALL_PERMISSIONS)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, PermissionServiceImpl.OLD_ALL_PERMISSIONS_REFERENCE) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + } + + public void testAuthenticatedAuthority() + { + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + ROLE_AUTHENTICATED, AccessStatus.ALLOWED)); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + ROLE_AUTHENTICATED, AccessStatus.DENIED)); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ), ROLE_AUTHENTICATED, AccessStatus.ALLOWED)); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + } + + public void testAllAuthorities() + { + + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + permissionService.getAllAuthorities(), AccessStatus.ALLOWED)); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + permissionService.getAllAuthorities(), AccessStatus.DENIED)); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ), permissionService.getAllAuthorities(), AccessStatus.ALLOWED)); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + } + + public void testAllPermissionsAllAuthorities() + { + + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, permissionService + .getAllPermissionReference(), permissionService.getAllAuthorities(), AccessStatus.ALLOWED)); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + permissionService.getAllAuthorities(), AccessStatus.DENIED)); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, permissionService + .getAllPermissionReference(), permissionService.getAllAuthorities(), AccessStatus.DENIED)); + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.WRITE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + } + + public void testGroupAndUserInteraction() + { + + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + "andy", AccessStatus.ALLOWED)); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + ROLE_AUTHENTICATED, AccessStatus.ALLOWED)); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.DENIED)); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + "andy", AccessStatus.DENIED)); + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + } + + public void testInheritPermissions() + { + runAs("admin"); + NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, + QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n2 = nodeService.createNode(n1, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}two"), + ContentModel.TYPE_FOLDER).getChildRef(); + + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ), "andy", + AccessStatus.ALLOWED)); + + runAs("andy"); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setInheritParentPermissions(n2, false); + + runAs("andy"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setInheritParentPermissions(n2, true); + + runAs("andy"); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + } + + public void testAncestorRequirementAndInheritance() + { + runAs("admin"); + + NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, + QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n2 = nodeService.createNode(n1, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}two"), + ContentModel.TYPE_FOLDER).getChildRef(); + + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ_CHILDREN), + "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_PROPERTIES), + "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_CONTENT), + "andy", AccessStatus.ALLOWED)); + + runAs("andy"); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ_CHILDREN), + "andy", AccessStatus.DENIED)); + permissionService.setInheritParentPermissions(n2, false); + + runAs("andy"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setInheritParentPermissions(n2, true); + + runAs("andy"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + // Changed by removing permission read parents access + // assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + } + + public void testPermissionCase() + { + + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_CHILDREN), "Andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_PROPERTIES), "ANDY", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_CONTENT), "AnDy", AccessStatus.ALLOWED)); + + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + +// permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, +// getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); +// permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, +// getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); +// permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, +// getPermission(PermissionService.READ_CONTENT), "andy", AccessStatus.ALLOWED)); +// +// +// runAs("andy"); +// assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); +// assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); +// assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); +// assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); +// runAs("lemur"); +// assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); +// assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); +// assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); +// assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + } + + public void testEffectiveComposite() + { + + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_CONTENT), "andy", AccessStatus.ALLOWED)); + + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + } + + public void testContentPermissions() + { + runAs("admin"); + + NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, + QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + NodeRef n2 = nodeService.createNode(n1, ContentModel.ASSOC_CONTAINS, QName.createQName("{namespace}two"), + ContentModel.TYPE_CONTENT).getChildRef(); + + runAs("andy"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ_CHILDREN), + "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_CHILDREN), + "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_PROPERTIES), + "andy", AccessStatus.ALLOWED)); + + runAs("andy"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_CONTENT), + "andy", AccessStatus.ALLOWED)); + + runAs("andy"); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.deletePermission(new SimplePermissionEntry(n2, + getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); + permissionService.deletePermission(new SimplePermissionEntry(n2, + getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); + permissionService.deletePermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_CONTENT), + "andy", AccessStatus.ALLOWED)); + + runAs("andy"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ), "andy", + AccessStatus.ALLOWED)); + + runAs("andy"); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + } + + public void testAllPermissionSet() + { + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.FULL_CONTROL), "andy", AccessStatus.ALLOWED)); + + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.FULL_CONTROL), "andy", AccessStatus.DENIED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED)); + + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + permissionService.deletePermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.FULL_CONTROL), "andy", AccessStatus.DENIED)); + + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED); + + } + + public void testChildrenRequirements() + { + if (!personService.createMissingPeople()) + { + assertEquals(1, nodeService.getChildAssocs(rootNodeRef).size()); + } + runAs("andy"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + "andy", AccessStatus.ALLOWED)); + + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.DELETE), + "andy", AccessStatus.ALLOWED)); + + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); + + runAs("andy"); + assertTrue(permissionService.hasPermission(systemNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(systemNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(systemNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(systemNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(systemNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(systemNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); + + permissionService.setPermission(new SimplePermissionEntry(systemNodeRef, + getPermission(PermissionService.DELETE), "andy", AccessStatus.DENIED)); + + runAs("andy"); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); + // The following are now true as we have no cascade delete check + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED); + runAs("lemur"); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_CHILDREN)) == AccessStatus.ALLOWED); + assertFalse(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.DELETE_NODE)) == AccessStatus.ALLOWED); + + } + + public void testClearPermission() + { + assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + "andy", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); + assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, getPermission(PermissionService.READ), + "lemur", AccessStatus.ALLOWED)); + permissionService.setPermission(new SimplePermissionEntry(rootNodeRef, + getPermission(PermissionService.READ_CHILDREN), "lemur", AccessStatus.ALLOWED)); + assertEquals(4, permissionService.getAllSetPermissions(rootNodeRef).size()); + + permissionService.clearPermission(rootNodeRef, "andy"); + assertEquals(2, permissionService.getAllSetPermissions(rootNodeRef).size()); + permissionService.clearPermission(rootNodeRef, "lemur"); + assertEquals(0, permissionService.getAllSetPermissions(rootNodeRef).size()); + + } + + // TODO: Test permissions on missing nodes + +} diff --git a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java index e374595c68..e9a87a88f0 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java @@ -1,970 +1,966 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.security.permissions.impl.model; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -import org.alfresco.repo.security.permissions.PermissionEntry; -import org.alfresco.repo.security.permissions.PermissionReference; -import org.alfresco.repo.security.permissions.impl.ModelDAO; -import org.alfresco.repo.security.permissions.impl.RequiredPermission; -import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; -import org.alfresco.service.cmr.dictionary.AspectDefinition; -import org.alfresco.service.cmr.dictionary.ClassDefinition; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.dictionary.TypeDefinition; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.security.AccessStatus; -import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.namespace.DynamicNamespacePrefixResolver; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.dom4j.Attribute; -import org.dom4j.Document; -import org.dom4j.DocumentException; -import org.dom4j.Element; -import org.dom4j.io.SAXReader; -import org.springframework.beans.factory.InitializingBean; - -/** - * The implementation of the model DAO - * - * Reads and stores the top level model information - * - * Encapsulates access to this information - * - * @author andyh - */ -public class PermissionModel implements ModelDAO, InitializingBean -{ - // IOC - - private NodeService nodeService; - - private DictionaryService dictionaryService; - - // XML Constants - - private static final String NAMESPACES = "namespaces"; - - private static final String NAMESPACE = "namespace"; - - private static final String NAMESPACE_URI = "uri"; - - private static final String NAMESPACE_PREFIX = "prefix"; - - private static final String PERMISSION_SET = "permissionSet"; - - private static final String GLOBAL_PERMISSION = "globalPermission"; - - private static final String DENY = "deny"; - - private static final String ALLOW = "allow"; - - private static final String DEFAULT_PERMISSION = "defaultPermission"; - - // Instance variables - - private String model; - - private Map permissionSets = new HashMap(); - - private Set globalPermissions = new HashSet(); - - private AccessStatus defaultPermission; - - // Cache granting permissions - private HashMap> grantingPermissions = - new HashMap>(); - - // Cache grantees - private HashMap> granteePermissions = - new HashMap>(); - - // Cache the mapping of extended groups to the base - private HashMap groupsToBaseGroup = - new HashMap(); - - private HashMap uniqueMap; - - private HashMap permissionMap; - - private HashMap permissionGroupMap; - - private HashMap permissionReferenceMap; - - private Map> cachedTypePermissionsExposed = - new HashMap>(128, 1.0f); - - private Map> cachedTypePermissionsUnexposed = - new HashMap>(128, 1.0f); - - public PermissionModel() - { - super(); - } - - // IOC - - public void setModel(String model) - { - this.model = model; - } - - public void setDictionaryService(DictionaryService dictionaryService) - { - this.dictionaryService = dictionaryService; - } - - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - /* - * Initialise from file - * - * (non-Javadoc) - * - * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() - */ - - public void afterPropertiesSet() - { - Document document = createDocument(model); - Element root = document.getRootElement(); - - Attribute defaultPermissionAttribute = root.attribute(DEFAULT_PERMISSION); - if (defaultPermissionAttribute != null) - { - if (defaultPermissionAttribute.getStringValue().equalsIgnoreCase(ALLOW)) - { - defaultPermission = AccessStatus.ALLOWED; - } - else if (defaultPermissionAttribute.getStringValue().equalsIgnoreCase(DENY)) - { - defaultPermission = AccessStatus.DENIED; - } - else - { - throw new PermissionModelException("The default permission must be deny or allow"); - } - } - else - { - defaultPermission = AccessStatus.DENIED; - } - - DynamicNamespacePrefixResolver nspr = new DynamicNamespacePrefixResolver(); - - // Namespaces - - for (Iterator nsit = root.elementIterator(NAMESPACES); nsit.hasNext(); /**/) - { - Element namespacesElement = (Element) nsit.next(); - for (Iterator it = namespacesElement.elementIterator(NAMESPACE); it.hasNext(); /**/) - { - Element nameSpaceElement = (Element) it.next(); - nspr.registerNamespace(nameSpaceElement.attributeValue(NAMESPACE_PREFIX), nameSpaceElement - .attributeValue(NAMESPACE_URI)); - } - } - - // Permission Sets - - for (Iterator psit = root.elementIterator(PERMISSION_SET); psit.hasNext(); /**/) - { - Element permissionSetElement = (Element) psit.next(); - PermissionSet permissionSet = new PermissionSet(); - permissionSet.initialise(permissionSetElement, nspr, this); - - permissionSets.put(permissionSet.getQName(), permissionSet); - } - - buildUniquePermissionMap(); - - // NodePermissions - - for (Iterator npit = root.elementIterator(GLOBAL_PERMISSION); npit.hasNext(); /**/) - { - Element globalPermissionElement = (Element) npit.next(); - GlobalPermissionEntry globalPermission = new GlobalPermissionEntry(); - globalPermission.initialise(globalPermissionElement, nspr, this); - - globalPermissions.add(globalPermission); - } - } - - /* - * Create the XML document from the file location - */ - private Document createDocument(String model) - { - InputStream is = this.getClass().getClassLoader().getResourceAsStream(model); - if (is == null) - { - throw new PermissionModelException("File not found: " + model); - } - SAXReader reader = new SAXReader(); - try - { - Document document = reader.read(is); - is.close(); - return document; - } - catch (DocumentException e) - { - throw new PermissionModelException("Failed to create permission model document ", e); - } - catch (IOException e) - { - throw new PermissionModelException("Failed to close permission model document ", e); - } - - } - - public AccessStatus getDefaultPermission() - { - return defaultPermission; - } - - public AccessStatus getDefaultPermission(PermissionReference pr) - { - Permission p = permissionMap.get(pr); - if (p == null) - { - return defaultPermission; - } - else - { - return p.getDefaultPermission(); - } - } - - public Set getGlobalPermissionEntries() - { - return Collections.unmodifiableSet(globalPermissions); - } - - public Map getPermissionSets() - { - return Collections.unmodifiableMap(permissionSets); - } - - public Set getAllPermissions(QName type) - { - return getAllPermissionsImpl(type, false); - } - - public Set getExposedPermissions(QName type) - { - return getAllPermissionsImpl(type, true); - } - - @SuppressWarnings("unchecked") - private Set getAllPermissionsImpl(QName type, boolean exposedOnly) - { - Map> cache; - if (exposedOnly) - { - cache = this.cachedTypePermissionsExposed; - } - else - { - cache = this.cachedTypePermissionsUnexposed; - } - LinkedHashSet permissions = cache.get(type); - if (permissions == null) - { - permissions = new LinkedHashSet(); - if (dictionaryService.getClass(type).isAspect()) - { - addAspectPermissions(type, permissions, exposedOnly); - } - else - { - mergeGeneralAspectPermissions(permissions, exposedOnly); - addTypePermissions(type, permissions, exposedOnly); - } - cache.put(type, permissions); - } - return (Set)permissions.clone(); - } - - /** - * Support to add permissions for types - * - * @param type - * @param permissions - */ - private void addTypePermissions(QName type, Set permissions, boolean exposedOnly) - { - TypeDefinition typeDef = dictionaryService.getType(type); - if (typeDef.getParentName() != null) - { - PermissionSet permissionSet = permissionSets.get(type); - if (!exposedOnly || (permissionSet == null) || permissionSet.exposeAll()) - { - addTypePermissions(typeDef.getParentName(), permissions, exposedOnly); - } - } - for (AspectDefinition ad : typeDef.getDefaultAspects()) - { - addAspectPermissions(ad.getName(), permissions, exposedOnly); - } - mergePermissions(permissions, type, exposedOnly, true); - } - - /** - * Support to add permissions for aspects. - * - * @param type - * @param permissions - */ - private void addAspectPermissions(QName type, Set permissions, boolean exposedOnly) - { - AspectDefinition aspectDef = dictionaryService.getAspect(type); - if (aspectDef.getParentName() != null) - { - PermissionSet permissionSet = permissionSets.get(type); - if (!exposedOnly || (permissionSet == null) || permissionSet.exposeAll()) - { - addAspectPermissions(aspectDef.getParentName(), permissions, exposedOnly); - } - } - mergePermissions(permissions, type, exposedOnly, true); - } - - /** - * Support to merge permissions together. Respects extended permissions. - * - * @param target - * @param type - */ - private void mergePermissions(Set target, QName type, boolean exposedOnly, boolean typeRequired) - { - PermissionSet permissionSet = permissionSets.get(type); - if (permissionSet != null) - { - for (PermissionGroup pg : permissionSet.getPermissionGroups()) - { - if (!exposedOnly || permissionSet.exposeAll() || pg.isExposed()) - { - if (!pg.isExtends()) - { - if (pg.isTypeRequired() == typeRequired) - { - target.add(pg); - } - } - else if (exposedOnly) - { - if (pg.isTypeRequired() == typeRequired) - { - target.add(getBasePermissionGroup(pg)); - } - } - } - } - for (Permission p : permissionSet.getPermissions()) - { - if (!exposedOnly || permissionSet.exposeAll() || p.isExposed()) - { - if (p.isTypeRequired() == typeRequired) - { - target.add(p); - } - } - } - } - } - - private void mergeGeneralAspectPermissions(Set target, boolean exposedOnly) - { - for(QName aspect : dictionaryService.getAllAspects()) - { - mergePermissions(target, aspect, exposedOnly, false); - } - } - - public Set getAllPermissions(NodeRef nodeRef) - { - return getExposedPermissionsImpl(nodeRef, false); - } - - public Set getExposedPermissions(NodeRef nodeRef) - { - return getExposedPermissionsImpl(nodeRef, true); - } - - public Set getExposedPermissionsImpl(NodeRef nodeRef, boolean exposedOnly) - { - // - // TODO: cache permissions based on type and exposed flag - // create JMeter test to see before/after effect! - // - QName typeName = nodeService.getType(nodeRef); - - Set permissions = getAllPermissions(typeName); - mergeGeneralAspectPermissions(permissions, exposedOnly); - // Add non mandatory aspects... - Set defaultAspects = new HashSet(); - for (AspectDefinition aspDef : dictionaryService.getType(typeName).getDefaultAspects()) - { - defaultAspects.add(aspDef.getName()); - } - for (QName aspect : nodeService.getAspects(nodeRef)) - { - if (!defaultAspects.contains(aspect)) - { - addAspectPermissions(aspect, permissions, exposedOnly); - } - } - return permissions; - } - - public synchronized Set getGrantingPermissions(PermissionReference permissionReference) - { - // Cache the results - Set granters = grantingPermissions.get(permissionReference); - if (granters == null) - { - granters = getGrantingPermissionsImpl(permissionReference); - grantingPermissions.put(permissionReference, granters); - } - return granters; - } - - private Set getGrantingPermissionsImpl(PermissionReference permissionReference) - { - // Query the model - HashSet permissions = new HashSet(); - permissions.add(permissionReference); - for (PermissionSet ps : permissionSets.values()) - { - for (PermissionGroup pg : ps.getPermissionGroups()) - { - if (grants(pg, permissionReference)) - { - permissions.add(getBasePermissionGroup(pg)); - } - if (pg.isAllowFullControl()) - { - permissions.add(pg); - } - } - for (Permission p : ps.getPermissions()) - { - if (p.equals(permissionReference)) - { - for (PermissionReference pg : p.getGrantedToGroups()) - { - permissions.add(getBasePermissionGroup(getPermissionGroup(pg))); - } - } - for (RequiredPermission rp : p.getRequiredPermissions()) - { - if (rp.equals(permissionReference) && rp.isImplies()) - { - permissions.add(p); - break; - } - } - } - } - return permissions; - } - - private boolean grants(PermissionGroup pg, PermissionReference permissionReference) - { - if (pg.getIncludedPermissionGroups().contains(permissionReference)) - { - return true; - } - if (getGranteePermissions(pg).contains(permissionReference)) - { - return true; - } - for (PermissionReference nested : pg.getIncludedPermissionGroups()) - { - if (grants(getPermissionGroup(nested), permissionReference)) - { - return true; - } - } - return false; - } - - public synchronized Set getGranteePermissions(PermissionReference permissionReference) - { - // Cache the results - Set grantees = granteePermissions.get(permissionReference); - if (grantees == null) - { - grantees = getGranteePermissionsImpl(permissionReference); - granteePermissions.put(permissionReference, grantees); - } - return grantees; - } - - private Set getGranteePermissionsImpl(PermissionReference permissionReference) - { - // Query the model - HashSet permissions = new HashSet(); - permissions.add(permissionReference); - for (PermissionSet ps : permissionSets.values()) - { - for (PermissionGroup pg : ps.getPermissionGroups()) - { - if (pg.equals(permissionReference)) - { - for (PermissionReference included : pg.getIncludedPermissionGroups()) - { - permissions.addAll(getGranteePermissions(included)); - } - - if (pg.isExtends()) - { - if (pg.getTypeQName() != null) - { - permissions.addAll(getGranteePermissions(new SimplePermissionReference(pg.getTypeQName(), - pg.getName()))); - } - else - { - ClassDefinition classDefinition = dictionaryService.getClass(pg.getQName()); - QName parent = classDefinition.getParentName(); - if (parent != null) - { - classDefinition = dictionaryService.getClass(parent); - PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference( - parent, pg.getName())); - if (attempt != null) - { - permissions.addAll(getGranteePermissions(attempt)); - } - } - } - } - - if (pg.isAllowFullControl()) - { - // add all available - permissions.addAll(getAllPermissions()); - } - } - } - PermissionGroup baseGroup = getBasePermissionGroupOrNull(getPermissionGroupOrNull(permissionReference)); - if (baseGroup != null) - { - for (Permission p : ps.getPermissions()) - { - for (PermissionReference grantedTo : p.getGrantedToGroups()) - { - PermissionGroup base = getBasePermissionGroupOrNull(getPermissionGroupOrNull(grantedTo)); - if (baseGroup.equals(base)) - { - permissions.add(p); - } - } - } - } - } - return permissions; - } - - private Set getAllPermissions() - { - HashSet permissions = new HashSet(); - for (PermissionSet ps : permissionSets.values()) - { - for (PermissionGroup pg : ps.getPermissionGroups()) - { - permissions.add(pg); - } - for (Permission p : ps.getPermissions()) - { - permissions.add(p); - } - } - return permissions; - } - - /** - * Support to find permission groups - * - * @param target - * @return - */ - private PermissionGroup getPermissionGroupOrNull(PermissionReference target) - { - PermissionGroup pg = permissionGroupMap.get(target); - return pg == null ? null : pg; - } - - /** - * Support to get a permission group - * - * @param target - * @return - */ - private PermissionGroup getPermissionGroup(PermissionReference target) - { - PermissionGroup pg = getPermissionGroupOrNull(target); - if (pg == null) - { - throw new PermissionModelException("There is no permission group :" - + target.getQName() + " " + target.getName()); - } - return pg; - } - - /** - * Get the base permission group for a given permission group. - * - * @param pg - * @return - */ - private synchronized PermissionGroup getBasePermissionGroupOrNull(PermissionGroup pg) - { - if (groupsToBaseGroup.containsKey(pg)) - { - return groupsToBaseGroup.get(pg); - } - else - { - PermissionGroup answer = getBasePermissionGroupOrNullImpl(pg); - groupsToBaseGroup.put(pg, answer); - return answer; - } - } - - /** - * Query the model for a base permission group - * - * Uses the Data Dictionary to reolve inheritance - * - * @param pg - * @return - */ - private PermissionGroup getBasePermissionGroupOrNullImpl(PermissionGroup pg) - { - if (pg == null) - { - return null; - } - if (pg.isExtends()) - { - if (pg.getTypeQName() != null) - { - return getPermissionGroup(new SimplePermissionReference(pg.getTypeQName(), pg.getName())); - } - else - { - ClassDefinition classDefinition = dictionaryService.getClass(pg.getQName()); - QName parent; - while ((parent = classDefinition.getParentName()) != null) - { - classDefinition = dictionaryService.getClass(parent); - PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference(parent, pg - .getName())); - if ((attempt != null) && (!attempt.isExtends())) - { - return attempt; - } - } - return null; - } - } - else - { - return pg; - } - } - - private PermissionGroup getBasePermissionGroup(PermissionGroup target) - { - PermissionGroup pg = getBasePermissionGroupOrNull(target); - if (pg == null) - { - throw new PermissionModelException("There is no parent for permission group :" - + target.getQName() + " " + target.getName()); - } - return pg; - } - - public Set getRequiredPermissions(PermissionReference required, QName qName, - Set aspectQNames, RequiredPermission.On on) - { - PermissionGroup pg = getBasePermissionGroupOrNull(getPermissionGroupOrNull(required)); - if (pg == null) - { - return getRequirementsForPermission(required, on); - } - else - { - return getRequirementsForPermissionGroup(pg, on, qName, aspectQNames); - } - } - - /** - * Get the requirements for a permission - * - * @param required - * @param on - * @return - */ - private Set getRequirementsForPermission(PermissionReference required, RequiredPermission.On on) - { - HashSet requiredPermissions = new HashSet(); - Permission p = getPermissionOrNull(required); - if (p != null) - { - for (RequiredPermission rp : p.getRequiredPermissions()) - { - if (!rp.isImplies() && rp.getOn().equals(on)) - { - requiredPermissions.add(rp); - } - } - } - return requiredPermissions; - } - - /** - * Get the requirements for a permission set - * - * @param target - * @param on - * @param qName - * @param aspectQNames - * @return - */ - private Set getRequirementsForPermissionGroup(PermissionGroup target, - RequiredPermission.On on, QName qName, Set aspectQNames) - { - HashSet requiredPermissions = new HashSet(); - if (target == null) - { - return requiredPermissions; - } - for (PermissionSet ps : permissionSets.values()) - { - for (PermissionGroup pg : ps.getPermissionGroups()) - { - if (target.equals(getBasePermissionGroupOrNull(pg)) - && isPartOfDynamicPermissionGroup(pg, qName, aspectQNames)) - { - // Add includes - for (PermissionReference pr : pg.getIncludedPermissionGroups()) - { - requiredPermissions.addAll(getRequirementsForPermissionGroup( - getBasePermissionGroupOrNull(getPermissionGroupOrNull(pr)), on, qName, aspectQNames)); - } - } - } - for (Permission p : ps.getPermissions()) - { - for (PermissionReference grantedTo : p.getGrantedToGroups()) - { - PermissionGroup base = getBasePermissionGroupOrNull(getPermissionGroupOrNull(grantedTo)); - if (target.equals(base) && (!base.isTypeRequired() || isPartOfDynamicPermissionGroup(grantedTo, qName, aspectQNames))) - { - if (on == RequiredPermission.On.NODE) - { - requiredPermissions.add(p); - } - } - } - } - } - return requiredPermissions; - } - - /** - * Check type specifc extension of permission sets. - * - * @param pr - * @param typeQname - * @param aspects - * @return - */ - private boolean isPartOfDynamicPermissionGroup(PermissionReference pr, QName typeQname, Set aspects) - { - if (dictionaryService.isSubClass(typeQname, pr.getQName())) - { - return true; - } - for (QName aspect : aspects) - { - if (dictionaryService.isSubClass(aspect, pr.getQName())) - { - return true; - } - } - return false; - } - - /** - * Utility method to find a permission - * - * @param perm - * @return - */ - private Permission getPermissionOrNull(PermissionReference perm) - { - Permission p = permissionMap.get(perm); - return p == null ? null : p; - } - - public boolean checkPermission(PermissionReference required) - { - Permission permission = getPermissionOrNull(required); - if (permission != null) - { - return true; - } - PermissionGroup pg = getPermissionGroupOrNull(required); - if (pg != null) - { - if (pg.isExtends()) - { - if (pg.getTypeQName() != null) - { - return checkPermission(new SimplePermissionReference(pg.getTypeQName(), pg.getName())); - } - else - { - ClassDefinition classDefinition = dictionaryService.getClass(pg.getQName()); - QName parent; - while ((parent = classDefinition.getParentName()) != null) - { - classDefinition = dictionaryService.getClass(parent); - PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference(parent, pg - .getName())); - if ((attempt != null) && attempt.isAllowFullControl()) - { - return true; - } - } - return false; - } - } - else - { - return pg.isAllowFullControl(); - } - } - else - { - return false; - } - - } - - public PermissionReference getPermissionReference(QName qname, String permissionName) - { - if(permissionName == null) - { - return null; - } - PermissionReference pr = uniqueMap.get(permissionName); - if (pr == null) - { - pr = permissionReferenceMap.get(permissionName); - if (pr == null) - { - throw new UnsupportedOperationException("Can not find " + permissionName); - } - } - return pr; - - } - - public boolean isUnique(PermissionReference permissionReference) - { - return uniqueMap.containsKey(permissionReference.getName()); - } - - private void buildUniquePermissionMap() - { - Set excluded = new HashSet(); - uniqueMap = new HashMap(); - permissionReferenceMap = new HashMap(); - permissionGroupMap = new HashMap(); - permissionMap = new HashMap(); - for (PermissionSet ps : permissionSets.values()) - { - for (PermissionGroup pg : ps.getPermissionGroups()) - { - if (uniqueMap.containsKey(pg.getName()) && !excluded.contains(pg.getName())) - { - PermissionReference value = uniqueMap.get(pg.getName()); - if (!value.equals(getBasePermissionGroup(pg))) - { - uniqueMap.remove(pg.getName()); - excluded.add(pg.getName()); - } - } - else - { - uniqueMap.put(pg.getName(), getBasePermissionGroup(pg)); - } - permissionReferenceMap.put(pg.toString(), pg); - permissionGroupMap.put(pg, pg); - } - for (Permission p : ps.getPermissions()) - { - if (uniqueMap.containsKey(p.getName()) && !excluded.contains(p.getName())) - { - PermissionReference value = uniqueMap.get(p.getName()); - if (!value.equals(p)) - { - uniqueMap.remove(p.getName()); - excluded.add(p.getName()); - } - } - else - { - uniqueMap.put(p.getName(), p); - } - permissionReferenceMap.put(p.toString(), p); - permissionMap.put(p, p); - } - } - // Add all permissions to the unique list - if (uniqueMap.containsKey(PermissionService.ALL_PERMISSIONS)) - { - throw new IllegalStateException( - "There must not be a permission with the same name as the ALL_PERMISSION constant: " - + PermissionService.ALL_PERMISSIONS); - } - uniqueMap.put(PermissionService.ALL_PERMISSIONS, new SimplePermissionReference(QName.createQName( - NamespaceService.SECURITY_MODEL_1_0_URI, PermissionService.ALL_PERMISSIONS), PermissionService.ALL_PERMISSIONS)); - - } - -} +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.security.permissions.impl.model; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.security.permissions.PermissionEntry; +import org.alfresco.repo.security.permissions.PermissionReference; +import org.alfresco.repo.security.permissions.impl.ModelDAO; +import org.alfresco.repo.security.permissions.impl.RequiredPermission; +import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; +import org.alfresco.service.cmr.dictionary.AspectDefinition; +import org.alfresco.service.cmr.dictionary.ClassDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.TypeDefinition; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.DynamicNamespacePrefixResolver; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.dom4j.Attribute; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.Element; +import org.dom4j.io.SAXReader; +import org.springframework.beans.factory.InitializingBean; + +/** + * The implementation of the model DAO Reads and stores the top level model information Encapsulates access to this information + * + * @author andyh + */ +public class PermissionModel implements ModelDAO, InitializingBean +{ + // IOC + + private NodeService nodeService; + + private DictionaryService dictionaryService; + + // XML Constants + + private static final String NAMESPACES = "namespaces"; + + private static final String NAMESPACE = "namespace"; + + private static final String NAMESPACE_URI = "uri"; + + private static final String NAMESPACE_PREFIX = "prefix"; + + private static final String PERMISSION_SET = "permissionSet"; + + private static final String GLOBAL_PERMISSION = "globalPermission"; + + private static final String DENY = "deny"; + + private static final String ALLOW = "allow"; + + private static final String DEFAULT_PERMISSION = "defaultPermission"; + + // Instance variables + + private String model; + + private Map permissionSets = new HashMap(); + + private Set globalPermissions = new HashSet(); + + private AccessStatus defaultPermission; + + // Cache granting permissions + private HashMap> grantingPermissions = new HashMap>(); + + // Cache grantees + private HashMap> granteePermissions = new HashMap>(); + + // Cache the mapping of extended groups to the base + private HashMap groupsToBaseGroup = new HashMap(); + + private HashMap uniqueMap; + + private HashMap permissionMap; + + private HashMap permissionGroupMap; + + private HashMap permissionReferenceMap; + + private Map> cachedTypePermissionsExposed = new HashMap>( + 128, 1.0f); + + private Map> cachedTypePermissionsUnexposed = new HashMap>( + 128, 1.0f); + + public PermissionModel() + { + super(); + } + + // IOC + + public void setModel(String model) + { + this.model = model; + } + + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /* + * Initialise from file (non-Javadoc) + * + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + + public void afterPropertiesSet() + { + Document document = createDocument(model); + Element root = document.getRootElement(); + + Attribute defaultPermissionAttribute = root.attribute(DEFAULT_PERMISSION); + if (defaultPermissionAttribute != null) + { + if (defaultPermissionAttribute.getStringValue().equalsIgnoreCase(ALLOW)) + { + defaultPermission = AccessStatus.ALLOWED; + } + else if (defaultPermissionAttribute.getStringValue().equalsIgnoreCase(DENY)) + { + defaultPermission = AccessStatus.DENIED; + } + else + { + throw new PermissionModelException("The default permission must be deny or allow"); + } + } + else + { + defaultPermission = AccessStatus.DENIED; + } + + DynamicNamespacePrefixResolver nspr = new DynamicNamespacePrefixResolver(); + + // Namespaces + + for (Iterator nsit = root.elementIterator(NAMESPACES); nsit.hasNext(); /**/) + { + Element namespacesElement = (Element) nsit.next(); + for (Iterator it = namespacesElement.elementIterator(NAMESPACE); it.hasNext(); /**/) + { + Element nameSpaceElement = (Element) it.next(); + nspr.registerNamespace(nameSpaceElement.attributeValue(NAMESPACE_PREFIX), nameSpaceElement + .attributeValue(NAMESPACE_URI)); + } + } + + // Permission Sets + + for (Iterator psit = root.elementIterator(PERMISSION_SET); psit.hasNext(); /**/) + { + Element permissionSetElement = (Element) psit.next(); + PermissionSet permissionSet = new PermissionSet(); + permissionSet.initialise(permissionSetElement, nspr, this); + + permissionSets.put(permissionSet.getQName(), permissionSet); + } + + buildUniquePermissionMap(); + + // NodePermissions + + for (Iterator npit = root.elementIterator(GLOBAL_PERMISSION); npit.hasNext(); /**/) + { + Element globalPermissionElement = (Element) npit.next(); + GlobalPermissionEntry globalPermission = new GlobalPermissionEntry(); + globalPermission.initialise(globalPermissionElement, nspr, this); + + globalPermissions.add(globalPermission); + } + } + + /* + * Create the XML document from the file location + */ + private Document createDocument(String model) + { + InputStream is = this.getClass().getClassLoader().getResourceAsStream(model); + if (is == null) + { + throw new PermissionModelException("File not found: " + model); + } + SAXReader reader = new SAXReader(); + try + { + Document document = reader.read(is); + is.close(); + return document; + } + catch (DocumentException e) + { + throw new PermissionModelException("Failed to create permission model document ", e); + } + catch (IOException e) + { + throw new PermissionModelException("Failed to close permission model document ", e); + } + + } + + public AccessStatus getDefaultPermission() + { + return defaultPermission; + } + + public AccessStatus getDefaultPermission(PermissionReference pr) + { + Permission p = permissionMap.get(pr); + if (p == null) + { + return defaultPermission; + } + else + { + return p.getDefaultPermission(); + } + } + + public Set getGlobalPermissionEntries() + { + return Collections.unmodifiableSet(globalPermissions); + } + + public Map getPermissionSets() + { + return Collections.unmodifiableMap(permissionSets); + } + + public Set getAllPermissions(QName type) + { + return getAllPermissionsImpl(type, false); + } + + public Set getExposedPermissions(QName type) + { + return getAllPermissionsImpl(type, true); + } + + @SuppressWarnings("unchecked") + private Set getAllPermissionsImpl(QName type, boolean exposedOnly) + { + Map> cache; + if (exposedOnly) + { + cache = this.cachedTypePermissionsExposed; + } + else + { + cache = this.cachedTypePermissionsUnexposed; + } + LinkedHashSet permissions = cache.get(type); + if (permissions == null) + { + permissions = new LinkedHashSet(); + ClassDefinition cd = dictionaryService.getClass(type); + if (cd != null) + { + if (cd.isAspect()) + { + addAspectPermissions(type, permissions, exposedOnly); + } + else + { + mergeGeneralAspectPermissions(permissions, exposedOnly); + addTypePermissions(type, permissions, exposedOnly); + } + } + cache.put(type, permissions); + } + return (Set) permissions.clone(); + } + + /** + * Support to add permissions for types + * + * @param type + * @param permissions + */ + private void addTypePermissions(QName type, Set permissions, boolean exposedOnly) + { + TypeDefinition typeDef = dictionaryService.getType(type); + if (typeDef.getParentName() != null) + { + PermissionSet permissionSet = permissionSets.get(type); + if (!exposedOnly || (permissionSet == null) || permissionSet.exposeAll()) + { + addTypePermissions(typeDef.getParentName(), permissions, exposedOnly); + } + } + for (AspectDefinition ad : typeDef.getDefaultAspects()) + { + addAspectPermissions(ad.getName(), permissions, exposedOnly); + } + mergePermissions(permissions, type, exposedOnly, true); + } + + /** + * Support to add permissions for aspects. + * + * @param type + * @param permissions + */ + private void addAspectPermissions(QName type, Set permissions, boolean exposedOnly) + { + AspectDefinition aspectDef = dictionaryService.getAspect(type); + if (aspectDef.getParentName() != null) + { + PermissionSet permissionSet = permissionSets.get(type); + if (!exposedOnly || (permissionSet == null) || permissionSet.exposeAll()) + { + addAspectPermissions(aspectDef.getParentName(), permissions, exposedOnly); + } + } + mergePermissions(permissions, type, exposedOnly, true); + } + + /** + * Support to merge permissions together. Respects extended permissions. + * + * @param target + * @param type + */ + private void mergePermissions(Set target, QName type, boolean exposedOnly, boolean typeRequired) + { + PermissionSet permissionSet = permissionSets.get(type); + if (permissionSet != null) + { + for (PermissionGroup pg : permissionSet.getPermissionGroups()) + { + if (!exposedOnly || permissionSet.exposeAll() || pg.isExposed()) + { + if (!pg.isExtends()) + { + if (pg.isTypeRequired() == typeRequired) + { + target.add(pg); + } + } + else if (exposedOnly) + { + if (pg.isTypeRequired() == typeRequired) + { + target.add(getBasePermissionGroup(pg)); + } + } + } + } + for (Permission p : permissionSet.getPermissions()) + { + if (!exposedOnly || permissionSet.exposeAll() || p.isExposed()) + { + if (p.isTypeRequired() == typeRequired) + { + target.add(p); + } + } + } + } + } + + private void mergeGeneralAspectPermissions(Set target, boolean exposedOnly) + { + for (QName aspect : dictionaryService.getAllAspects()) + { + mergePermissions(target, aspect, exposedOnly, false); + } + } + + public Set getAllPermissions(NodeRef nodeRef) + { + return getExposedPermissionsImpl(nodeRef, false); + } + + public Set getExposedPermissions(NodeRef nodeRef) + { + return getExposedPermissionsImpl(nodeRef, true); + } + + public Set getExposedPermissionsImpl(NodeRef nodeRef, boolean exposedOnly) + { + // + // TODO: cache permissions based on type and exposed flag + // create JMeter test to see before/after effect! + // + QName typeName = nodeService.getType(nodeRef); + + Set permissions = getAllPermissions(typeName); + mergeGeneralAspectPermissions(permissions, exposedOnly); + // Add non mandatory aspects... + Set defaultAspects = new HashSet(); + for (AspectDefinition aspDef : dictionaryService.getType(typeName).getDefaultAspects()) + { + defaultAspects.add(aspDef.getName()); + } + for (QName aspect : nodeService.getAspects(nodeRef)) + { + if (!defaultAspects.contains(aspect)) + { + addAspectPermissions(aspect, permissions, exposedOnly); + } + } + return permissions; + } + + public synchronized Set getGrantingPermissions(PermissionReference permissionReference) + { + // Cache the results + Set granters = grantingPermissions.get(permissionReference); + if (granters == null) + { + granters = getGrantingPermissionsImpl(permissionReference); + grantingPermissions.put(permissionReference, granters); + } + return granters; + } + + private Set getGrantingPermissionsImpl(PermissionReference permissionReference) + { + // Query the model + HashSet permissions = new HashSet(); + permissions.add(permissionReference); + for (PermissionSet ps : permissionSets.values()) + { + for (PermissionGroup pg : ps.getPermissionGroups()) + { + if (grants(pg, permissionReference)) + { + permissions.add(getBasePermissionGroup(pg)); + } + if (pg.isAllowFullControl()) + { + permissions.add(pg); + } + } + for (Permission p : ps.getPermissions()) + { + if (p.equals(permissionReference)) + { + for (PermissionReference pg : p.getGrantedToGroups()) + { + permissions.add(getBasePermissionGroup(getPermissionGroup(pg))); + } + } + for (RequiredPermission rp : p.getRequiredPermissions()) + { + if (rp.equals(permissionReference) && rp.isImplies()) + { + permissions.add(p); + break; + } + } + } + } + return permissions; + } + + private boolean grants(PermissionGroup pg, PermissionReference permissionReference) + { + if (pg.getIncludedPermissionGroups().contains(permissionReference)) + { + return true; + } + if (getGranteePermissions(pg).contains(permissionReference)) + { + return true; + } + for (PermissionReference nested : pg.getIncludedPermissionGroups()) + { + if (grants(getPermissionGroup(nested), permissionReference)) + { + return true; + } + } + return false; + } + + public synchronized Set getGranteePermissions(PermissionReference permissionReference) + { + // Cache the results + Set grantees = granteePermissions.get(permissionReference); + if (grantees == null) + { + grantees = getGranteePermissionsImpl(permissionReference); + granteePermissions.put(permissionReference, grantees); + } + return grantees; + } + + private Set getGranteePermissionsImpl(PermissionReference permissionReference) + { + // Query the model + HashSet permissions = new HashSet(); + permissions.add(permissionReference); + for (PermissionSet ps : permissionSets.values()) + { + for (PermissionGroup pg : ps.getPermissionGroups()) + { + if (pg.equals(permissionReference)) + { + for (PermissionReference included : pg.getIncludedPermissionGroups()) + { + permissions.addAll(getGranteePermissions(included)); + } + + if (pg.isExtends()) + { + if (pg.getTypeQName() != null) + { + permissions.addAll(getGranteePermissions(new SimplePermissionReference(pg.getTypeQName(), + pg.getName()))); + } + else + { + ClassDefinition classDefinition = dictionaryService.getClass(pg.getQName()); + QName parent = classDefinition.getParentName(); + if (parent != null) + { + classDefinition = dictionaryService.getClass(parent); + PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference( + parent, pg.getName())); + if (attempt != null) + { + permissions.addAll(getGranteePermissions(attempt)); + } + } + } + } + + if (pg.isAllowFullControl()) + { + // add all available + permissions.addAll(getAllPermissions()); + } + } + } + PermissionGroup baseGroup = getBasePermissionGroupOrNull(getPermissionGroupOrNull(permissionReference)); + if (baseGroup != null) + { + for (Permission p : ps.getPermissions()) + { + for (PermissionReference grantedTo : p.getGrantedToGroups()) + { + PermissionGroup base = getBasePermissionGroupOrNull(getPermissionGroupOrNull(grantedTo)); + if (baseGroup.equals(base)) + { + permissions.add(p); + } + } + } + } + } + return permissions; + } + + private Set getAllPermissions() + { + HashSet permissions = new HashSet(); + for (PermissionSet ps : permissionSets.values()) + { + for (PermissionGroup pg : ps.getPermissionGroups()) + { + permissions.add(pg); + } + for (Permission p : ps.getPermissions()) + { + permissions.add(p); + } + } + return permissions; + } + + /** + * Support to find permission groups + * + * @param target + * @return + */ + private PermissionGroup getPermissionGroupOrNull(PermissionReference target) + { + PermissionGroup pg = permissionGroupMap.get(target); + return pg == null ? null : pg; + } + + /** + * Support to get a permission group + * + * @param target + * @return + */ + private PermissionGroup getPermissionGroup(PermissionReference target) + { + PermissionGroup pg = getPermissionGroupOrNull(target); + if (pg == null) + { + throw new PermissionModelException("There is no permission group :" + + target.getQName() + " " + target.getName()); + } + return pg; + } + + /** + * Get the base permission group for a given permission group. + * + * @param pg + * @return + */ + private synchronized PermissionGroup getBasePermissionGroupOrNull(PermissionGroup pg) + { + if (groupsToBaseGroup.containsKey(pg)) + { + return groupsToBaseGroup.get(pg); + } + else + { + PermissionGroup answer = getBasePermissionGroupOrNullImpl(pg); + groupsToBaseGroup.put(pg, answer); + return answer; + } + } + + /** + * Query the model for a base permission group Uses the Data Dictionary to reolve inheritance + * + * @param pg + * @return + */ + private PermissionGroup getBasePermissionGroupOrNullImpl(PermissionGroup pg) + { + if (pg == null) + { + return null; + } + if (pg.isExtends()) + { + if (pg.getTypeQName() != null) + { + return getPermissionGroup(new SimplePermissionReference(pg.getTypeQName(), pg.getName())); + } + else + { + ClassDefinition classDefinition = dictionaryService.getClass(pg.getQName()); + QName parent; + while ((parent = classDefinition.getParentName()) != null) + { + classDefinition = dictionaryService.getClass(parent); + PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference(parent, pg + .getName())); + if ((attempt != null) && (!attempt.isExtends())) + { + return attempt; + } + } + return null; + } + } + else + { + return pg; + } + } + + private PermissionGroup getBasePermissionGroup(PermissionGroup target) + { + PermissionGroup pg = getBasePermissionGroupOrNull(target); + if (pg == null) + { + throw new PermissionModelException("There is no parent for permission group :" + + target.getQName() + " " + target.getName()); + } + return pg; + } + + public Set getRequiredPermissions(PermissionReference required, QName qName, + Set aspectQNames, RequiredPermission.On on) + { + PermissionGroup pg = getBasePermissionGroupOrNull(getPermissionGroupOrNull(required)); + if (pg == null) + { + return getRequirementsForPermission(required, on); + } + else + { + return getRequirementsForPermissionGroup(pg, on, qName, aspectQNames); + } + } + + /** + * Get the requirements for a permission + * + * @param required + * @param on + * @return + */ + private Set getRequirementsForPermission(PermissionReference required, RequiredPermission.On on) + { + HashSet requiredPermissions = new HashSet(); + Permission p = getPermissionOrNull(required); + if (p != null) + { + for (RequiredPermission rp : p.getRequiredPermissions()) + { + if (!rp.isImplies() && rp.getOn().equals(on)) + { + requiredPermissions.add(rp); + } + } + } + return requiredPermissions; + } + + /** + * Get the requirements for a permission set + * + * @param target + * @param on + * @param qName + * @param aspectQNames + * @return + */ + private Set getRequirementsForPermissionGroup(PermissionGroup target, + RequiredPermission.On on, QName qName, Set aspectQNames) + { + HashSet requiredPermissions = new HashSet(); + if (target == null) + { + return requiredPermissions; + } + for (PermissionSet ps : permissionSets.values()) + { + for (PermissionGroup pg : ps.getPermissionGroups()) + { + PermissionGroup base = getBasePermissionGroupOrNull(pg); + if (target.equals(base) + && (!base.isTypeRequired() || isPartOfDynamicPermissionGroup(pg, qName, aspectQNames))) + { + // Add includes + for (PermissionReference pr : pg.getIncludedPermissionGroups()) + { + requiredPermissions.addAll(getRequirementsForPermissionGroup( + getBasePermissionGroupOrNull(getPermissionGroupOrNull(pr)), on, qName, aspectQNames)); + } + } + } + for (Permission p : ps.getPermissions()) + { + for (PermissionReference grantedTo : p.getGrantedToGroups()) + { + PermissionGroup base = getBasePermissionGroupOrNull(getPermissionGroupOrNull(grantedTo)); + if (target.equals(base) + && (!base.isTypeRequired() || isPartOfDynamicPermissionGroup(grantedTo, qName, aspectQNames))) + { + if (on == RequiredPermission.On.NODE) + { + requiredPermissions.add(p); + } + } + } + } + } + return requiredPermissions; + } + + /** + * Check type specifc extension of permission sets. + * + * @param pr + * @param typeQname + * @param aspects + * @return + */ + private boolean isPartOfDynamicPermissionGroup(PermissionReference pr, QName typeQname, Set aspects) + { + if (dictionaryService.isSubClass(typeQname, pr.getQName())) + { + return true; + } + for (QName aspect : aspects) + { + if (dictionaryService.isSubClass(aspect, pr.getQName())) + { + return true; + } + } + return false; + } + + /** + * Utility method to find a permission + * + * @param perm + * @return + */ + private Permission getPermissionOrNull(PermissionReference perm) + { + Permission p = permissionMap.get(perm); + return p == null ? null : p; + } + + public boolean checkPermission(PermissionReference required) + { + Permission permission = getPermissionOrNull(required); + if (permission != null) + { + return true; + } + PermissionGroup pg = getPermissionGroupOrNull(required); + if (pg != null) + { + if (pg.isExtends()) + { + if (pg.getTypeQName() != null) + { + return checkPermission(new SimplePermissionReference(pg.getTypeQName(), pg.getName())); + } + else + { + ClassDefinition classDefinition = dictionaryService.getClass(pg.getQName()); + QName parent; + while ((parent = classDefinition.getParentName()) != null) + { + classDefinition = dictionaryService.getClass(parent); + PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference(parent, pg + .getName())); + if ((attempt != null) && attempt.isAllowFullControl()) + { + return true; + } + } + return false; + } + } + else + { + return pg.isAllowFullControl(); + } + } + else + { + return false; + } + + } + + public PermissionReference getPermissionReference(QName qname, String permissionName) + { + if (permissionName == null) + { + return null; + } + PermissionReference pr = uniqueMap.get(permissionName); + if (pr == null) + { + pr = permissionReferenceMap.get(permissionName); + if (pr == null) + { + throw new UnsupportedOperationException("Can not find " + permissionName); + } + } + return pr; + + } + + public boolean isUnique(PermissionReference permissionReference) + { + return uniqueMap.containsKey(permissionReference.getName()); + } + + private void buildUniquePermissionMap() + { + Set excluded = new HashSet(); + uniqueMap = new HashMap(); + permissionReferenceMap = new HashMap(); + permissionGroupMap = new HashMap(); + permissionMap = new HashMap(); + for (PermissionSet ps : permissionSets.values()) + { + for (PermissionGroup pg : ps.getPermissionGroups()) + { + if (uniqueMap.containsKey(pg.getName()) && !excluded.contains(pg.getName())) + { + PermissionReference value = uniqueMap.get(pg.getName()); + if (!value.equals(getBasePermissionGroup(pg))) + { + uniqueMap.remove(pg.getName()); + excluded.add(pg.getName()); + } + } + else + { + uniqueMap.put(pg.getName(), getBasePermissionGroup(pg)); + } + permissionReferenceMap.put(pg.toString(), pg); + permissionGroupMap.put(pg, pg); + } + for (Permission p : ps.getPermissions()) + { + if (uniqueMap.containsKey(p.getName()) && !excluded.contains(p.getName())) + { + PermissionReference value = uniqueMap.get(p.getName()); + if (!value.equals(p)) + { + uniqueMap.remove(p.getName()); + excluded.add(p.getName()); + } + } + else + { + uniqueMap.put(p.getName(), p); + } + permissionReferenceMap.put(p.toString(), p); + permissionMap.put(p, p); + } + } + // Add all permissions to the unique list + if (uniqueMap.containsKey(PermissionService.ALL_PERMISSIONS)) + { + throw new IllegalStateException( + "There must not be a permission with the same name as the ALL_PERMISSION constant: " + + PermissionService.ALL_PERMISSIONS); + } + uniqueMap.put(PermissionService.ALL_PERMISSIONS, new SimplePermissionReference(QName.createQName( + NamespaceService.SECURITY_MODEL_1_0_URI, PermissionService.ALL_PERMISSIONS), + PermissionService.ALL_PERMISSIONS)); + + } + +} diff --git a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModelTest.java b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModelTest.java index 861d8678eb..758e3d94d7 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModelTest.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModelTest.java @@ -22,6 +22,7 @@ import org.alfresco.repo.security.permissions.PermissionEntry; import org.alfresco.repo.security.permissions.PermissionReference; import org.alfresco.repo.security.permissions.impl.AbstractPermissionTest; import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; +import org.alfresco.repo.security.permissions.impl.RequiredPermission.On; import org.alfresco.service.namespace.QName; public class PermissionModelTest extends AbstractPermissionTest @@ -32,12 +33,21 @@ public class PermissionModelTest extends AbstractPermissionTest super(); } + public void testWoof() + { + QName typeQname = nodeService.getType(rootNodeRef); + Set aspectQNames = nodeService.getAspects(rootNodeRef); + PermissionReference ref = permissionModelDAO.getPermissionReference(null, "CheckOut"); + Set answer = permissionModelDAO.getRequiredPermissions(ref, typeQname, aspectQNames, On.NODE); + assertEquals(1, answer.size()); + } + public void testIncludePermissionGroups() { Set grantees = permissionModelDAO.getGranteePermissions(new SimplePermissionReference(QName.createQName("cm", "cmobject", namespacePrefixResolver), "Consumer")); - assertEquals(5, grantees.size()); + assertEquals(8, grantees.size()); } public void testIncludePermissionGroups2() @@ -45,7 +55,7 @@ public class PermissionModelTest extends AbstractPermissionTest Set grantees = permissionModelDAO.getGranteePermissions(new SimplePermissionReference(QName.createQName("cm", "cmobject", namespacePrefixResolver), "Contributor")); - assertEquals(11, grantees.size()); + assertEquals(17, grantees.size()); } public void testIncludePermissionGroups3() @@ -53,7 +63,7 @@ public class PermissionModelTest extends AbstractPermissionTest Set grantees = permissionModelDAO.getGranteePermissions(new SimplePermissionReference(QName.createQName("cm", "cmobject", namespacePrefixResolver), "Editor")); - assertEquals(11, grantees.size()); + assertEquals(17, grantees.size()); } public void testIncludePermissionGroups4() @@ -61,14 +71,34 @@ public class PermissionModelTest extends AbstractPermissionTest Set grantees = permissionModelDAO.getGranteePermissions(new SimplePermissionReference(QName.createQName("cm", "cmobject", namespacePrefixResolver), "Collaborator")); - assertEquals(16, grantees.size()); + assertEquals(24, grantees.size()); + } + + public void testIncludePermissionGroups5() + { + Set grantees = permissionModelDAO.getGranteePermissions(new SimplePermissionReference(QName.createQName("cm", "cmobject", + namespacePrefixResolver), "Coordinator")); + + assertEquals(59, grantees.size()); + } + + public void testIncludePermissionGroups6() + { + Set grantees = permissionModelDAO.getGranteePermissions(new SimplePermissionReference(QName.createQName("cm", "cmobject", + namespacePrefixResolver), "RecordAdministrator")); + + assertEquals(19, grantees.size()); } public void testGetGrantingPermissions() { Set granters = permissionModelDAO.getGrantingPermissions(new SimplePermissionReference(QName.createQName("sys", "base", namespacePrefixResolver), "ReadProperties")); - assertEquals(9, granters.size()); + assertEquals(10, granters.size()); + + granters = permissionModelDAO.getGrantingPermissions(new SimplePermissionReference(QName.createQName("sys", "base", + namespacePrefixResolver), "_ReadProperties")); + assertEquals(11, granters.size()); } public void testGlobalPermissions() @@ -76,4 +106,5 @@ public class PermissionModelTest extends AbstractPermissionTest Set globalPermissions = permissionModelDAO.getGlobalPermissionEntries(); assertEquals(5, globalPermissions.size()); } + } diff --git a/source/java/org/alfresco/repo/security/person/AbstractHomeFolderProvider.java b/source/java/org/alfresco/repo/security/person/AbstractHomeFolderProvider.java new file mode 100644 index 0000000000..530f7361f9 --- /dev/null +++ b/source/java/org/alfresco/repo/security/person/AbstractHomeFolderProvider.java @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.security.person; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.cmr.security.PermissionService; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.InitializingBean; + +/** + * Common support for creating home folders This is hooked into node creation events from Person type objects via the homeFolderManager. Provider must all be wired up to the + * homeFolderManager. + * + * @author Andy Hind + */ +public abstract class AbstractHomeFolderProvider implements HomeFolderProvider, BeanNameAware, InitializingBean +{ + /** + * The provider name + */ + private String name; + + /** + * The home folder manager + */ + private HomeFolderManager homeFolderManager; + + /** + * The store ref in which to conduct searches + */ + private StoreRef storeRef; + + /** + * Service registry to get hold of public services (so taht actions are audited) + */ + private ServiceRegistry serviceRegistry; + + /** + * The path to a folder + */ + private String path; + + /** + * Cache the result of the path look up. + */ + private NodeRef pathNodeRef; + + /** + * The owner to set on creation of a home folder (if unset this will be the uid). + */ + private String ownerOnCreate; + + /** + * Set if permissions are inherited when nodes are created. + */ + private boolean inheritsPermissionsOnCreate = false; + + /** + * A set of permissions to set for the owner when a home folder is created + */ + private Set ownerPemissionsToSetOnCreate; + + /** + * General permissions to set on the node Map<(String)uid, Set<(String)permission>>. + */ + private Map> permissionsToSetOnCreate; + + /** + * Permissions to set for the user - on create and reference. + */ + private Set userPemissions; + + /** + * Clear existing permissions on new home folders (useful of created from a template. + */ + private boolean clearExistingPermissionsOnCreate = false; + + public AbstractHomeFolderProvider() + { + super(); + } + + /** + * Register with the homeFolderManagewr + */ + public void afterPropertiesSet() throws Exception + { + homeFolderManager.addProvider(this); + } + + // === // + // IOC // + // === // + + /** + * Get the home folder manager. + */ + protected HomeFolderManager getHomeFolderManager() + { + return homeFolderManager; + } + + /** + * Set the home folder manager. + * + * @param homeFolderManager + */ + public void setHomeFolderManager(HomeFolderManager homeFolderManager) + { + this.homeFolderManager = homeFolderManager; + } + + /** + * Get the provider name + */ + public String getName() + { + return name; + } + + /** + * The provider name is taken from the bean name + */ + public void setBeanName(String name) + { + this.name = name; + } + + /** + * Get the path + * + * @return + */ + protected String getPath() + { + return path; + } + + /** + * Set the path + * + * @param path + */ + public void setPath(String path) + { + this.path = path; + } + + /** + * Get the store ref + * + * @return + */ + protected StoreRef getStoreRef() + { + return storeRef; + } + + /** + * Set the store ref + * + * @param storeRef + */ + public void setStoreRef(StoreRef storeRef) + { + this.storeRef = storeRef; + } + + /** + * Set the store from the string url. + * + * @param storeUrl + */ + public void setStoreUrl(String storeUrl) + { + this.storeRef = new StoreRef(storeUrl); + } + + /** + * Get the service registry. + * + * @return + */ + protected ServiceRegistry getServiceRegistry() + { + return serviceRegistry; + } + + /** + * Set the service registry. + * + * @param serviceRegistry + */ + public void setServiceRegistry(ServiceRegistry serviceRegistry) + { + this.serviceRegistry = serviceRegistry; + } + + /** + * Inherit permissions when home folder are created? + * + * @param inheritsPermissionsOnCreate + */ + public void setInheritsPermissionsOnCreate(boolean inheritsPermissionsOnCreate) + { + this.inheritsPermissionsOnCreate = inheritsPermissionsOnCreate; + } + + /** + * The owner to set on create. + * + * @param ownerOnCreate + */ + public void setOwnerOnCreate(String ownerOnCreate) + { + this.ownerOnCreate = ownerOnCreate; + } + + /** + * The owner permissions to set on create. + * + * @param ownerPemissionsToSetOnCreate + */ + public void setOwnerPemissionsToSetOnCreate(Set ownerPemissionsToSetOnCreate) + { + this.ownerPemissionsToSetOnCreate = ownerPemissionsToSetOnCreate; + } + + /** + * General permissions to set on create. + * + * @param permissionsToSetOnCreate + */ + public void setPermissionsToSetOnCreate(Map> permissionsToSetOnCreate) + { + this.permissionsToSetOnCreate = permissionsToSetOnCreate; + } + + /** + * User permissions to set on create and on reference. + * + * @param userPemissions + */ + public void setUserPemissions(Set userPemissions) + { + this.userPemissions = userPemissions; + } + + /** + * Clear exising permissions on create. Useful to clear permissions from a template. + * + * @param clearExistingPermissionsOnCreate + */ + public void setClearExistingPermissionsOnCreate(boolean clearExistingPermissionsOnCreate) + { + this.clearExistingPermissionsOnCreate = clearExistingPermissionsOnCreate; + } + + /** + * Cache path to node resolution/ + * + * @return + */ + protected synchronized NodeRef getPathNodeRef() + { + if (pathNodeRef == null) + { + pathNodeRef = resolvePath(path); + } + return pathNodeRef; + } + + /** + * Utility metho to resolve paths to nodes. + * + * @param pathToResolve + * @return + */ + protected NodeRef resolvePath(String pathToResolve) + { + List refs = serviceRegistry.getSearchService().selectNodes( + serviceRegistry.getNodeService().getRootNode(storeRef), pathToResolve, null, + serviceRegistry.getNamespaceService(), false); + if (refs.size() != 1) + { + throw new IllegalStateException("Non-unique path: found : " + pathToResolve + " " + refs.size()); + } + return refs.get(0); + } + + /** + * The implementation of the policy binding. Run as the system user for auditing. + */ + public void onCreateNode(ChildAssociationRef childAssocRef) + { + AuthenticationUtil.RunAsWork action = new OnCreateNode(childAssocRef); + AuthenticationUtil.runAs(action, AuthenticationUtil.getSystemUserName()); + } + + /** + * Abstract implementation to find/create the approriate home space. + * + * @param person + * @return + */ + protected abstract HomeSpaceNodeRef getHomeFolder(NodeRef person); + + /** + * Helper class to encapsulate the createion settinhg permissions etc + * + * @author Andy Hind + */ + private class OnCreateNode implements AuthenticationUtil.RunAsWork + { + ChildAssociationRef childAssocRef; + + OnCreateNode(ChildAssociationRef childAssocRef) + { + this.childAssocRef = childAssocRef; + } + + public NodeRef doWork() throws Exception + { + + // Find person + NodeRef personNodeRef = childAssocRef.getChildRef(); + // Get home folder + HomeSpaceNodeRef homeFolder = getHomeFolder(personNodeRef); + // If it exists + if (homeFolder.getNodeRef() != null) + { + // Get uid and keep + String uid = DefaultTypeConverter.INSTANCE.convert(String.class, serviceRegistry.getNodeService() + .getProperty(personNodeRef, ContentModel.PROP_USERNAME)); + + // If created or found then set (other wise it was already set correctly) + if (homeFolder.getStatus() != HomeSpaceNodeRef.Status.VALID) + { + serviceRegistry.getNodeService().setProperty(personNodeRef, ContentModel.PROP_HOMEFOLDER, + homeFolder.getNodeRef()); + } + + // If created.. + if (homeFolder.getStatus() == HomeSpaceNodeRef.Status.CREATED) + { + // Set to a specified owner or make owned by the person. + if (ownerOnCreate != null) + { + serviceRegistry.getOwnableService().setOwner(homeFolder.getNodeRef(), ownerOnCreate); + } + else + { + + serviceRegistry.getOwnableService().setOwner(homeFolder.getNodeRef(), uid); + } + + // clear permissions - useful of not required from a template + + if (clearExistingPermissionsOnCreate) + { + serviceRegistry.getPermissionService().deletePermissions(homeFolder.getNodeRef()); + } + + // inherit permissions + + serviceRegistry.getPermissionService().setInheritParentPermissions(homeFolder.getNodeRef(), + inheritsPermissionsOnCreate); + + // Set owner permissions + + if (ownerPemissionsToSetOnCreate != null) + { + for (String permission : ownerPemissionsToSetOnCreate) + { + serviceRegistry.getPermissionService().setPermission(homeFolder.getNodeRef(), + PermissionService.OWNER_AUTHORITY, permission, true); + } + } + + // Add other permissions + + if (permissionsToSetOnCreate != null) + { + for (String user : permissionsToSetOnCreate.keySet()) + { + Set set = permissionsToSetOnCreate.get(user); + if (set != null) + { + for (String permission : set) + { + serviceRegistry.getPermissionService().setPermission(homeFolder.getNodeRef(), user, + permission, true); + } + } + } + } + } + + // Add user permissions on create and reference + + if (userPemissions != null) + { + for (String permission : userPemissions) + { + serviceRegistry.getPermissionService().setPermission(homeFolder.getNodeRef(), uid, permission, + true); + } + } + } + return homeFolder.getNodeRef(); + + } + } + +} diff --git a/source/java/org/alfresco/repo/security/person/BootstrapHomeFolderProvider.java b/source/java/org/alfresco/repo/security/person/BootstrapHomeFolderProvider.java new file mode 100644 index 0000000000..c48ee1ae55 --- /dev/null +++ b/source/java/org/alfresco/repo/security/person/BootstrapHomeFolderProvider.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.security.person; + +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Provider to use in the boostrap process - does nothing + * + * Probably not required as behaviour/policies are disabled during normal import. + * + * @author Andy Hind + */ +public class BootstrapHomeFolderProvider extends AbstractHomeFolderProvider +{ + + @Override + protected HomeSpaceNodeRef getHomeFolder(NodeRef person) + { + return new HomeSpaceNodeRef(null, HomeSpaceNodeRef.Status.VALID); + } + +} diff --git a/source/java/org/alfresco/repo/security/person/ExistingPathBasedHomeFolderProvider.java b/source/java/org/alfresco/repo/security/person/ExistingPathBasedHomeFolderProvider.java new file mode 100644 index 0000000000..fc4caba1be --- /dev/null +++ b/source/java/org/alfresco/repo/security/person/ExistingPathBasedHomeFolderProvider.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.security.person; + +import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; + +/** + * Set a home space from a simple path. + * + * @author Andy Hind + */ +public class ExistingPathBasedHomeFolderProvider extends AbstractHomeFolderProvider +{ + + public ExistingPathBasedHomeFolderProvider() + { + super(); + } + + protected HomeSpaceNodeRef getHomeFolder(NodeRef person) + { + NodeRef existingHomeFolder = DefaultTypeConverter.INSTANCE.convert(NodeRef.class, getServiceRegistry().getNodeService().getProperty( + person, ContentModel.PROP_HOMEFOLDER)); + if (existingHomeFolder == null) + { + return new HomeSpaceNodeRef(getPathNodeRef(), HomeSpaceNodeRef.Status.REFERENCED); + } + else + { + return new HomeSpaceNodeRef(existingHomeFolder, HomeSpaceNodeRef.Status.VALID); + } + } + +} diff --git a/source/java/org/alfresco/repo/security/person/HomeFolderManager.java b/source/java/org/alfresco/repo/security/person/HomeFolderManager.java new file mode 100644 index 0000000000..0327f11820 --- /dev/null +++ b/source/java/org/alfresco/repo/security/person/HomeFolderManager.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.security.person; + +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.policy.JavaBehaviour; +import org.alfresco.repo.policy.PolicyComponent; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.springframework.beans.factory.InitializingBean; + +/** + * Manage home folder creation by binding to events from the cm:person type. + * + * @author Andy Hind + */ +public class HomeFolderManager implements InitializingBean, NodeServicePolicies.OnCreateNodePolicy +{ + + private PolicyComponent policyComponent; + + private NodeService nodeService; + + /** + * A default provider + */ + private HomeFolderProvider defaultProvider; + + /** + * Providers that have registered and are looken up by name (== bean name) + */ + private Map providers = new HashMap(); + + /** + * Bind the calss behaviour to this implementation + */ + public void afterPropertiesSet() throws Exception + { + policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"), + ContentModel.TYPE_PERSON, new JavaBehaviour(this, "onCreateNode")); + } + + /** + * Set the policy component. + * + * @param policyComponent + */ + public void setPolicyComponent(PolicyComponent policyComponent) + { + this.policyComponent = policyComponent; + } + + /** + * Set the node service. + * @param nodeService + */ + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Register a home folder provider. + * + * @param provider + */ + public void addProvider(HomeFolderProvider provider) + { + providers.put(provider.getName(), provider); + } + + /** + * Set the default home folder provider (user which none is specified or when one is not found) + * @param defaultProvider + */ + public void setDefaultProvider(HomeFolderProvider defaultProvider) + { + this.defaultProvider = defaultProvider; + } + + /** + * Find the provider and call. + */ + public void onCreateNode(ChildAssociationRef childAssocRef) + { + HomeFolderProvider provider = defaultProvider; + String providerName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(childAssocRef + .getChildRef(), ContentModel.PROP_HOME_FOLDER_PROVIDER)); + if (providerName != null) + { + provider = providers.get(providerName); + if (provider == null) + { + provider = defaultProvider; + } + } + if (provider != null) + { + provider.onCreateNode(childAssocRef); + } + } +} diff --git a/source/java/org/alfresco/repo/security/person/HomeFolderProvider.java b/source/java/org/alfresco/repo/security/person/HomeFolderProvider.java new file mode 100644 index 0000000000..911a7c9b9c --- /dev/null +++ b/source/java/org/alfresco/repo/security/person/HomeFolderProvider.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.security.person; + +import org.alfresco.repo.node.NodeServicePolicies; + +/** + * Interface for home folder providers. + * + * @author Andy Hind + */ +public interface HomeFolderProvider extends NodeServicePolicies.OnCreateNodePolicy +{ + /** + * Get the name of the provider. + * + * @return + */ + public String getName(); +} diff --git a/source/java/org/alfresco/repo/security/person/HomeSpaceNodeRef.java b/source/java/org/alfresco/repo/security/person/HomeSpaceNodeRef.java new file mode 100644 index 0000000000..2edcf2f7a0 --- /dev/null +++ b/source/java/org/alfresco/repo/security/person/HomeSpaceNodeRef.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.security.person; + +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * A ref to a home folder + * - the node ref + * - a simple status as to how it was obtained + * + * @author Andy Hind + */ +public class HomeSpaceNodeRef +{ + public enum Status{VALID, REFERENCED, CREATED}; + + private NodeRef nodeRef; + + private Status status; + + public HomeSpaceNodeRef(NodeRef nodeRef, Status status) + { + this.nodeRef = nodeRef; + this.status = status; + } + + NodeRef getNodeRef() + { + return nodeRef; + } + + Status getStatus() + { + return status; + } + + +} diff --git a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java index 690dfa13c9..ea5571f075 100644 --- a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java +++ b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java @@ -1,410 +1,388 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.security.person; - -import java.io.Serializable; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.model.ContentModel; -import org.alfresco.repo.security.permissions.PermissionServiceSPI; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; -import org.alfresco.service.cmr.search.ResultSet; -import org.alfresco.service.cmr.search.ResultSetRow; -import org.alfresco.service.cmr.search.SearchParameters; -import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.cmr.security.AuthorityService; -import org.alfresco.service.cmr.security.NoSuchPersonException; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.namespace.NamespacePrefixResolver; -import org.alfresco.service.namespace.QName; - -public class PersonServiceImpl implements PersonService -{ - public static final String SYSTEM_FOLDER = "/sys:system"; - - public static final String PEOPLE_FOLDER = SYSTEM_FOLDER + "/sys:people"; - - // IOC - - private StoreRef storeRef; - - private NodeService nodeService; - - private SearchService searchService; - - private AuthorityService authorityService; - - private PermissionServiceSPI permissionServiceSPI; - - private NamespacePrefixResolver namespacePrefixResolver; - - private boolean createMissingPeople; - - private String companyHomePath; - - private NodeRef companyHomeNodeRef; - - private static Set mutableProperties; - - private boolean userNamesAreCaseSensitive = false; - - static - { - Set props = new HashSet(); - props.add(ContentModel.PROP_HOMEFOLDER); - props.add(ContentModel.PROP_FIRSTNAME); - // Middle Name - props.add(ContentModel.PROP_LASTNAME); - props.add(ContentModel.PROP_EMAIL); - props.add(ContentModel.PROP_ORGID); - mutableProperties = Collections.unmodifiableSet(props); - } - - public PersonServiceImpl() - { - super(); - } - - public boolean getUserNamesAreCaseSensitive() - { - return userNamesAreCaseSensitive; - } - - public void setUserNamesAreCaseSensitive(boolean userNamesAreCaseSensitive) - { - this.userNamesAreCaseSensitive = userNamesAreCaseSensitive; - } - - public NodeRef getPerson(String userName) - { - NodeRef personNode = getPersonOrNull(userName); - if (personNode == null) - { - if (createMissingPeople()) - { - return createMissingPerson(userName); - } - else - { - throw new NoSuchPersonException(userName); - } - - } - else - { - return personNode; - } - } - - public boolean personExists(String caseSensitiveUserName) - { - return getPersonOrNull(caseSensitiveUserName) != null; - } - - public NodeRef getPersonOrNull(String searchUserName) - { - SearchParameters sp = new SearchParameters(); - sp.setLanguage(SearchService.LANGUAGE_LUCENE); - sp.setQuery("TYPE:\\{http\\://www.alfresco.org/model/content/1.0\\}person +@cm\\:userName:\"" + searchUserName - + "\""); - sp.addStore(storeRef); - sp.excludeDataInTheCurrentTransaction(false); - - ResultSet rs = null; - - try - { - rs = searchService.query(sp); - - NodeRef returnRef = null; - - for (ResultSetRow row : rs) - { - - NodeRef nodeRef = row.getNodeRef(); - if (nodeService.exists(nodeRef)) - { - String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty( - nodeRef, ContentModel.PROP_USERNAME)); - - if (userNamesAreCaseSensitive) - { - if (realUserName.equals(searchUserName)) - { - if (returnRef == null) - { - returnRef = nodeRef; - } - else - { - throw new AlfrescoRuntimeException("Found more than one user for " + searchUserName - + " (case sensitive)"); - } - } - } - else - { - if (realUserName.equalsIgnoreCase(searchUserName)) - { - if (returnRef == null) - { - returnRef = nodeRef; - } - else - { - throw new AlfrescoRuntimeException("Found more than one user for " + searchUserName - + " (case insensitive)"); - } - } - } - } - } - - return returnRef; - } - finally - { - if (rs != null) - { - rs.close(); - } - } - } - - public boolean createMissingPeople() - { - return createMissingPeople; - } - - public Set getMutableProperties() - { - return mutableProperties; - } - - public void setPersonProperties(String userName, Map properties) - { - NodeRef personNode = getPersonOrNull(userName); - if (personNode == null) - { - if (createMissingPeople()) - { - personNode = createMissingPerson(userName); - } - else - { - throw new PersonException("No person found for user name " + userName); - } - - } - else - { - String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(personNode, - ContentModel.PROP_USERNAME)); - properties.put(ContentModel.PROP_USERNAME, realUserName); - } - - nodeService.setProperties(personNode, properties); - } - - public boolean isMutable() - { - return true; - } - - private NodeRef createMissingPerson(String userName) - { - HashMap properties = getDefaultProperties(userName); - return createPerson(properties); - } - - private HashMap getDefaultProperties(String userName) - { - HashMap properties = new HashMap(); - properties.put(ContentModel.PROP_USERNAME, userName); - properties.put(ContentModel.PROP_HOMEFOLDER, getHomeFolder()); - properties.put(ContentModel.PROP_FIRSTNAME, userName); - properties.put(ContentModel.PROP_LASTNAME, ""); - properties.put(ContentModel.PROP_EMAIL, ""); - properties.put(ContentModel.PROP_ORGID, ""); - return properties; - } - - private NodeRef getHomeFolder() - { - return getCompanyHome(); - } - - public NodeRef createPerson(Map properties) - { - String userName = DefaultTypeConverter.INSTANCE.convert(String.class, properties - .get(ContentModel.PROP_USERNAME)); - properties.put(ContentModel.PROP_USERNAME, userName); - return nodeService.createNode(getPeopleContainer(), ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_PERSON, - ContentModel.TYPE_PERSON, properties).getChildRef(); - } - - public NodeRef getPeopleContainer() - { - NodeRef rootNodeRef = nodeService.getRootNode(storeRef); - List results = searchService.selectNodes(rootNodeRef, PEOPLE_FOLDER, null, namespacePrefixResolver, - false); - if (results.size() == 0) - { - throw new AlfrescoRuntimeException("Required people system path not found: " + PEOPLE_FOLDER); - } - else - { - return results.get(0); - } - } - - public void deletePerson(String userName) - { - NodeRef personNodeRef = getPersonOrNull(userName); - - // delete the person - if (personNodeRef != null) - { - nodeService.deleteNode(personNodeRef); - } - - // remove user from any containing authorities - Set containerAuthorities = authorityService.getContainingAuthorities(null, userName, true); - for (String containerAuthority : containerAuthorities) - { - authorityService.removeAuthority(containerAuthority, userName); - } - - // remove any user permissions - permissionServiceSPI.deletePermissions(userName); - } - - public Set getAllPeople() - { - SearchParameters sp = new SearchParameters(); - sp.setLanguage(SearchService.LANGUAGE_LUCENE); - sp.setQuery("TYPE:\"" + ContentModel.TYPE_PERSON + "\""); - sp.addStore(storeRef); - sp.excludeDataInTheCurrentTransaction(false); - - LinkedHashSet nodes = new LinkedHashSet(); - ResultSet rs = null; - - try - { - rs = searchService.query(sp); - - for (ResultSetRow row : rs) - { - - NodeRef nodeRef = row.getNodeRef(); - if (nodeService.exists(nodeRef)) - { - nodes.add(nodeRef); - } - } - } - finally - { - if (rs != null) - { - rs.close(); - } - } - return nodes; - } - - public void setCreateMissingPeople(boolean createMissingPeople) - { - this.createMissingPeople = createMissingPeople; - } - - public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver) - { - this.namespacePrefixResolver = namespacePrefixResolver; - } - - public void setAuthorityService(AuthorityService authorityService) - { - this.authorityService = authorityService; - } - - public void setPermissionServiceSPI(PermissionServiceSPI permissionServiceSPI) - { - this.permissionServiceSPI = permissionServiceSPI; - } - - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - public void setSearchService(SearchService searchService) - { - this.searchService = searchService; - } - - public void setStoreUrl(String storeUrl) - { - this.storeRef = new StoreRef(storeUrl); - } - - public void setCompanyHomePath(String companyHomePath) - { - this.companyHomePath = companyHomePath; - } - - public synchronized NodeRef getCompanyHome() - { - if (companyHomeNodeRef == null) - { - List refs = searchService.selectNodes(nodeService.getRootNode(storeRef), companyHomePath, null, - namespacePrefixResolver, false); - if (refs.size() != 1) - { - throw new IllegalStateException("Invalid company home path: found : " + refs.size()); - } - companyHomeNodeRef = refs.get(0); - } - return companyHomeNodeRef; - } - - public String getUserIdentifier(String caseSensitiveUserName) - { - NodeRef nodeRef = getPersonOrNull(caseSensitiveUserName); - if ((nodeRef != null) && nodeService.exists(nodeRef)) - { - String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(nodeRef, - ContentModel.PROP_USERNAME)); - return realUserName; - } - return null; - } - - // IOC Setters - -} +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.security.person; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.permissions.PermissionServiceSPI; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.ResultSetRow; +import org.alfresco.service.cmr.search.SearchParameters; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.NoSuchPersonException; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.namespace.NamespacePrefixResolver; +import org.alfresco.service.namespace.QName; + +public class PersonServiceImpl implements PersonService +{ + public static final String SYSTEM_FOLDER = "/sys:system"; + + public static final String PEOPLE_FOLDER = SYSTEM_FOLDER + "/sys:people"; + + // IOC + + private StoreRef storeRef; + + private NodeService nodeService; + + private SearchService searchService; + + private AuthorityService authorityService; + + private PermissionServiceSPI permissionServiceSPI; + + private NamespacePrefixResolver namespacePrefixResolver; + + private boolean createMissingPeople; + + private static Set mutableProperties; + + private boolean userNamesAreCaseSensitive = false; + + private String defaultHomeFolderProvider; + + static + { + Set props = new HashSet(); + props.add(ContentModel.PROP_HOMEFOLDER); + props.add(ContentModel.PROP_FIRSTNAME); + // Middle Name + props.add(ContentModel.PROP_LASTNAME); + props.add(ContentModel.PROP_EMAIL); + props.add(ContentModel.PROP_ORGID); + mutableProperties = Collections.unmodifiableSet(props); + } + + public PersonServiceImpl() + { + super(); + } + + public boolean getUserNamesAreCaseSensitive() + { + return userNamesAreCaseSensitive; + } + + public void setUserNamesAreCaseSensitive(boolean userNamesAreCaseSensitive) + { + this.userNamesAreCaseSensitive = userNamesAreCaseSensitive; + } + + void setDefaultHomeFolderProvider(String defaultHomeFolderProvider) + { + this.defaultHomeFolderProvider = defaultHomeFolderProvider; + } + + public NodeRef getPerson(String userName) + { + NodeRef personNode = getPersonOrNull(userName); + if (personNode == null) + { + if (createMissingPeople()) + { + return createMissingPerson(userName); + } + else + { + throw new NoSuchPersonException(userName); + } + + } + else + { + return personNode; + } + } + + public boolean personExists(String caseSensitiveUserName) + { + return getPersonOrNull(caseSensitiveUserName) != null; + } + + public NodeRef getPersonOrNull(String searchUserName) + { + SearchParameters sp = new SearchParameters(); + sp.setLanguage(SearchService.LANGUAGE_LUCENE); + sp.setQuery("TYPE:\\{http\\://www.alfresco.org/model/content/1.0\\}person +@cm\\:userName:\"" + searchUserName + + "\""); + sp.addStore(storeRef); + sp.excludeDataInTheCurrentTransaction(false); + + ResultSet rs = null; + + try + { + rs = searchService.query(sp); + + NodeRef returnRef = null; + + for (ResultSetRow row : rs) + { + + NodeRef nodeRef = row.getNodeRef(); + if (nodeService.exists(nodeRef)) + { + String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty( + nodeRef, ContentModel.PROP_USERNAME)); + + if (userNamesAreCaseSensitive) + { + if (realUserName.equals(searchUserName)) + { + if (returnRef == null) + { + returnRef = nodeRef; + } + else + { + throw new AlfrescoRuntimeException("Found more than one user for " + searchUserName + + " (case sensitive)"); + } + } + } + else + { + if (realUserName.equalsIgnoreCase(searchUserName)) + { + if (returnRef == null) + { + returnRef = nodeRef; + } + else + { + throw new AlfrescoRuntimeException("Found more than one user for " + searchUserName + + " (case insensitive)"); + } + } + } + } + } + + return returnRef; + } + finally + { + if (rs != null) + { + rs.close(); + } + } + } + + public boolean createMissingPeople() + { + return createMissingPeople; + } + + public Set getMutableProperties() + { + return mutableProperties; + } + + public void setPersonProperties(String userName, Map properties) + { + NodeRef personNode = getPersonOrNull(userName); + if (personNode == null) + { + if (createMissingPeople()) + { + personNode = createMissingPerson(userName); + } + else + { + throw new PersonException("No person found for user name " + userName); + } + + } + else + { + String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(personNode, + ContentModel.PROP_USERNAME)); + properties.put(ContentModel.PROP_USERNAME, realUserName); + } + + nodeService.setProperties(personNode, properties); + } + + public boolean isMutable() + { + return true; + } + + private NodeRef createMissingPerson(String userName) + { + HashMap properties = getDefaultProperties(userName); + return createPerson(properties); + } + + private HashMap getDefaultProperties(String userName) + { + HashMap properties = new HashMap(); + properties.put(ContentModel.PROP_USERNAME, userName); + properties.put(ContentModel.PROP_FIRSTNAME, userName); + properties.put(ContentModel.PROP_LASTNAME, ""); + properties.put(ContentModel.PROP_EMAIL, ""); + properties.put(ContentModel.PROP_ORGID, ""); + properties.put(ContentModel.PROP_HOME_FOLDER_PROVIDER, defaultHomeFolderProvider); + return properties; + } + + public NodeRef createPerson(Map properties) + { + String userName = DefaultTypeConverter.INSTANCE.convert(String.class, properties + .get(ContentModel.PROP_USERNAME)); + properties.put(ContentModel.PROP_USERNAME, userName); + return nodeService.createNode(getPeopleContainer(), ContentModel.ASSOC_CHILDREN, ContentModel.TYPE_PERSON, + ContentModel.TYPE_PERSON, properties).getChildRef(); + } + + public NodeRef getPeopleContainer() + { + NodeRef rootNodeRef = nodeService.getRootNode(storeRef); + List results = searchService.selectNodes(rootNodeRef, PEOPLE_FOLDER, null, namespacePrefixResolver, + false); + if (results.size() == 0) + { + throw new AlfrescoRuntimeException("Required people system path not found: " + PEOPLE_FOLDER); + } + else + { + return results.get(0); + } + } + + public void deletePerson(String userName) + { + NodeRef personNodeRef = getPersonOrNull(userName); + + // delete the person + if (personNodeRef != null) + { + nodeService.deleteNode(personNodeRef); + } + + // remove user from any containing authorities + Set containerAuthorities = authorityService.getContainingAuthorities(null, userName, true); + for (String containerAuthority : containerAuthorities) + { + authorityService.removeAuthority(containerAuthority, userName); + } + + // remove any user permissions + permissionServiceSPI.deletePermissions(userName); + } + + public Set getAllPeople() + { + SearchParameters sp = new SearchParameters(); + sp.setLanguage(SearchService.LANGUAGE_LUCENE); + sp.setQuery("TYPE:\"" + ContentModel.TYPE_PERSON + "\""); + sp.addStore(storeRef); + sp.excludeDataInTheCurrentTransaction(false); + + LinkedHashSet nodes = new LinkedHashSet(); + ResultSet rs = null; + + try + { + rs = searchService.query(sp); + + for (ResultSetRow row : rs) + { + + NodeRef nodeRef = row.getNodeRef(); + if (nodeService.exists(nodeRef)) + { + nodes.add(nodeRef); + } + } + } + finally + { + if (rs != null) + { + rs.close(); + } + } + return nodes; + } + + public void setCreateMissingPeople(boolean createMissingPeople) + { + this.createMissingPeople = createMissingPeople; + } + + public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver) + { + this.namespacePrefixResolver = namespacePrefixResolver; + } + + public void setAuthorityService(AuthorityService authorityService) + { + this.authorityService = authorityService; + } + + public void setPermissionServiceSPI(PermissionServiceSPI permissionServiceSPI) + { + this.permissionServiceSPI = permissionServiceSPI; + } + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + public void setSearchService(SearchService searchService) + { + this.searchService = searchService; + } + + public void setStoreUrl(String storeUrl) + { + this.storeRef = new StoreRef(storeUrl); + } + + public String getUserIdentifier(String caseSensitiveUserName) + { + NodeRef nodeRef = getPersonOrNull(caseSensitiveUserName); + if ((nodeRef != null) && nodeService.exists(nodeRef)) + { + String realUserName = DefaultTypeConverter.INSTANCE.convert(String.class, nodeService.getProperty(nodeRef, + ContentModel.PROP_USERNAME)); + return realUserName; + } + return null; + } + + // IOC Setters + +} diff --git a/source/java/org/alfresco/repo/security/person/UIDBasedHomeFolderProvider.java b/source/java/org/alfresco/repo/security/person/UIDBasedHomeFolderProvider.java new file mode 100644 index 0000000000..1208023a48 --- /dev/null +++ b/source/java/org/alfresco/repo/security/person/UIDBasedHomeFolderProvider.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.security.person; + +import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.model.FileInfo; +import org.alfresco.service.cmr.model.FileNotFoundException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; + +/** + * Create home spaces based on the UID of the user. + * + * If a suitable space is found it is reused, if not it will be made. + * + * @author Andy Hind + */ +public class UIDBasedHomeFolderProvider extends ExistingPathBasedHomeFolderProvider +{ + private String templatePath; + + private NodeRef templateNodeRef; + + public UIDBasedHomeFolderProvider() + { + super(); + } + + public void setTemplatePath(String templatePath) + { + this.templatePath = templatePath; + } + + protected HomeSpaceNodeRef getHomeFolder(NodeRef person) + { + NodeRef existingHomeFolder = DefaultTypeConverter.INSTANCE.convert(NodeRef.class, getServiceRegistry() + .getNodeService().getProperty(person, ContentModel.PROP_HOMEFOLDER)); + if (existingHomeFolder == null) + { + String uid = DefaultTypeConverter.INSTANCE.convert(String.class, getServiceRegistry().getNodeService() + .getProperty(person, ContentModel.PROP_USERNAME)); + FileInfo fileInfo; + + // Test if it already exists + + NodeRef exising = getServiceRegistry().getFileFolderService().searchSimple(getPathNodeRef(), uid); + if (exising != null) + { + fileInfo = getServiceRegistry().getFileFolderService().getFileInfo(exising); + } + else + { + + if (templatePath == null) + { + fileInfo = getServiceRegistry().getFileFolderService().create(getPathNodeRef(), uid, + ContentModel.TYPE_FOLDER); + + } + else + { + try + { + fileInfo = getServiceRegistry().getFileFolderService().copy(getTemplateNodeRef(), + getPathNodeRef(), uid); + } + catch (FileNotFoundException e) + { + throw new PersonException("Invalid template to create home space"); + } + } + } + NodeRef homeFolderNodeRef = fileInfo.getNodeRef(); + return new HomeSpaceNodeRef(homeFolderNodeRef, HomeSpaceNodeRef.Status.CREATED); + } + else + { + return new HomeSpaceNodeRef(existingHomeFolder, HomeSpaceNodeRef.Status.VALID); + } + } + + protected synchronized NodeRef getTemplateNodeRef() + { + if (templateNodeRef == null) + { + templateNodeRef = resolvePath(templatePath); + } + return templateNodeRef; + } + +} diff --git a/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java b/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java index c5f4e42070..6ae52880b9 100644 --- a/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java +++ b/source/java/org/alfresco/repo/service/ServiceDescriptorRegistry.java @@ -1,354 +1,372 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.repo.service; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.alfresco.service.ServiceDescriptor; -import org.alfresco.service.ServiceRegistry; -import org.alfresco.service.cmr.action.ActionService; -import org.alfresco.service.cmr.audit.AuditService; -import org.alfresco.service.cmr.avm.AVMService; -import org.alfresco.service.cmr.avmsync.AVMSyncService; -import org.alfresco.service.cmr.coci.CheckOutCheckInService; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.lock.LockService; -import org.alfresco.service.cmr.model.FileFolderService; -import org.alfresco.service.cmr.repository.ContentService; -import org.alfresco.service.cmr.repository.CopyService; -import org.alfresco.service.cmr.repository.MimetypeService; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.repository.ScriptService; -import org.alfresco.service.cmr.repository.TemplateService; -import org.alfresco.service.cmr.rule.RuleService; -import org.alfresco.service.cmr.search.CategoryService; -import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.service.cmr.security.AuthorityService; -import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.cmr.version.VersionService; -import org.alfresco.service.cmr.view.ExporterService; -import org.alfresco.service.cmr.view.ImporterService; -import org.alfresco.service.cmr.workflow.WorkflowService; -import org.alfresco.service.descriptor.DescriptorService; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.service.transaction.TransactionService; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; - - -/** - * Implementation of a Service Registry based on the definition of - * Services contained within a Spring Bean Factory. - * - * @author David Caruana - */ -public class ServiceDescriptorRegistry - implements BeanFactoryAware, BeanFactoryPostProcessor, ServiceRegistry -{ - // Bean Factory within which the registry lives - private BeanFactory beanFactory = null; - - // Service Descriptor map - private Map descriptors = new HashMap(); - - - /* (non-Javadoc) - * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory) - */ - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException - { - Map beans = beanFactory.getBeansOfType(ServiceDescriptorMetaData.class); - Iterator iter = beans.entrySet().iterator(); - while (iter.hasNext()) - { - Map.Entry entry = (Map.Entry)iter.next(); - ServiceDescriptorMetaData metaData = (ServiceDescriptorMetaData)entry.getValue(); - QName serviceName = QName.createQName(metaData.getNamespace(), (String)entry.getKey()); - StoreRedirector redirector = (entry.getValue() instanceof StoreRedirector) ? (StoreRedirector)entry.getValue() : null; - BeanServiceDescriptor serviceDescriptor = new BeanServiceDescriptor(serviceName, metaData, redirector); - descriptors.put(serviceDescriptor.getQualifiedName(), serviceDescriptor); - } - } - - /* (non-Javadoc) - * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org.springframework.beans.factory.BeanFactory) - */ - public void setBeanFactory(BeanFactory beanFactory) throws BeansException - { - this.beanFactory = beanFactory; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.service.ServiceRegistry#getServices() - */ - public Collection getServices() - { - return Collections.unmodifiableSet(descriptors.keySet()); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.service.ServiceRegistry#isServiceProvided(org.alfresco.repo.ref.QName) - */ - public boolean isServiceProvided(QName service) - { - return descriptors.containsKey(service); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.service.ServiceRegistry#getServiceDescriptor(org.alfresco.repo.ref.QName) - */ - public ServiceDescriptor getServiceDescriptor(QName service) - { - return descriptors.get(service); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.service.ServiceRegistry#getService(org.alfresco.repo.ref.QName) - */ - public Object getService(QName service) - { - return beanFactory.getBean(service.getLocalName()); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getDescriptorService() - */ - public DescriptorService getDescriptorService() - { - return (DescriptorService)getService(DESCRIPTOR_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.service.ServiceRegistry#getNodeService() - */ - public NodeService getNodeService() - { - return (NodeService)getService(NODE_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.service.ServiceRegistry#getNodeService() - */ - public AuthenticationService getAuthenticationService() - { - return (AuthenticationService)getService(AUTHENTICATION_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.service.ServiceRegistry#getContentService() - */ - public ContentService getContentService() - { - return (ContentService)getService(CONTENT_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getMimetypeService() - */ - public MimetypeService getMimetypeService() - { - return (MimetypeService)getService(MIMETYPE_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.service.ServiceRegistry#getVersionService() - */ - public VersionService getVersionService() - { - return (VersionService)getService(VERSION_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.service.ServiceRegistry#getLockService() - */ - public LockService getLockService() - { - return (LockService)getService(LOCK_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.service.ServiceRegistry#getDictionaryService() - */ - public DictionaryService getDictionaryService() - { - return (DictionaryService)getService(DICTIONARY_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getSearchService() - */ - public SearchService getSearchService() - { - return (SearchService)getService(SEARCH_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getTransactionService() - */ - public TransactionService getTransactionService() - { - return (TransactionService)getService(TRANSACTION_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getCopyService() - */ - public CopyService getCopyService() - { - return (CopyService)getService(COPY_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getCheckOutCheckInService() - */ - public CheckOutCheckInService getCheckOutCheckInService() - { - return (CheckOutCheckInService)getService(COCI_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getCategoryService() - */ - public CategoryService getCategoryService() - { - return (CategoryService)getService(CATEGORY_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getNamespaceService() - */ - public NamespaceService getNamespaceService() - { - return (NamespaceService)getService(NAMESPACE_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getImporterService() - */ - public ImporterService getImporterService() - { - return (ImporterService)getService(IMPORTER_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getExporterService() - */ - public ExporterService getExporterService() - { - return (ExporterService)getService(EXPORTER_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getRuleService() - */ - public RuleService getRuleService() - { - return (RuleService)getService(RULE_SERVICE); - } - - /* - * (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getActionService() - */ - public ActionService getActionService() - { - return (ActionService)getService(ACTION_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getPermissionService() - */ - public PermissionService getPermissionService() - { - return (PermissionService)getService(PERMISSIONS_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getAuthorityService() - */ - public AuthorityService getAuthorityService() - { - return (AuthorityService)getService(AUTHORITY_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getTemplateService() - */ - public TemplateService getTemplateService() - { - return (TemplateService)getService(TEMPLATE_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getTemplateService() - */ - public FileFolderService getFileFolderService() - { - return (FileFolderService)getService(FILE_FOLDER_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getScriptService() - */ - public ScriptService getScriptService() - { - return (ScriptService)getService(SCRIPT_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getWorkflowService() - */ - public WorkflowService getWorkflowService() - { - return (WorkflowService)getService(WORKFLOW_SERVICE); - } - - /* (non-Javadoc) - * @see org.alfresco.service.ServiceRegistry#getWorkflowService() - */ - public AuditService getAuditService() - { - return (AuditService)getService(AUDIT_SERVICE); - } - - /** - * Get the AVMService. - * @return The AVMService or null if there is none. - */ - public AVMService getAVMService() - { - return (AVMService)getService(AVM_SERVICE); - } - - /** - * Get the AVM Sync Service. - * @return The AVM Sync Service. - */ - public AVMSyncService getAVMSyncService() - { - return (AVMSyncService)getService(AVM_SYNC_SERVICE); - } -} +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.service; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.alfresco.service.ServiceDescriptor; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.action.ActionService; +import org.alfresco.service.cmr.audit.AuditService; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avmsync.AVMSyncService; +import org.alfresco.service.cmr.coci.CheckOutCheckInService; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.lock.LockService; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.CopyService; +import org.alfresco.service.cmr.repository.MimetypeService; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.ScriptService; +import org.alfresco.service.cmr.repository.TemplateService; +import org.alfresco.service.cmr.rule.RuleService; +import org.alfresco.service.cmr.search.CategoryService; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.OwnableService; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.version.VersionService; +import org.alfresco.service.cmr.view.ExporterService; +import org.alfresco.service.cmr.view.ImporterService; +import org.alfresco.service.cmr.workflow.WorkflowService; +import org.alfresco.service.descriptor.DescriptorService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; + + +/** + * Implementation of a Service Registry based on the definition of + * Services contained within a Spring Bean Factory. + * + * @author David Caruana + */ +public class ServiceDescriptorRegistry + implements BeanFactoryAware, BeanFactoryPostProcessor, ServiceRegistry +{ + // Bean Factory within which the registry lives + private BeanFactory beanFactory = null; + + // Service Descriptor map + private Map descriptors = new HashMap(); + + + /* (non-Javadoc) + * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory) + */ + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException + { + Map beans = beanFactory.getBeansOfType(ServiceDescriptorMetaData.class); + Iterator iter = beans.entrySet().iterator(); + while (iter.hasNext()) + { + Map.Entry entry = (Map.Entry)iter.next(); + ServiceDescriptorMetaData metaData = (ServiceDescriptorMetaData)entry.getValue(); + QName serviceName = QName.createQName(metaData.getNamespace(), (String)entry.getKey()); + StoreRedirector redirector = (entry.getValue() instanceof StoreRedirector) ? (StoreRedirector)entry.getValue() : null; + BeanServiceDescriptor serviceDescriptor = new BeanServiceDescriptor(serviceName, metaData, redirector); + descriptors.put(serviceDescriptor.getQualifiedName(), serviceDescriptor); + } + } + + /* (non-Javadoc) + * @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org.springframework.beans.factory.BeanFactory) + */ + public void setBeanFactory(BeanFactory beanFactory) throws BeansException + { + this.beanFactory = beanFactory; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.service.ServiceRegistry#getServices() + */ + public Collection getServices() + { + return Collections.unmodifiableSet(descriptors.keySet()); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.service.ServiceRegistry#isServiceProvided(org.alfresco.repo.ref.QName) + */ + public boolean isServiceProvided(QName service) + { + return descriptors.containsKey(service); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.service.ServiceRegistry#getServiceDescriptor(org.alfresco.repo.ref.QName) + */ + public ServiceDescriptor getServiceDescriptor(QName service) + { + return descriptors.get(service); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.service.ServiceRegistry#getService(org.alfresco.repo.ref.QName) + */ + public Object getService(QName service) + { + return beanFactory.getBean(service.getLocalName()); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getDescriptorService() + */ + public DescriptorService getDescriptorService() + { + return (DescriptorService)getService(DESCRIPTOR_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.service.ServiceRegistry#getNodeService() + */ + public NodeService getNodeService() + { + return (NodeService)getService(NODE_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.service.ServiceRegistry#getNodeService() + */ + public AuthenticationService getAuthenticationService() + { + return (AuthenticationService)getService(AUTHENTICATION_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.service.ServiceRegistry#getContentService() + */ + public ContentService getContentService() + { + return (ContentService)getService(CONTENT_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getMimetypeService() + */ + public MimetypeService getMimetypeService() + { + return (MimetypeService)getService(MIMETYPE_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.service.ServiceRegistry#getVersionService() + */ + public VersionService getVersionService() + { + return (VersionService)getService(VERSION_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.service.ServiceRegistry#getLockService() + */ + public LockService getLockService() + { + return (LockService)getService(LOCK_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.service.ServiceRegistry#getDictionaryService() + */ + public DictionaryService getDictionaryService() + { + return (DictionaryService)getService(DICTIONARY_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getSearchService() + */ + public SearchService getSearchService() + { + return (SearchService)getService(SEARCH_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getTransactionService() + */ + public TransactionService getTransactionService() + { + return (TransactionService)getService(TRANSACTION_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getCopyService() + */ + public CopyService getCopyService() + { + return (CopyService)getService(COPY_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getCheckOutCheckInService() + */ + public CheckOutCheckInService getCheckOutCheckInService() + { + return (CheckOutCheckInService)getService(COCI_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getCategoryService() + */ + public CategoryService getCategoryService() + { + return (CategoryService)getService(CATEGORY_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getNamespaceService() + */ + public NamespaceService getNamespaceService() + { + return (NamespaceService)getService(NAMESPACE_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getImporterService() + */ + public ImporterService getImporterService() + { + return (ImporterService)getService(IMPORTER_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getExporterService() + */ + public ExporterService getExporterService() + { + return (ExporterService)getService(EXPORTER_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getRuleService() + */ + public RuleService getRuleService() + { + return (RuleService)getService(RULE_SERVICE); + } + + /* + * (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getActionService() + */ + public ActionService getActionService() + { + return (ActionService)getService(ACTION_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getPermissionService() + */ + public PermissionService getPermissionService() + { + return (PermissionService)getService(PERMISSIONS_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getAuthorityService() + */ + public AuthorityService getAuthorityService() + { + return (AuthorityService)getService(AUTHORITY_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getTemplateService() + */ + public TemplateService getTemplateService() + { + return (TemplateService)getService(TEMPLATE_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getTemplateService() + */ + public FileFolderService getFileFolderService() + { + return (FileFolderService)getService(FILE_FOLDER_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getScriptService() + */ + public ScriptService getScriptService() + { + return (ScriptService)getService(SCRIPT_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getWorkflowService() + */ + public WorkflowService getWorkflowService() + { + return (WorkflowService)getService(WORKFLOW_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getWorkflowService() + */ + public AuditService getAuditService() + { + return (AuditService)getService(AUDIT_SERVICE); + } + + /** + * Get the AVMService. + * @return The AVMService or null if there is none. + */ + public AVMService getAVMService() + { + return (AVMService)getService(AVM_SERVICE); + } + + /** + * Get the AVM Sync Service. + * @return The AVM Sync Service. + */ + public AVMSyncService getAVMSyncService() + { + return (AVMSyncService)getService(AVM_SYNC_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getOwnableService() + */ + public OwnableService getOwnableService() + { + return (OwnableService)getService(OWNABLE_SERVICE); + } + + /* (non-Javadoc) + * @see org.alfresco.service.ServiceRegistry#getPersonService() + */ + public PersonService getPersonService() + { + return (PersonService)getService(PERSON_SERVICE); + } +} diff --git a/source/java/org/alfresco/repo/transaction/DummyTransactionService.java b/source/java/org/alfresco/repo/transaction/DummyTransactionService.java index fa21ec0fc3..34bc47ebf4 100644 --- a/source/java/org/alfresco/repo/transaction/DummyTransactionService.java +++ b/source/java/org/alfresco/repo/transaction/DummyTransactionService.java @@ -45,6 +45,10 @@ public class DummyTransactionService implements TransactionService return false; } + public void setReadOnly(boolean readOnly) + { + } + public UserTransaction getUserTransaction() { return txn; diff --git a/source/java/org/alfresco/repo/transaction/TransactionAwareSingleton.java b/source/java/org/alfresco/repo/transaction/TransactionAwareSingleton.java new file mode 100644 index 0000000000..c383a2fc26 --- /dev/null +++ b/source/java/org/alfresco/repo/transaction/TransactionAwareSingleton.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.transaction; + +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; + +/** + * A transactionally-safe storage class for singleton objects. Changes to the singleton + * are only visibly promoted when the transaction is committed. + *

+ * + * private static final TransactionAwareSingleton MY_SINGLETON = new TransactionAwareSingleton(); + * + *

+ * All modifications to the singleton via {@link #get()} and {@link #put(T)} are made in a + * transaction-local manner and promoted to the shared value in a thread-safe manner upon + * transacton completion. Transaction-local changes take precedence over the shared value. + * + * @see org.alfresco.repo.transaction.AlfrescoTransactionSupport + * + * @author Derek Hulley + */ +public class TransactionAwareSingleton extends TransactionListenerAdapter +{ + private static final String TRANSACTION_KEY = "TransactionAwareSingleton.storage"; + + private final ReadLock singletonReadLock; + private final WriteLock singletonWriteLock; + private Object singletonValue; + + public TransactionAwareSingleton() + { + ReentrantReadWriteLock serverReadWriteLock = new ReentrantReadWriteLock(); + singletonReadLock = serverReadWriteLock.readLock(); + singletonWriteLock = serverReadWriteLock.writeLock(); + } + + private void setValue(Object value) + { + // get a write lock + singletonWriteLock.lock(); + try + { + singletonValue = value; + } + finally + { + singletonWriteLock.unlock(); + } + } + + private Object getValue() + { + // get a read lock + singletonReadLock.lock(); + try + { + return singletonValue; + } + finally + { + singletonReadLock.unlock(); + } + } + + /** + * @return Returns the transaction- and thread-safe wrapped instance + */ + @SuppressWarnings("unchecked") + public T get() + { + // an in-transaction value overrides the singleton + TransactionStorage storage = (TransactionStorage) AlfrescoTransactionSupport.getResource(TRANSACTION_KEY); + if (storage != null) + { + return (T) storage.newValue; + } + else + { + return (T) getValue(); + } + } + + /** + * Store the value in a transaction- and thread-safe manner. It will only be persisted + * at the end of the transaction but will be visible to the current transaction from + * this call onwards. + * + * @param value the value to store + */ + public void put(T value) + { + // the value is changing + TransactionStorage storage = (TransactionStorage) AlfrescoTransactionSupport.getResource(TRANSACTION_KEY); + if (storage == null) + { + // it has not changed before + storage = new TransactionStorage(); + AlfrescoTransactionSupport.bindResource(TRANSACTION_KEY, storage); + // listen to the transaction + AlfrescoTransactionSupport.bindListener(this); + } + storage.newValue = value; + } + + /** + * Promotes the storage value to the single value, if required + */ + public void afterCommit() + { + TransactionStorage storage = (TransactionStorage) AlfrescoTransactionSupport.getResource(TRANSACTION_KEY); + if (storage != null) + { + // the value was overridden + setValue(storage.newValue); + } + } + + /** + * In-transaction storage of the altered value + * @author Derek Hulley + */ + private static class TransactionStorage + { + public Object newValue; + } +} diff --git a/source/java/org/alfresco/repo/transaction/TransactionAwareSingletonTest.java b/source/java/org/alfresco/repo/transaction/TransactionAwareSingletonTest.java new file mode 100644 index 0000000000..546c9bcefa --- /dev/null +++ b/source/java/org/alfresco/repo/transaction/TransactionAwareSingletonTest.java @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.repo.transaction; + +import java.util.Random; + +import javax.transaction.UserTransaction; + +import junit.framework.TestCase; + +import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.springframework.context.ApplicationContext; + +/** + * @see org.alfresco.repo.transaction.TransactionAwareSingleton + * + * @author Derek Hulley + */ +public class TransactionAwareSingletonTest extends TestCase +{ + private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + private static Random rand = new Random(); + + /** the instance to test */ + private TransactionAwareSingleton singleton = new TransactionAwareSingleton(); + private static final Integer INTEGER_ONE = new Integer(1); + private static final Integer INTEGER_TWO = new Integer(2); + + private TransactionService transactionService; + + public void setUp() throws Exception + { + transactionService = (TransactionService) ctx.getBean("transactionComponent"); + } + + public void testCommit() throws Throwable + { + UserTransaction txn = transactionService.getUserTransaction(); + try + { + txn.begin(); + + singleton.put(INTEGER_ONE); + check(INTEGER_ONE, true); + check(null, false); + + // commit + txn.commit(); + } + catch (Throwable e) + { + try { txn.rollback(); } catch (Throwable ee) {} + throw e; + } + check(INTEGER_ONE, true); + check(INTEGER_ONE, false); + } + + public void testRollback() throws Throwable + { + UserTransaction txn = transactionService.getUserTransaction(); + try + { + txn.begin(); + + singleton.put(INTEGER_TWO); + check(INTEGER_TWO, true); + check(null, false); + + // rollback + txn.rollback(); + } + catch (Throwable e) + { + try { txn.rollback(); } catch (Throwable ee) {} + throw e; + } + check(null, true); + check(null, false); + } + + private static final int THREAD_COUNT = 20; + public void testThreadsCommit() throws Throwable + { + TestThread[] threads = new TestThread[THREAD_COUNT]; + for (int i = 0; i < THREAD_COUNT; i++) + { + TestThread thread = new TestThread(true); + thread.start(); + threads[i] = thread; + } + // wait for them to complete + for (int i = 0; i < THREAD_COUNT; i++) + { + while (threads[i].finished == false) + { + synchronized(this) + { + try { wait(20); } catch (Throwable e) {} + } + } + if (threads[i].error != null) + { + throw threads[i].error; + } + } + } + public void testThreadsRollback() throws Throwable + { + TestThread[] threads = new TestThread[THREAD_COUNT]; + for (int i = 0; i < THREAD_COUNT; i++) + { + TestThread thread = new TestThread(false); + thread.start(); + threads[i] = thread; + } + } + + /** + * Dumps random values into + * @author Derek Hulley + */ + private class TestThread extends Thread + { + private boolean finished = false; + private Throwable error; + private boolean commit; + private Integer value = new Integer((int)System.nanoTime()); + + public TestThread(boolean commit) + { + this.commit = commit; + } + @Override + public synchronized void run() + { + UserTransaction txn = transactionService.getUserTransaction(); + try + { + txn.begin(); + + singleton.put(value); + + // wait for some random time + try + { + wait((long)(rand.nextDouble() * 1000.0)); // wait up to a second + } + catch (InterruptedException e) + { + // ignore + } + + // check + check(value, true); + + if (commit) + { + txn.commit(); + } + else + { + // rollback + txn.rollback(); + } + } + catch (Throwable e) + { + try { txn.rollback(); } catch (Throwable ee) {} + this.error = e; + } + if (!commit) + { + try + { + // no thread changes + check(null, false); + } + catch (Throwable e) + { + error = e; + } + } + finished = true; + } + } + + private void check(final Integer expected, boolean inTransaction) + { + TransactionWork checkWork = new TransactionWork() + { + public Object doWork() throws Exception + { + Integer actual = singleton.get(); + assertTrue("Values don't match: " + expected + " != " + actual, actual == expected); + return null; + } + }; + if (inTransaction) + { + TransactionUtil.executeInUserTransaction(transactionService, checkWork); + } + else + { + TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, checkWork); + } + } +} diff --git a/source/java/org/alfresco/repo/workflow/StartWorkflowActionExecuter.java b/source/java/org/alfresco/repo/workflow/StartWorkflowActionExecuter.java index 0aa6c80b6d..eb4f2297af 100644 --- a/source/java/org/alfresco/repo/workflow/StartWorkflowActionExecuter.java +++ b/source/java/org/alfresco/repo/workflow/StartWorkflowActionExecuter.java @@ -31,20 +31,24 @@ import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.workflow.WorkflowDefinition; +import org.alfresco.service.cmr.workflow.WorkflowPath; import org.alfresco.service.cmr.workflow.WorkflowService; +import org.alfresco.service.cmr.workflow.WorkflowTask; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; /** * Simple workflow action executor * - * @author Roy Wetherall + * @author David Caruana */ public class StartWorkflowActionExecuter extends ActionExecuterAbstractBase { public static final String NAME = "start-workflow"; - public static final String PARAM_WORKFLOW_NAME = "workflowName"; + public static final String PARAM_END_START_TASK = "endStartTask"; + public static final String PARAM_START_TASK_TRANSITION = "startTaskTransition"; + // action dependencies private NamespaceService namespaceService; @@ -94,7 +98,9 @@ public class StartWorkflowActionExecuter extends ActionExecuterAbstractBase protected void addParameterDefinitions(List paramList) { paramList.add(new ParameterDefinitionImpl(PARAM_WORKFLOW_NAME, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_WORKFLOW_NAME))); - // TODO: Start Task Template parameter + paramList.add(new ParameterDefinitionImpl(PARAM_END_START_TASK, DataTypeDefinition.BOOLEAN, false, getParamDisplayLabel(PARAM_END_START_TASK))); + paramList.add(new ParameterDefinitionImpl(PARAM_START_TASK_TRANSITION, DataTypeDefinition.TEXT, false, getParamDisplayLabel(PARAM_START_TASK_TRANSITION))); + // TODO: start task node parameter } @@ -127,9 +133,31 @@ public class StartWorkflowActionExecuter extends ActionExecuterAbstractBase workflowParameters.put(qname, value); } } - + + // provide a default context, if one is not specified + Serializable context = workflowParameters.get(WorkflowModel.PROP_CONTEXT); + if (context == null) + { + workflowParameters.put(WorkflowModel.PROP_CONTEXT, childAssoc.getParentRef()); + } + // start the workflow - workflowService.startWorkflow(def.id, workflowParameters); + WorkflowPath path = workflowService.startWorkflow(def.id, workflowParameters); + + // determine whether to auto-end the start task + Boolean endStartTask = (Boolean)ruleAction.getParameterValue(PARAM_END_START_TASK); + String startTaskTransition = (String)ruleAction.getParameterValue(PARAM_START_TASK_TRANSITION); + endStartTask = (endStartTask == null) ? true : false; + startTaskTransition = (startTaskTransition == null) ? "" : startTaskTransition; + + // auto-end the start task with the provided transition (if one) + if (endStartTask) + { + List tasks = workflowService.getTasksForWorkflowPath(path.id); + for (WorkflowTask task : tasks) + { + workflowService.endTask(task.id, startTaskTransition); + } + } } - } diff --git a/source/java/org/alfresco/repo/workflow/StartWorkflowActionExecuterTest.java b/source/java/org/alfresco/repo/workflow/StartWorkflowActionExecuterTest.java index 8a635cbab3..369d30e706 100644 --- a/source/java/org/alfresco/repo/workflow/StartWorkflowActionExecuterTest.java +++ b/source/java/org/alfresco/repo/workflow/StartWorkflowActionExecuterTest.java @@ -31,9 +31,9 @@ import org.alfresco.util.BaseSpringTest; import org.alfresco.util.GUID; /** - * Add features action execution test + * Start Advanced Workflow action execution test * - * @author Roy Wetherall + * @author David Caruana */ public class StartWorkflowActionExecuterTest extends BaseSpringTest { @@ -78,9 +78,10 @@ public class StartWorkflowActionExecuterTest extends BaseSpringTest // Execute the action ActionImpl action = new ActionImpl(null, GUID.generate(), StartWorkflowActionExecuter.NAME, null); action.setParameterValue(StartWorkflowActionExecuter.PARAM_WORKFLOW_NAME, "jbpm$wf:review"); - action.setParameterValue(WorkflowModel.PROP_REVIEW_DUE_DATE.toPrefixString(namespaceService), new Date()); + action.setParameterValue(WorkflowModel.PROP_WORKFLOW_DUE_DATE.toPrefixString(namespaceService), new Date()); NodeRef reviewer = personService.getPerson("admin"); - action.setParameterValue(WorkflowModel.ASSOC_REVIEWER.toPrefixString(namespaceService), reviewer); + action.setParameterValue(WorkflowModel.ASSOC_ASSIGNEE.toPrefixString(namespaceService), reviewer); executer.execute(action, this.nodeRef); } + } diff --git a/source/java/org/alfresco/repo/workflow/WorkflowComponent.java b/source/java/org/alfresco/repo/workflow/WorkflowComponent.java index ea0065cc5c..15aebb5ec5 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowComponent.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowComponent.java @@ -118,6 +118,14 @@ public interface WorkflowComponent */ public List getActiveWorkflows(String workflowDefinitionId); + /** + * Gets a specific workflow instances + * + * @param workflowId the id of the workflow to retrieve + * @return the workflow instance + */ + public WorkflowInstance getWorkflowById(String workflowId); + /** * Gets all Paths for the specified Workflow instance * diff --git a/source/java/org/alfresco/repo/workflow/WorkflowDeployer.java b/source/java/org/alfresco/repo/workflow/WorkflowDeployer.java index e0020f37c8..0755746654 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowDeployer.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowDeployer.java @@ -16,12 +16,15 @@ */ package org.alfresco.repo.workflow; +import java.util.ArrayList; import java.util.List; import java.util.Properties; import javax.transaction.UserTransaction; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.dictionary.DictionaryBootstrap; +import org.alfresco.repo.dictionary.DictionaryDAO; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.service.cmr.view.ImporterException; import org.alfresco.service.cmr.workflow.WorkflowDeployment; @@ -56,7 +59,10 @@ public class WorkflowDeployer implements ApplicationListener private TransactionService transactionService; private WorkflowService workflowService; private AuthenticationComponent authenticationComponent; + private DictionaryDAO dictionaryDAO; private List workflowDefinitions; + private List models = new ArrayList(); + private List resourceBundles = new ArrayList(); /** @@ -89,6 +95,16 @@ public class WorkflowDeployer implements ApplicationListener this.authenticationComponent = authenticationComponent; } + /** + * Sets the Dictionary DAO + * + * @param dictionaryDAO + */ + public void setDictionaryDAO(DictionaryDAO dictionaryDAO) + { + this.dictionaryDAO = dictionaryDAO; + } + /** * Sets the Workflow Definitions * @@ -99,6 +115,26 @@ public class WorkflowDeployer implements ApplicationListener this.workflowDefinitions = workflowDefinitions; } + /** + * Sets the initial list of Workflow models to bootstrap with + * + * @param modelResources the model names + */ + public void setModels(List modelResources) + { + this.models = modelResources; + } + + /** + * Sets the initial list of Workflow reosurce bundles to bootstrap with + * + * @param modelResources the model names + */ + public void setLabels(List labels) + { + this.resourceBundles = labels; + } + /** * Deploy the Workflow Definitions */ @@ -124,6 +160,16 @@ public class WorkflowDeployer implements ApplicationListener { userTransaction.begin(); + // bootstrap the workflow models and labels + if (models != null && resourceBundles != null) + { + DictionaryBootstrap dictionaryBootstrap = new DictionaryBootstrap(); + dictionaryBootstrap.setDictionaryDAO(dictionaryDAO); + dictionaryBootstrap.setModels(models); + dictionaryBootstrap.setLabels(resourceBundles); + dictionaryBootstrap.bootstrap(); + } + // bootstrap the workflow definitions if (workflowDefinitions != null) { diff --git a/source/java/org/alfresco/repo/workflow/WorkflowModel.java b/source/java/org/alfresco/repo/workflow/WorkflowModel.java index 9f72746f5c..827911e3f7 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowModel.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowModel.java @@ -45,26 +45,24 @@ public interface WorkflowModel // workflow task contstants static final QName TYPE_WORKFLOW_TASK = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowTask"); static final QName PROP_CONTEXT = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "context"); + static final QName PROP_DESCRIPTION = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "description"); static final QName PROP_OUTCOME = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "outcome"); static final QName PROP_PACKAGE_ACTION_GROUP = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageActionGroup"); static final QName PROP_PACKAGE_ITEM_ACTION_GROUP = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "packageItemActionGroup"); static final QName ASSOC_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "package"); - + + // workflow task contstants + static final QName TYPE_START_TASK = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "startTask"); + static final QName PROP_WORKFLOW_DESCRIPTION = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDescription"); + static final QName PROP_WORKFLOW_PRIORITY = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowPriority"); + static final QName PROP_WORKFLOW_DUE_DATE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDueDate"); + static final QName ASSOC_ASSIGNEE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "assignee"); + // workflow package static final QName ASPECT_WORKFLOW_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowPackage"); + static final QName PROP_IS_SYSTEM_PACKAGE = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "isSystemPackage"); static final QName PROP_WORKFLOW_DEFINITION_ID = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDefinitionId"); static final QName PROP_WORKFLOW_DEFINITION_NAME = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowDefinitionName"); static final QName PROP_WORKFLOW_INSTANCE_ID = QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "workflowInstanceId"); - - - // - // Workflow Models - // - - // review & approve - static final QName TYPE_SUBMITREVIEW_TASK = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "submitReviewTask"); - static final QName PROP_REVIEW_PRIORITY = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "reviewPriority"); - static final QName PROP_REVIEW_DUE_DATE = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "reviewDueDate"); - static final QName ASSOC_REVIEWER = QName.createQName(NamespaceService.WORKFLOW_MODEL_1_0_URI, "reviewer"); - + } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/workflow/WorkflowPackageComponent.java b/source/java/org/alfresco/repo/workflow/WorkflowPackageComponent.java index 8a4675b3d2..72d8c4e572 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowPackageComponent.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowPackageComponent.java @@ -16,6 +16,8 @@ */ package org.alfresco.repo.workflow; +import java.util.List; + import org.alfresco.service.cmr.repository.NodeRef; @@ -38,6 +40,24 @@ public interface WorkflowPackageComponent */ public NodeRef createPackage(NodeRef container); - // TODO: Support for finding packages via meta-data of WorkflowPackage aspect + /** + * Deletes a Workflow Package + * + * The workflow package aspect is removed, and if the container was previously created by the workflow + * service (i.e. not provided from elsewhere), it will be deleted. + * + * @param container + */ + public void deletePackage(NodeRef container); + + // TODO: Further support for finding packages via meta-data of WorkflowPackage aspect + + /** + * Gets the Workflows that act upon the specified Repository content. + * + * @param packageItem the repository content item to get workflows for + * @return list of workflows which act upon the specified content + */ + public List getWorkflowIdsForContent(NodeRef packageItem); } diff --git a/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java b/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java index 3f15a29649..dc8737b20d 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java @@ -21,8 +21,6 @@ import java.util.List; import org.alfresco.model.ContentModel; import org.alfresco.repo.importer.ImporterBootstrap; -import org.alfresco.service.cmr.model.FileFolderService; -import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; @@ -31,6 +29,7 @@ import org.alfresco.service.cmr.workflow.WorkflowException; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.util.GUID; +import org.alfresco.util.ParameterCheck; /** @@ -41,14 +40,13 @@ import org.alfresco.util.GUID; */ public class WorkflowPackageImpl implements WorkflowPackageComponent { - private final static String PACKAGE_FOLDER = "Workflow Packages"; + private final static String PACKAGE_FOLDER = "packages"; // service dependencies private ImporterBootstrap bootstrap; private SearchService searchService; private NodeService nodeService; private NamespaceService namespaceService; - private FileFolderService fileFolderService; private NodeRef systemWorkflowContainer = null; @@ -60,14 +58,6 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent this.bootstrap = bootstrap; } - /** - * @param fileFolderService file folder service - */ - public void setFileFolderService(FileFolderService fileFolderService) - { - this.fileFolderService = fileFolderService; - } - /** * @param searchService search service */ @@ -99,17 +89,31 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent public NodeRef createPackage(NodeRef container) { // create a container, if one is not specified + boolean isSystemPackage = false; if (container == null) { // create simple folder in workflow system folder NodeRef system = getSystemWorkflowContainer(); // TODO: Consider structuring this folder, if number of children becomes an issue - List folders = new ArrayList(); - folders.add(PACKAGE_FOLDER); - folders.add(GUID.generate()); - FileInfo containerFolder = fileFolderService.makeFolders(system, folders, ContentModel.TYPE_FOLDER); - container = containerFolder.getNodeRef(); + NodeRef packages = null; + List results = searchService.selectNodes(system, "./" + NamespaceService.CONTENT_MODEL_PREFIX + ":" + PACKAGE_FOLDER, null, namespaceService, false); + if (results.size() > 0) + { + packages = results.get(0); + } + else + { + QName qname = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, PACKAGE_FOLDER); + ChildAssociationRef childRef = nodeService.createNode(system, ContentModel.ASSOC_CHILDREN, qname, ContentModel.TYPE_SYSTEM_FOLDER); + packages = childRef.getChildRef(); + } + + String containerName = "pkg_" + GUID.generate(); + QName qname = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, containerName); + ChildAssociationRef childRef = nodeService.createNode(packages, ContentModel.ASSOC_CONTAINS, qname, ContentModel.TYPE_SYSTEM_FOLDER); + container = childRef.getChildRef(); + isSystemPackage = true; } // attach workflow package @@ -118,11 +122,56 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent throw new WorkflowException("Container '" + container + "' is already a workflow package."); } nodeService.addAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE, null); + nodeService.setProperty(container, WorkflowModel.PROP_IS_SYSTEM_PACKAGE, isSystemPackage); // return container return container; } + /* (non-Javadoc) + * @see org.alfresco.repo.workflow.WorkflowPackageComponent#deletePackage(org.alfresco.service.cmr.repository.NodeRef) + */ + public void deletePackage(NodeRef container) + { + if (container != null && nodeService.exists(container) && nodeService.hasAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE)) + { + Boolean isSystemPackage = (Boolean)nodeService.getProperty(container, WorkflowModel.PROP_IS_SYSTEM_PACKAGE); + if (isSystemPackage != null && isSystemPackage.booleanValue()) + { + nodeService.deleteNode(container); + } + else + { + nodeService.removeAspect(container, WorkflowModel.ASPECT_WORKFLOW_PACKAGE); + } + } + } + + /* (non-Javadoc) + * @see org.alfresco.repo.workflow.WorkflowPackageComponent#getWorkflowIdsForContent(org.alfresco.service.cmr.repository.NodeRef, boolean) + */ + public List getWorkflowIdsForContent(NodeRef packageItem) + { + ParameterCheck.mandatory("packageItem", packageItem); + List workflowIds = new ArrayList(); + if (nodeService.exists(packageItem)) + { + List packageItemParents = nodeService.getParentAssocs(packageItem); + for (ChildAssociationRef packageItemParent : packageItemParents) + { + NodeRef parentRef = packageItemParent.getParentRef(); + if (nodeService.hasAspect(parentRef, WorkflowModel.ASPECT_WORKFLOW_PACKAGE)) + { + String workflowInstance = (String)nodeService.getProperty(parentRef, WorkflowModel.PROP_WORKFLOW_INSTANCE_ID); + if (workflowInstance != null && workflowInstance.length() > 0) + { + workflowIds.add(workflowInstance); + } + } + } + } + return workflowIds; + } /** * Gets the system workflow container for storing workflow related items @@ -142,7 +191,6 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent } return systemWorkflowContainer; } - /** * Finds the system workflow container @@ -165,7 +213,6 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent return systemWorkflowContainer; } - /** * Finds the system container * @@ -186,7 +233,6 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent } return nodeRefs.get(0); } - /** * Creates the System Workflow Container @@ -201,10 +247,10 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent { String name = bootstrap.getConfiguration().getProperty("system.workflow_container.childname"); QName qname = QName.createQName(name, namespaceService); - ChildAssociationRef childRef = nodeService.createNode(systemContainer, ContentModel.ASSOC_CHILDREN, qname, ContentModel.TYPE_FOLDER); + ChildAssociationRef childRef = nodeService.createNode(systemContainer, ContentModel.ASSOC_CHILDREN, qname, ContentModel.TYPE_CONTAINER); systemWorkflowContainer = childRef.getChildRef(); } return systemWorkflowContainer; } - + } diff --git a/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java b/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java index bdaac4c483..f290514867 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowServiceImpl.java @@ -185,6 +185,16 @@ public class WorkflowServiceImpl implements WorkflowService return component.getActiveWorkflows(workflowDefinitionId); } + /* (non-Javadoc) + * @see org.alfresco.service.cmr.workflow.WorkflowService#getWorkflowById(java.lang.String) + */ + public WorkflowInstance getWorkflowById(String workflowId) + { + String engineId = BPMEngineRegistry.getEngineId(workflowId); + WorkflowComponent component = getWorkflowComponent(engineId); + return component.getWorkflowById(workflowId); + } + /* (non-Javadoc) * @see org.alfresco.service.cmr.workflow.WorkflowService#getWorkflowPaths(java.lang.String) */ @@ -200,6 +210,8 @@ public class WorkflowServiceImpl implements WorkflowService */ public WorkflowInstance cancelWorkflow(String workflowId) { + WorkflowInstance instance = getWorkflowById(workflowId); + workflowPackageComponent.deletePackage(instance.workflowPackage); String engineId = BPMEngineRegistry.getEngineId(workflowId); WorkflowComponent component = getWorkflowComponent(engineId); return component.cancelWorkflow(workflowId); @@ -296,6 +308,27 @@ public class WorkflowServiceImpl implements WorkflowService { return workflowPackageComponent.createPackage(container); } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.workflow.WorkflowService#getWorkflowsForContent(org.alfresco.service.cmr.repository.NodeRef, boolean) + */ + public List getWorkflowsForContent(NodeRef packageItem, boolean active) + { + List workflowIds = workflowPackageComponent.getWorkflowIdsForContent(packageItem); + List workflowInstances = new ArrayList(workflowIds.size()); + for (String workflowId : workflowIds) + { + String engineId = BPMEngineRegistry.getEngineId(workflowId); + WorkflowComponent component = getWorkflowComponent(engineId); + WorkflowInstance instance = component.getWorkflowById(workflowId); + if (instance != null && instance.active == active) + { + workflowInstances.add(instance); + } + } + return workflowInstances; + } + /** * Gets the Workflow Component registered against the specified BPM Engine Id diff --git a/source/java/org/alfresco/repo/workflow/WorkflowServiceImplTest.java b/source/java/org/alfresco/repo/workflow/WorkflowServiceImplTest.java index 5747b33103..00214e2b6e 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowServiceImplTest.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowServiceImplTest.java @@ -16,15 +16,24 @@ */ package org.alfresco.repo.workflow; +import java.io.Serializable; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.workflow.WorkflowDefinition; +import org.alfresco.service.cmr.workflow.WorkflowInstance; import org.alfresco.service.cmr.workflow.WorkflowPath; import org.alfresco.service.cmr.workflow.WorkflowService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; import org.alfresco.util.BaseSpringTest; @@ -43,7 +52,7 @@ public class WorkflowServiceImplTest extends BaseSpringTest { workflowService = (WorkflowService)applicationContext.getBean(ServiceRegistry.WORKFLOW_SERVICE.getLocalName()); nodeService = (NodeService)applicationContext.getBean(ServiceRegistry.NODE_SERVICE.getLocalName()); - + // authenticate AuthenticationComponent auth = (AuthenticationComponent) applicationContext.getBean("authenticationComponent"); auth.setSystemUserAsCurrentUser(); @@ -77,4 +86,44 @@ public class WorkflowServiceImplTest extends BaseSpringTest assertTrue(nodeService.hasAspect(nodeRef, WorkflowModel.ASPECT_WORKFLOW_PACKAGE)); } + public void testAssociateWorkflowPackage() + { + // create workflow package + NodeRef rootRef = nodeService.getRootNode(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "spacesStore")); + NodeRef nodeRef = workflowService.createPackage(null); + assertNotNull(nodeRef); + assertTrue(nodeService.hasAspect(nodeRef, WorkflowModel.ASPECT_WORKFLOW_PACKAGE)); + ChildAssociationRef childAssoc = nodeService.createNode(rootRef, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_PREFIX, "test"), ContentModel.TYPE_CONTENT, null); + nodeService.addChild(nodeRef, childAssoc.getChildRef(), ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_PREFIX, "test")); + + // start workflow + List workflowDefs = workflowService.getDefinitions(); + assertNotNull(workflowDefs); + assertTrue(workflowDefs.size() > 0); + WorkflowDefinition workflowDef = workflowDefs.get(0); + Map parameters = new HashMap(); + parameters.put(WorkflowModel.ASSOC_PACKAGE, nodeRef); + WorkflowPath path = workflowService.startWorkflow(workflowDef.id, parameters); + assertNotNull(path); + assertTrue(path.active); + assertNotNull(path.node); + assertNotNull(path.instance); + assertEquals(workflowDef.id, path.instance.definition.id); + String workflowDefId = (String)nodeService.getProperty(nodeRef, WorkflowModel.PROP_WORKFLOW_DEFINITION_ID); + assertEquals(workflowDefId, workflowDef.id); + String workflowDefName = (String)nodeService.getProperty(nodeRef, WorkflowModel.PROP_WORKFLOW_DEFINITION_NAME); + assertEquals(workflowDefName, workflowDef.name); + String workflowInstanceId = (String)nodeService.getProperty(nodeRef, WorkflowModel.PROP_WORKFLOW_INSTANCE_ID); + assertEquals(workflowInstanceId, path.instance.id); + + // get workflows for content + List instances = workflowService.getWorkflowsForContent(childAssoc.getChildRef(), true); + assertNotNull(instances); + assertEquals(1, instances.size()); + assertEquals(instances.get(0).id, path.instance.id); + List completedInstances = workflowService.getWorkflowsForContent(childAssoc.getChildRef(), false); + assertNotNull(completedInstances); + assertEquals(0, completedInstances.size()); + } + } diff --git a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJavaScript.java b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJavaScript.java index b3bab2b2db..59f09962af 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJavaScript.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/AlfrescoJavaScript.java @@ -23,6 +23,7 @@ import java.util.Map; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.ScriptService; +import org.alfresco.service.cmr.workflow.WorkflowException; import org.dom4j.Element; import org.jbpm.context.def.VariableAccess; import org.jbpm.context.exe.ContextInstance; @@ -36,7 +37,7 @@ import org.xml.sax.InputSource; * A jBPM Action Handler for executing Alfresco Script * * The configuration of this action is as follows: - * + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/source/java/org/alfresco/service/ServiceRegistry.java b/source/java/org/alfresco/service/ServiceRegistry.java index eaa0796af9..570e270b78 100644 --- a/source/java/org/alfresco/service/ServiceRegistry.java +++ b/source/java/org/alfresco/service/ServiceRegistry.java @@ -1,292 +1,310 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.service; - -import java.util.Collection; - -import org.alfresco.service.cmr.action.ActionService; -import org.alfresco.service.cmr.audit.AuditService; -import org.alfresco.service.cmr.avm.AVMService; -import org.alfresco.service.cmr.avmsync.AVMSyncService; -import org.alfresco.service.cmr.coci.CheckOutCheckInService; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.lock.LockService; -import org.alfresco.service.cmr.model.FileFolderService; -import org.alfresco.service.cmr.repository.ContentService; -import org.alfresco.service.cmr.repository.CopyService; -import org.alfresco.service.cmr.repository.MimetypeService; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.repository.ScriptService; -import org.alfresco.service.cmr.repository.TemplateService; -import org.alfresco.service.cmr.rule.RuleService; -import org.alfresco.service.cmr.search.CategoryService; -import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.service.cmr.security.AuthorityService; -import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.cmr.version.VersionService; -import org.alfresco.service.cmr.view.ExporterService; -import org.alfresco.service.cmr.view.ImporterService; -import org.alfresco.service.cmr.workflow.WorkflowService; -import org.alfresco.service.descriptor.DescriptorService; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.service.transaction.TransactionService; - - -/** - * This interface represents the registry of public Repository Services. - * The registry provides meta-data about each service and provides - * access to the service interface. - * - * @author David Caruana - */ -@PublicService -public interface ServiceRegistry -{ - // Service Bean Names - - static final String SERVICE_REGISTRY = "ServiceRegistry"; - - static final QName REGISTRY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ServiceRegistry"); - static final QName DESCRIPTOR_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "DescriptorService"); - static final QName TRANSACTION_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "TransactionService"); - static final QName AUTHENTICATION_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "AuthenticationService"); - static final QName NAMESPACE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "NamespaceService"); - static final QName DICTIONARY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "DictionaryService"); - static final QName NODE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "NodeService"); - static final QName CONTENT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ContentService"); - static final QName MIMETYPE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "MimetypeService"); - static final QName SEARCH_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "SearchService"); - static final QName CATEGORY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CategoryService"); - static final QName COPY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CopyService"); - static final QName LOCK_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "LockService"); - static final QName VERSION_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "VersionService"); - static final QName COCI_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CheckoutCheckinService"); - static final QName RULE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "RuleService"); - static final QName IMPORTER_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ImporterService"); - static final QName EXPORTER_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ExporterService"); - static final QName ACTION_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ActionService"); - static final QName PERMISSIONS_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "PermissionService"); - static final QName AUTHORITY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "AuthorityService"); - static final QName TEMPLATE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "TemplateService"); - static final QName FILE_FOLDER_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "FileFolderService"); - static final QName SCRIPT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ScriptService"); - static final QName WORKFLOW_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "WorkflowService"); - static final QName AUDIT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "AuditService"); - static final QName AVM_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "AVMService"); - static final QName AVM_SYNC_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "AVMSyncService"); - - /** - * Get the list of services provided by the Repository - * - * @return list of provided Services - */ - @NotAuditable - Collection getServices(); - - /** - * Is the specified service provided by the Repository? - * - * @param service name of service to test provision of - * @return true => provided, false => not provided - */ - @NotAuditable - boolean isServiceProvided(QName service); - - /** - * Get meta-data about the specified service - * - * @param service name of service to retrieve meta data for - * @return the service meta data - */ - @NotAuditable - ServiceDescriptor getServiceDescriptor(QName service); - - /** - * Get the specified service. - * - * @param service name of service to retrieve - * @return the service interface (must cast to interface as described in service meta-data) - */ - @NotAuditable - Object getService(QName service); - - /** - * @return the descriptor service - */ - @NotAuditable - DescriptorService getDescriptorService(); - - /** - * @return the transaction service - */ - @NotAuditable - TransactionService getTransactionService(); - - /** - * @return the namespace service (or null, if one is not provided) - */ - @NotAuditable - NamespaceService getNamespaceService(); - - /** - * @return the authentication service (or null, if one is not provided) - */ - @NotAuditable - AuthenticationService getAuthenticationService(); - - /** - * @return the node service (or null, if one is not provided) - */ - @NotAuditable - NodeService getNodeService(); - - /** - * @return the content service (or null, if one is not provided) - */ - @NotAuditable - ContentService getContentService(); - - /** - * @return the mimetype service (or null, if one is not provided) - */ - @NotAuditable - MimetypeService getMimetypeService(); - - /** - * @return the search service (or null, if one is not provided) - */ - @NotAuditable - SearchService getSearchService(); - - /** - * @return the version service (or null, if one is not provided) - */ - @NotAuditable - VersionService getVersionService(); - - /** - * @return the lock service (or null, if one is not provided) - */ - @NotAuditable - LockService getLockService(); - - /** - * @return the dictionary service (or null, if one is not provided) - */ - @NotAuditable - DictionaryService getDictionaryService(); - - /** - * @return the copy service (or null, if one is not provided) - */ - @NotAuditable - CopyService getCopyService(); - - /** - * @return the checkout / checkin service (or null, if one is not provided) - */ - @NotAuditable - CheckOutCheckInService getCheckOutCheckInService(); - - /** - * @return the category service (or null, if one is not provided) - */ - @NotAuditable - CategoryService getCategoryService(); - - /** - * @return the importer service or null if not present - */ - @NotAuditable - ImporterService getImporterService(); - - /** - * @return the exporter service or null if not present - */ - @NotAuditable - ExporterService getExporterService(); - - /** - * @return the rule service (or null, if one is not provided) - */ - @NotAuditable - RuleService getRuleService(); - - /** - * @return the action service (or null if one is not provided) - */ - @NotAuditable - ActionService getActionService(); - - /** - * @return the permission service (or null if one is not provided) - */ - @NotAuditable - PermissionService getPermissionService(); - - /** - * @return the authority service (or null if one is not provided) - */ - @NotAuditable - AuthorityService getAuthorityService(); - - /** - * @return the template service (or null if one is not provided) - */ - @NotAuditable - TemplateService getTemplateService(); - - /** - * @return the file-folder manipulation service (or null if one is not provided) - */ - @NotAuditable - FileFolderService getFileFolderService(); - - /** - * @return the script execution service (or null if one is not provided) - */ - @NotAuditable - ScriptService getScriptService(); - - /** - * @return the workflow service (or null if one is not provided) - */ - @NotAuditable - WorkflowService getWorkflowService(); - - /** - * @return the audit service (or null if one is not provided) - */ - @NotAuditable - AuditService getAuditService(); - - /** - * Get the AVMService. - * @return The AVM service (or null if one is not provided); - */ - @NotAuditable - AVMService getAVMService(); - - /** - * Get the AVM Sync Service. - * @return The AVM Sync Service. - */ - @NotAuditable - AVMSyncService getAVMSyncService(); -} +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.service; + +import java.util.Collection; + +import org.alfresco.service.cmr.action.ActionService; +import org.alfresco.service.cmr.audit.AuditService; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avmsync.AVMSyncService; +import org.alfresco.service.cmr.coci.CheckOutCheckInService; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.lock.LockService; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.CopyService; +import org.alfresco.service.cmr.repository.MimetypeService; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.ScriptService; +import org.alfresco.service.cmr.repository.TemplateService; +import org.alfresco.service.cmr.rule.RuleService; +import org.alfresco.service.cmr.search.CategoryService; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.OwnableService; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.version.VersionService; +import org.alfresco.service.cmr.view.ExporterService; +import org.alfresco.service.cmr.view.ImporterService; +import org.alfresco.service.cmr.workflow.WorkflowService; +import org.alfresco.service.descriptor.DescriptorService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; + + +/** + * This interface represents the registry of public Repository Services. + * The registry provides meta-data about each service and provides + * access to the service interface. + * + * @author David Caruana + */ +@PublicService +public interface ServiceRegistry +{ + // Service Bean Names + + static final String SERVICE_REGISTRY = "ServiceRegistry"; + + static final QName REGISTRY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ServiceRegistry"); + static final QName DESCRIPTOR_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "DescriptorService"); + static final QName TRANSACTION_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "TransactionService"); + static final QName AUTHENTICATION_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "AuthenticationService"); + static final QName NAMESPACE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "NamespaceService"); + static final QName DICTIONARY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "DictionaryService"); + static final QName NODE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "NodeService"); + static final QName CONTENT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ContentService"); + static final QName MIMETYPE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "MimetypeService"); + static final QName SEARCH_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "SearchService"); + static final QName CATEGORY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CategoryService"); + static final QName COPY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CopyService"); + static final QName LOCK_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "LockService"); + static final QName VERSION_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "VersionService"); + static final QName COCI_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "CheckoutCheckinService"); + static final QName RULE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "RuleService"); + static final QName IMPORTER_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ImporterService"); + static final QName EXPORTER_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ExporterService"); + static final QName ACTION_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ActionService"); + static final QName PERMISSIONS_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "PermissionService"); + static final QName AUTHORITY_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "AuthorityService"); + static final QName TEMPLATE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "TemplateService"); + static final QName FILE_FOLDER_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "FileFolderService"); + static final QName SCRIPT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "ScriptService"); + static final QName WORKFLOW_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "WorkflowService"); + static final QName AUDIT_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "AuditService"); + static final QName OWNABLE_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "OwnableService"); + static final QName PERSON_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "PersonService"); + static final QName AVM_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "AVMService"); + static final QName AVM_SYNC_SERVICE = QName.createQName(NamespaceService.ALFRESCO_URI, "AVMSyncService"); + + /** + * Get the list of services provided by the Repository + * + * @return list of provided Services + */ + @NotAuditable + Collection getServices(); + + /** + * Is the specified service provided by the Repository? + * + * @param service name of service to test provision of + * @return true => provided, false => not provided + */ + @NotAuditable + boolean isServiceProvided(QName service); + + /** + * Get meta-data about the specified service + * + * @param service name of service to retrieve meta data for + * @return the service meta data + */ + @NotAuditable + ServiceDescriptor getServiceDescriptor(QName service); + + /** + * Get the specified service. + * + * @param service name of service to retrieve + * @return the service interface (must cast to interface as described in service meta-data) + */ + @NotAuditable + Object getService(QName service); + + /** + * @return the descriptor service + */ + @NotAuditable + DescriptorService getDescriptorService(); + + /** + * @return the transaction service + */ + @NotAuditable + TransactionService getTransactionService(); + + /** + * @return the namespace service (or null, if one is not provided) + */ + @NotAuditable + NamespaceService getNamespaceService(); + + /** + * @return the authentication service (or null, if one is not provided) + */ + @NotAuditable + AuthenticationService getAuthenticationService(); + + /** + * @return the node service (or null, if one is not provided) + */ + @NotAuditable + NodeService getNodeService(); + + /** + * @return the content service (or null, if one is not provided) + */ + @NotAuditable + ContentService getContentService(); + + /** + * @return the mimetype service (or null, if one is not provided) + */ + @NotAuditable + MimetypeService getMimetypeService(); + + /** + * @return the search service (or null, if one is not provided) + */ + @NotAuditable + SearchService getSearchService(); + + /** + * @return the version service (or null, if one is not provided) + */ + @NotAuditable + VersionService getVersionService(); + + /** + * @return the lock service (or null, if one is not provided) + */ + @NotAuditable + LockService getLockService(); + + /** + * @return the dictionary service (or null, if one is not provided) + */ + @NotAuditable + DictionaryService getDictionaryService(); + + /** + * @return the copy service (or null, if one is not provided) + */ + @NotAuditable + CopyService getCopyService(); + + /** + * @return the checkout / checkin service (or null, if one is not provided) + */ + @NotAuditable + CheckOutCheckInService getCheckOutCheckInService(); + + /** + * @return the category service (or null, if one is not provided) + */ + @NotAuditable + CategoryService getCategoryService(); + + /** + * @return the importer service or null if not present + */ + @NotAuditable + ImporterService getImporterService(); + + /** + * @return the exporter service or null if not present + */ + @NotAuditable + ExporterService getExporterService(); + + /** + * @return the rule service (or null, if one is not provided) + */ + @NotAuditable + RuleService getRuleService(); + + /** + * @return the action service (or null if one is not provided) + */ + @NotAuditable + ActionService getActionService(); + + /** + * @return the permission service (or null if one is not provided) + */ + @NotAuditable + PermissionService getPermissionService(); + + /** + * @return the authority service (or null if one is not provided) + */ + @NotAuditable + AuthorityService getAuthorityService(); + + /** + * @return the template service (or null if one is not provided) + */ + @NotAuditable + TemplateService getTemplateService(); + + /** + * @return the file-folder manipulation service (or null if one is not provided) + */ + @NotAuditable + FileFolderService getFileFolderService(); + + /** + * @return the script execution service (or null if one is not provided) + */ + @NotAuditable + ScriptService getScriptService(); + + /** + * @return the workflow service (or null if one is not provided) + */ + @NotAuditable + WorkflowService getWorkflowService(); + + /** + * @return the audit service (or null if one is not provided) + */ + @NotAuditable + AuditService getAuditService(); + + /** + * Get the AVMService. + * @return The AVM service (or null if one is not provided); + */ + @NotAuditable + AVMService getAVMService(); + + /** + * Get the AVM Sync Service. + * @return The AVM Sync Service. + */ + @NotAuditable + AVMSyncService getAVMSyncService(); + + /** + * Get the ownable service (or null if one is not provided) + * @return + */ + @NotAuditable + OwnableService getOwnableService(); + + /** + * Get the person service (or null if one is not provided) + * @return + */ + @NotAuditable + PersonService getPersonService(); +} diff --git a/source/java/org/alfresco/service/cmr/repository/CopyService.java b/source/java/org/alfresco/service/cmr/repository/CopyService.java index 33a2311e47..d69e77e82a 100644 --- a/source/java/org/alfresco/service/cmr/repository/CopyService.java +++ b/source/java/org/alfresco/service/cmr/repository/CopyService.java @@ -39,6 +39,10 @@ public interface CopyService * If the new node resides in a different workspace the new node will * have the same id. *

+ * NOTE: It is up to the client code to set the name of the newly created node. + * Use the {@link NodeService node service} and catch the + * {@link DuplicateChildNodeNameException} + *

* If the new node resides in the same workspace then * the new node will have the Copy aspect applied to it which will * reference the original node. diff --git a/source/java/org/alfresco/service/cmr/repository/NodeRef.java b/source/java/org/alfresco/service/cmr/repository/NodeRef.java index f16b838003..ea8c8a8874 100644 --- a/source/java/org/alfresco/service/cmr/repository/NodeRef.java +++ b/source/java/org/alfresco/service/cmr/repository/NodeRef.java @@ -36,6 +36,15 @@ public final class NodeRef implements EntityRef, Serializable private final StoreRef storeRef; private final String id; + /** + * @see #NodeRef(StoreRef, String) + * @see StoreRef#StoreRef(String, String) + */ + public NodeRef(String protocol, String identifier, String id) + { + this(new StoreRef(protocol, identifier), id); + } + /** * Construct a Node Reference from a Store Reference and Node Id * diff --git a/source/java/org/alfresco/service/cmr/repository/NodeService.java b/source/java/org/alfresco/service/cmr/repository/NodeService.java index 51c1f2c6f4..2b8c0aba46 100644 --- a/source/java/org/alfresco/service/cmr/repository/NodeService.java +++ b/source/java/org/alfresco/service/cmr/repository/NodeService.java @@ -1,564 +1,564 @@ -/* - * Copyright (C) 2005 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ -package org.alfresco.service.cmr.repository; - -import java.io.Serializable; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.service.Auditable; -import org.alfresco.service.PublicService; -import org.alfresco.service.cmr.dictionary.InvalidAspectException; -import org.alfresco.service.cmr.dictionary.InvalidTypeException; -import org.alfresco.service.namespace.QName; -import org.alfresco.service.namespace.QNamePattern; - -/** - * Interface for public and internal node and store operations. - * - * @author Derek Hulley - */ -@PublicService -public interface NodeService -{ - /** - * Gets a list of all available node store references - * - * @return Returns a list of store references - */ - @Auditable - public List getStores(); - - /** - * Create a new store for the given protocol and identifier. The implementation - * may create the store in any number of locations, including a database or - * Subversion. - * - * @param protocol the implementation protocol - * @param identifier the protocol-specific identifier - * @return Returns a reference to the store - * @throws StoreExistsException - */ - @Auditable(key = Auditable.Key.RETURN, parameters = {"protocol", "identifier"}) - public StoreRef createStore(String protocol, String identifier) throws StoreExistsException; - - /** - * @param storeRef a reference to the store to look for - * @return Returns true if the store exists, otherwise false - */ - @Auditable(parameters = {"storeRef"}) - public boolean exists(StoreRef storeRef); - - /** - * @param nodeRef a reference to the node to look for - * @return Returns true if the node exists, otherwise false - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) - public boolean exists(NodeRef nodeRef); - - /** - * Gets the ID of the last transaction that caused the node to change. This includes - * deletions, so it is possible that the node being referenced no longer exists. - * If the node never existed, then null is returned. - * - * @param nodeRef a reference to a current or previously existing node - * @return Returns the status of the node, or null if the node never existed - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) - public NodeRef.Status getNodeStatus(NodeRef nodeRef); - - /** - * @param storeRef a reference to an existing store - * @return Returns a reference to the root node of the store - * @throws InvalidStoreRefException if the store could not be found - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"storeRef"}) - public NodeRef getRootNode(StoreRef storeRef) throws InvalidStoreRefException; - - /** - * @see #createNode(NodeRef, QName, QName, QName, Map) - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"parentRef", "assocTypeQName", "assocQName", "nodeTypeQName"}) - public ChildAssociationRef createNode( - NodeRef parentRef, - QName assocTypeQName, - QName assocQName, - QName nodeTypeQName) - throws InvalidNodeRefException, InvalidTypeException; - - /** - * Creates a new, non-abstract, real node as a primary child of the given parent node. - * - * @param parentRef the parent node - * @param assocTypeQName the type of the association to create. This is used - * for verification against the data dictionary. - * @param assocQName the qualified name of the association - * @param nodeTypeQName a reference to the node type - * @param properties optional map of properties to keyed by their qualified names - * @return Returns a reference to the newly created child association - * @throws InvalidNodeRefException if the parent reference is invalid - * @throws InvalidTypeException if the node type reference is not recognised - * - * @see org.alfresco.service.cmr.dictionary.DictionaryService - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"parentRef", "assocTypeQName", "assocQName", "nodeTypeQName", "properties"}) - public ChildAssociationRef createNode( - NodeRef parentRef, - QName assocTypeQName, - QName assocQName, - QName nodeTypeQName, - Map properties) - throws InvalidNodeRefException, InvalidTypeException; - - /** - * Moves the primary location of the given node. - *

- * This involves changing the node's primary parent and possibly the name of the - * association referencing it. - *

- * If the new parent is in a different store from the original, then the entire - * node hierarchy is moved to the new store. Inter-store associations are not - * affected. - * - * @param nodeToMoveRef the node to move - * @param newParentRef the new parent of the moved node - * @param assocTypeQName the type of the association to create. This is used - * for verification against the data dictionary. - * @param assocQName the qualified name of the new child association - * @return Returns a reference to the newly created child association - * @throws InvalidNodeRefException if either the parent node or move node reference is invalid - * @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add - * - * @see #getPrimaryParent(NodeRef) - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeToMoveRef", "newParentRef", "assocTypeQName", "assocQName"}) - public ChildAssociationRef moveNode( - NodeRef nodeToMoveRef, - NodeRef newParentRef, - QName assocTypeQName, - QName assocQName) - throws InvalidNodeRefException; - - /** - * Set the ordering index of the child association. This affects the ordering of - * of the return values of methods that return a set of children or child - * associations. - * - * @param childAssocRef the child association that must be moved in the order - * @param index an arbitrary index that will affect the return order - * - * @see #getChildAssocs(NodeRef) - * @see #getChildAssocs(NodeRef, QNamePattern, QNamePattern) - * @see ChildAssociationRef#getNthSibling() - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"childAssocRef", "index"}) - public void setChildAssociationIndex( - ChildAssociationRef childAssocRef, - int index) - throws InvalidChildAssociationRefException; - - /** - * @param nodeRef - * @return Returns the type name - * @throws InvalidNodeRefException if the node could not be found - * - * @see org.alfresco.service.cmr.dictionary.DictionaryService - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) - public QName getType(NodeRef nodeRef) throws InvalidNodeRefException; - - /** - * Re-sets the type of the node. Can be called in order specialise a node to a sub-type. - * - * This should be used with caution since calling it changes the type of the node and thus - * implies a different set of aspects, properties and associations. It is the calling codes - * responsibility to ensure that the node is in a approriate state after changing the type. - * - * @param nodeRef the node reference - * @param typeQName the type QName - * - * @since 1.1 - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "typeQName"}) - public void setType(NodeRef nodeRef, QName typeQName) throws InvalidNodeRefException; - - /** - * Applies an aspect to the given node. After this method has been called, - * the node with have all the aspect-related properties present - * - * @param nodeRef - * @param aspectTypeQName the aspect to apply to the node - * @param aspectProperties a minimum of the mandatory properties required for - * the aspect - * @throws InvalidNodeRefException - * @throws InvalidAspectException if the class reference is not to a valid aspect - * - * @see org.alfresco.service.cmr.dictionary.DictionaryService#getAspect(QName) - * @see org.alfresco.service.cmr.dictionary.ClassDefinition#getProperties() - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "aspectTypeQName", "aspectProperties"}) - public void addAspect( - NodeRef nodeRef, - QName aspectTypeQName, - Map aspectProperties) - throws InvalidNodeRefException, InvalidAspectException; - - /** - * Remove an aspect and all related properties from a node - * - * @param nodeRef - * @param aspectTypeQName the type of aspect to remove - * @throws InvalidNodeRefException if the node could not be found - * @throws InvalidAspectException if the the aspect is unknown or if the - * aspect is mandatory for the class of the node - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "aspectTypeQName"}) - public void removeAspect(NodeRef nodeRef, QName aspectTypeQName) - throws InvalidNodeRefException, InvalidAspectException; - - /** - * Determines if a given aspect is present on a node. Aspects may only be - * removed if they are NOT mandatory. - * - * @param nodeRef - * @param aspectTypeQName - * @return Returns true if the aspect has been applied to the given node, - * otherwise false - * @throws InvalidNodeRefException if the node could not be found - * @throws InvalidAspectException if the aspect reference is invalid - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "aspectTypeQName"}) - public boolean hasAspect(NodeRef nodeRef, QName aspectTypeQName) - throws InvalidNodeRefException, InvalidAspectException; - - /** - * @param nodeRef - * @return Returns a set of all aspects applied to the node, including mandatory - * aspects - * @throws InvalidNodeRefException if the node could not be found - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) - public Set getAspects(NodeRef nodeRef) throws InvalidNodeRefException; - - /** - * Deletes the given node. - *

- * All associations (both children and regular node associations) - * will be deleted, and where the given node is the primary parent, - * the children will also be cascade deleted. - * - * @param nodeRef reference to a node within a store - * @throws InvalidNodeRefException if the reference given is invalid - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) - public void deleteNode(NodeRef nodeRef) throws InvalidNodeRefException; - - /** - * Makes a parent-child association between the given nodes. Both nodes must belong to the same store. - *

- * - * - * @param parentRef - * @param childRef - * @param assocTypeQName the qualified name of the association type as defined in the datadictionary - * @param qname the qualified name of the association - * @return Returns a reference to the newly created child association - * @throws InvalidNodeRefException if the parent or child nodes could not be found - * @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"parentRef", "childRef", "assocTypeQName", "qname"}) - public ChildAssociationRef addChild( - NodeRef parentRef, - NodeRef childRef, - QName assocTypeQName, - QName qname) throws InvalidNodeRefException; - - /** - * Severs all parent-child relationships between two nodes. - *

- * The child node will be cascade deleted if one of the associations was the - * primary association, i.e. the one with which the child node was created. - * - * @param parentRef the parent end of the association - * @param childRef the child end of the association - * @throws InvalidNodeRefException if the parent or child nodes could not be found - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"parentRef", "childRef"}) - public void removeChild(NodeRef parentRef, NodeRef childRef) throws InvalidNodeRefException; - - /** - * @param nodeRef - * @return Returns all properties keyed by their qualified name - * @throws InvalidNodeRefException if the node could not be found - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) - public Map getProperties(NodeRef nodeRef) throws InvalidNodeRefException; - - /** - * @param nodeRef - * @param qname the qualified name of the property - * @return Returns the value of the property, or null if not yet set - * @throws InvalidNodeRefException if the node could not be found - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "qname"}) - public Serializable getProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException; - - /** - * Set the values of all properties to be an Serializable instances. - * The properties given must still fulfill the requirements of the class and - * aspects relevant to the node. - *

- * NOTE: Null values are allowed. - * - * @param nodeRef - * @param properties all the properties of the node keyed by their qualified names - * @throws InvalidNodeRefException if the node could not be found - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "properties"}) - public void setProperties(NodeRef nodeRef, Map properties) throws InvalidNodeRefException; - - /** - * Sets the value of a property to be any Serializable instance. - * To remove a property value, use {@link #getProperties(NodeRef)}, remove the - * value and call {@link #setProperties(NodeRef, Map)}. - *

- * NOTE: Null values are allowed. - * - * @param nodeRef - * @param qname the fully qualified name of the property - * @param propertyValue the value of the property - never null - * @throws InvalidNodeRefException if the node could not be found - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "qname", "value"}) - public void setProperty(NodeRef nodeRef, QName qname, Serializable value) throws InvalidNodeRefException; - - /** - * @param nodeRef the child node - * @return Returns a list of all parent-child associations that exist where the given - * node is the child - * @throws InvalidNodeRefException if the node could not be found - * - * @see #getParentAssocs(NodeRef, QNamePattern, QNamePattern) - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) - public List getParentAssocs(NodeRef nodeRef) throws InvalidNodeRefException; - - /** - * Gets all parent associations where the pattern of the association qualified - * name is a match - *

- * The resultant list is ordered by (a) explicit index and (b) association creation time. - * - * @param nodeRef the child node - * @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 - * @return Returns a list of all parent-child associations that exist where the given - * node is the child - * @throws InvalidNodeRefException if the node could not be found - * - * @see ChildAssociationRef#getNthSibling() - * @see #setChildAssociationIndex(ChildAssociationRef, int) - * @see QName - * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "typeQNamePattern", "qnamePattern"}) - public List getParentAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern) - throws InvalidNodeRefException; - - /** - * Get all child associations of the given node. - *

- * The resultant list is ordered by (a) explicit index and (b) association creation time. - * - * @param nodeRef the parent node - usually a container - * @return Returns a collection of ChildAssocRef instances. If the - * node is not a container then the result will be empty. - * @throws InvalidNodeRefException if the node could not be found - * - * @see #getChildAssocs(NodeRef, QNamePattern, QNamePattern) - * @see #setChildAssociationIndex(ChildAssociationRef, int) - * @see ChildAssociationRef#getNthSibling() - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) - public List getChildAssocs(NodeRef nodeRef) throws InvalidNodeRefException; - - /** - * Gets all child associations where the pattern of the association qualified - * name is a match. - * - * @param nodeRef the parent node - usually a container - * @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 - * @return Returns a list of ChildAssocRef instances. If the - * node is not a container 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 getChildAssocs( - NodeRef nodeRef, - QNamePattern typeQNamePattern, - QNamePattern qnamePattern) - throws InvalidNodeRefException; - - /** - * Get the node with the given name within the context of the parent node. The name - * is case-insensitive as Alfresco has to support case-insensitive clients as standard. - * - * @param nodeRef the parent node - usuall a container - * @param assocTypeQName the type of the association - * @param childName the name of the node as per the property cm:name - * @return Returns the child node or null if not found - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "assocTypeQName", "childName"}) - public NodeRef getChildByName( - NodeRef nodeRef, - QName assocTypeQName, - String childName); - - /** - * Fetches the primary parent-child relationship. - *

- * For a root node, the parent node reference will be null. - * - * @param nodeRef - * @return Returns the primary parent-child association of the node - * @throws InvalidNodeRefException if the node could not be found - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) - public ChildAssociationRef getPrimaryParent(NodeRef nodeRef) throws InvalidNodeRefException; - - /** - * - * @param sourceRef a reference to a real node - * @param targetRef a reference to a node - * @param assocTypeQName the qualified name of the association type - * @return Returns a reference to the new association - * @throws InvalidNodeRefException if either of the nodes could not be found - * @throws AssociationExistsException - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"sourceRef", "targetRef", "assocTypeQName"}) - public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) - throws InvalidNodeRefException, AssociationExistsException; - - /** - * - * @param sourceRef the associaton source node - * @param targetRef the association target node - * @param assocTypeQName the qualified name of the association type - * @throws InvalidNodeRefException if either of the nodes could not be found - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"sourceRef", "targetRef", "assocTypeQName"}) - public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) - throws InvalidNodeRefException; - - /** - * Fetches all associations from the given source where the associations' - * qualified names match the pattern provided. - * - * @param sourceRef the association source - * @param qnamePattern the association qname pattern to match against - * @return Returns a list of NodeAssocRef instances for which the - * given node is a source - * @throws InvalidNodeRefException if the source node could not be found - * - * @see QName - * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"sourceRef", "qnamePattern"}) - public List getTargetAssocs(NodeRef sourceRef, QNamePattern qnamePattern) - throws InvalidNodeRefException; - - /** - * Fetches all associations to the given target where the associations' - * qualified names match the pattern provided. - * - * @param targetRef the association target - * @param qnamePattern the association qname pattern to match against - * @return Returns a list of NodeAssocRef instances for which the - * given node is a target - * @throws InvalidNodeRefException - * - * @see QName - * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"targetRef", "qnamePattern"}) - public List getSourceAssocs(NodeRef targetRef, QNamePattern qnamePattern) - throws InvalidNodeRefException; - - /** - * The root node has an entry in the path(s) returned. For this reason, there - * will always be at least one path element in the returned path(s). - * The first element will have a null parent reference and qname. - * - * @param nodeRef - * @return Returns the path to the node along the primary node path - * @throws InvalidNodeRefException if the node could not be found - * - * @see #getPaths(NodeRef, boolean) - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) - public Path getPath(NodeRef nodeRef) throws InvalidNodeRefException; - - /** - * The root node has an entry in the path(s) returned. For this reason, there - * will always be at least one path element in the returned path(s). - * The first element will have a null parent reference and qname. - * - * @param nodeRef - * @param primaryOnly true if only the primary path must be retrieved. If true, the - * result will have exactly one entry. - * @return Returns a List of all possible paths to the given node - * @throws InvalidNodeRefException if the node could not be found - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "primaryOnly"}) - public List getPaths(NodeRef nodeRef, boolean primaryOnly) throws InvalidNodeRefException; - - /** - * Get the node where archived items will have gone when deleted from the given store. - * - * @param storeRef the store that items were deleted from - * @return Returns the archive node parent - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"storeRef"}) - public NodeRef getStoreArchiveNode(StoreRef storeRef); - - /** - * Restore an individual node (along with its sub-tree nodes) to the target location. - * The archived node must have the {@link org.alfresco.model.ContentModel#ASPECT_ARCHIVED archived aspect} - * set against it. - * - * @param archivedNodeRef the archived node - * @param destinationParentNodeRef the parent to move the node into - * or null to use the original - * @param assocTypeQName the primary association type name to use in the new location - * or null to use the original - * @param assocQName the primary association name to use in the new location - * or null to use the original - * @return Returns the reference to the newly created node - */ - @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"archivedNodeRef", "destinationParentNodeRef", "assocTypeQName", "assocQName"}) - public NodeRef restoreNode( - NodeRef archivedNodeRef, - NodeRef destinationParentNodeRef, - QName assocTypeQName, - QName assocQName); -} +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.service.cmr.repository; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.alfresco.service.Auditable; +import org.alfresco.service.PublicService; +import org.alfresco.service.cmr.dictionary.InvalidAspectException; +import org.alfresco.service.cmr.dictionary.InvalidTypeException; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.QNamePattern; + +/** + * Interface for public and internal node and store operations. + * + * @author Derek Hulley + */ +@PublicService +public interface NodeService +{ + /** + * Gets a list of all available node store references + * + * @return Returns a list of store references + */ + @Auditable + public List getStores(); + + /** + * Create a new store for the given protocol and identifier. The implementation + * may create the store in any number of locations, including a database or + * Subversion. + * + * @param protocol the implementation protocol + * @param identifier the protocol-specific identifier + * @return Returns a reference to the store + * @throws StoreExistsException + */ + @Auditable(key = Auditable.Key.RETURN, parameters = {"protocol", "identifier"}) + public StoreRef createStore(String protocol, String identifier) throws StoreExistsException; + + /** + * @param storeRef a reference to the store to look for + * @return Returns true if the store exists, otherwise false + */ + @Auditable(parameters = {"storeRef"}) + public boolean exists(StoreRef storeRef); + + /** + * @param nodeRef a reference to the node to look for + * @return Returns true if the node exists, otherwise false + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) + public boolean exists(NodeRef nodeRef); + + /** + * Gets the ID of the last transaction that caused the node to change. This includes + * deletions, so it is possible that the node being referenced no longer exists. + * If the node never existed, then null is returned. + * + * @param nodeRef a reference to a current or previously existing node + * @return Returns the status of the node, or null if the node never existed + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) + public NodeRef.Status getNodeStatus(NodeRef nodeRef); + + /** + * @param storeRef a reference to an existing store + * @return Returns a reference to the root node of the store + * @throws InvalidStoreRefException if the store could not be found + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"storeRef"}) + public NodeRef getRootNode(StoreRef storeRef) throws InvalidStoreRefException; + + /** + * @see #createNode(NodeRef, QName, QName, QName, Map) + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"parentRef", "assocTypeQName", "assocQName", "nodeTypeQName"}) + public ChildAssociationRef createNode( + NodeRef parentRef, + QName assocTypeQName, + QName assocQName, + QName nodeTypeQName) + throws InvalidNodeRefException, InvalidTypeException; + + /** + * Creates a new, non-abstract, real node as a primary child of the given parent node. + * + * @param parentRef the parent node + * @param assocTypeQName the type of the association to create. This is used + * for verification against the data dictionary. + * @param assocQName the qualified name of the association + * @param nodeTypeQName a reference to the node type + * @param properties optional map of properties to keyed by their qualified names + * @return Returns a reference to the newly created child association + * @throws InvalidNodeRefException if the parent reference is invalid + * @throws InvalidTypeException if the node type reference is not recognised + * + * @see org.alfresco.service.cmr.dictionary.DictionaryService + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"parentRef", "assocTypeQName", "assocQName", "nodeTypeQName", "properties"}) + public ChildAssociationRef createNode( + NodeRef parentRef, + QName assocTypeQName, + QName assocQName, + QName nodeTypeQName, + Map properties) + throws InvalidNodeRefException, InvalidTypeException; + + /** + * Moves the primary location of the given node. + *

+ * This involves changing the node's primary parent and possibly the name of the + * association referencing it. + *

+ * If the new parent is in a different store from the original, then the entire + * node hierarchy is moved to the new store. Inter-store associations are not + * affected. + * + * @param nodeToMoveRef the node to move + * @param newParentRef the new parent of the moved node + * @param assocTypeQName the type of the association to create. This is used + * for verification against the data dictionary. + * @param assocQName the qualified name of the new child association + * @return Returns a reference to the newly created child association + * @throws InvalidNodeRefException if either the parent node or move node reference is invalid + * @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add + * + * @see #getPrimaryParent(NodeRef) + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeToMoveRef", "newParentRef", "assocTypeQName", "assocQName"}) + public ChildAssociationRef moveNode( + NodeRef nodeToMoveRef, + NodeRef newParentRef, + QName assocTypeQName, + QName assocQName) + throws InvalidNodeRefException; + + /** + * Set the ordering index of the child association. This affects the ordering of + * of the return values of methods that return a set of children or child + * associations. + * + * @param childAssocRef the child association that must be moved in the order + * @param index an arbitrary index that will affect the return order + * + * @see #getChildAssocs(NodeRef) + * @see #getChildAssocs(NodeRef, QNamePattern, QNamePattern) + * @see ChildAssociationRef#getNthSibling() + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"childAssocRef", "index"}) + public void setChildAssociationIndex( + ChildAssociationRef childAssocRef, + int index) + throws InvalidChildAssociationRefException; + + /** + * @param nodeRef + * @return Returns the type name + * @throws InvalidNodeRefException if the node could not be found + * + * @see org.alfresco.service.cmr.dictionary.DictionaryService + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) + public QName getType(NodeRef nodeRef) throws InvalidNodeRefException; + + /** + * Re-sets the type of the node. Can be called in order specialise a node to a sub-type. + * + * This should be used with caution since calling it changes the type of the node and thus + * implies a different set of aspects, properties and associations. It is the calling codes + * responsibility to ensure that the node is in a approriate state after changing the type. + * + * @param nodeRef the node reference + * @param typeQName the type QName + * + * @since 1.1 + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "typeQName"}) + public void setType(NodeRef nodeRef, QName typeQName) throws InvalidNodeRefException; + + /** + * Applies an aspect to the given node. After this method has been called, + * the node with have all the aspect-related properties present + * + * @param nodeRef + * @param aspectTypeQName the aspect to apply to the node + * @param aspectProperties a minimum of the mandatory properties required for + * the aspect + * @throws InvalidNodeRefException + * @throws InvalidAspectException if the class reference is not to a valid aspect + * + * @see org.alfresco.service.cmr.dictionary.DictionaryService#getAspect(QName) + * @see org.alfresco.service.cmr.dictionary.ClassDefinition#getProperties() + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "aspectTypeQName", "aspectProperties"}) + public void addAspect( + NodeRef nodeRef, + QName aspectTypeQName, + Map aspectProperties) + throws InvalidNodeRefException, InvalidAspectException; + + /** + * Remove an aspect and all related properties from a node + * + * @param nodeRef + * @param aspectTypeQName the type of aspect to remove + * @throws InvalidNodeRefException if the node could not be found + * @throws InvalidAspectException if the the aspect is unknown or if the + * aspect is mandatory for the class of the node + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "aspectTypeQName"}) + public void removeAspect(NodeRef nodeRef, QName aspectTypeQName) + throws InvalidNodeRefException, InvalidAspectException; + + /** + * Determines if a given aspect is present on a node. Aspects may only be + * removed if they are NOT mandatory. + * + * @param nodeRef + * @param aspectTypeQName + * @return Returns true if the aspect has been applied to the given node, + * otherwise false + * @throws InvalidNodeRefException if the node could not be found + * @throws InvalidAspectException if the aspect reference is invalid + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "aspectTypeQName"}) + public boolean hasAspect(NodeRef nodeRef, QName aspectTypeQName) + throws InvalidNodeRefException, InvalidAspectException; + + /** + * @param nodeRef + * @return Returns a set of all aspects applied to the node, including mandatory + * aspects + * @throws InvalidNodeRefException if the node could not be found + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) + public Set getAspects(NodeRef nodeRef) throws InvalidNodeRefException; + + /** + * Deletes the given node. + *

+ * All associations (both children and regular node associations) + * will be deleted, and where the given node is the primary parent, + * the children will also be cascade deleted. + * + * @param nodeRef reference to a node within a store + * @throws InvalidNodeRefException if the reference given is invalid + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) + public void deleteNode(NodeRef nodeRef) throws InvalidNodeRefException; + + /** + * Makes a parent-child association between the given nodes. Both nodes must belong to the same store. + *

+ * + * + * @param parentRef + * @param childRef + * @param assocTypeQName the qualified name of the association type as defined in the datadictionary + * @param qname the qualified name of the association + * @return Returns a reference to the newly created child association + * @throws InvalidNodeRefException if the parent or child nodes could not be found + * @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"parentRef", "childRef", "assocTypeQName", "qname"}) + public ChildAssociationRef addChild( + NodeRef parentRef, + NodeRef childRef, + QName assocTypeQName, + QName qname) throws InvalidNodeRefException; + + /** + * Severs all parent-child relationships between two nodes. + *

+ * The child node will be cascade deleted if one of the associations was the + * primary association, i.e. the one with which the child node was created. + * + * @param parentRef the parent end of the association + * @param childRef the child end of the association + * @return Returns a collection of deleted entities - both associations and node references. + * @throws InvalidNodeRefException if the parent or child nodes could not be found + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"parentRef", "childRef"}) + public void removeChild(NodeRef parentRef, NodeRef childRef) throws InvalidNodeRefException; + + /** + * @param nodeRef + * @return Returns all properties keyed by their qualified name + * @throws InvalidNodeRefException if the node could not be found + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) + public Map getProperties(NodeRef nodeRef) throws InvalidNodeRefException; + + /** + * @param nodeRef + * @param qname the qualified name of the property + * @return Returns the value of the property, or null if not yet set + * @throws InvalidNodeRefException if the node could not be found + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "qname"}) + public Serializable getProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException; + + /** + * Set the values of all properties to be an Serializable instances. + * The properties given must still fulfill the requirements of the class and + * aspects relevant to the node. + *

+ * NOTE: Null values are allowed. + * + * @param nodeRef + * @param properties all the properties of the node keyed by their qualified names + * @throws InvalidNodeRefException if the node could not be found + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "properties"}) + public void setProperties(NodeRef nodeRef, Map properties) throws InvalidNodeRefException; + + /** + * Sets the value of a property to be any Serializable instance. + * To remove a property value, use {@link #getProperties(NodeRef)}, remove the + * value and call {@link #setProperties(NodeRef, Map)}. + *

+ * NOTE: Null values are allowed. + * + * @param nodeRef + * @param qname the fully qualified name of the property + * @param propertyValue the value of the property - never null + * @throws InvalidNodeRefException if the node could not be found + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "qname", "value"}) + public void setProperty(NodeRef nodeRef, QName qname, Serializable value) throws InvalidNodeRefException; + + /** + * @param nodeRef the child node + * @return Returns a list of all parent-child associations that exist where the given + * node is the child + * @throws InvalidNodeRefException if the node could not be found + * + * @see #getParentAssocs(NodeRef, QNamePattern, QNamePattern) + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) + public List getParentAssocs(NodeRef nodeRef) throws InvalidNodeRefException; + + /** + * Gets all parent associations where the pattern of the association qualified + * name is a match + *

+ * The resultant list is ordered by (a) explicit index and (b) association creation time. + * + * @param nodeRef the child node + * @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 + * @return Returns a list of all parent-child associations that exist where the given + * node is the child + * @throws InvalidNodeRefException if the node could not be found + * + * @see ChildAssociationRef#getNthSibling() + * @see #setChildAssociationIndex(ChildAssociationRef, int) + * @see QName + * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "typeQNamePattern", "qnamePattern"}) + public List getParentAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern) + throws InvalidNodeRefException; + + /** + * Get all child associations of the given node. + *

+ * The resultant list is ordered by (a) explicit index and (b) association creation time. + * + * @param nodeRef the parent node - usually a container + * @return Returns a collection of ChildAssocRef instances. If the + * node is not a container then the result will be empty. + * @throws InvalidNodeRefException if the node could not be found + * + * @see #getChildAssocs(NodeRef, QNamePattern, QNamePattern) + * @see #setChildAssociationIndex(ChildAssociationRef, int) + * @see ChildAssociationRef#getNthSibling() + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) + public List getChildAssocs(NodeRef nodeRef) throws InvalidNodeRefException; + + /** + * Gets all child associations where the pattern of the association qualified + * name is a match. + * + * @param nodeRef the parent node - usually a container + * @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 + * @return Returns a list of ChildAssocRef instances. If the + * node is not a container 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 getChildAssocs( + NodeRef nodeRef, + QNamePattern typeQNamePattern, + QNamePattern qnamePattern) + throws InvalidNodeRefException; + + /** + * Get the node with the given name within the context of the parent node. The name + * is case-insensitive as Alfresco has to support case-insensitive clients as standard. + * + * @param nodeRef the parent node - usuall a container + * @param assocTypeQName the type of the association + * @param childName the name of the node as per the property cm:name + * @return Returns the child node or null if not found + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "assocTypeQName", "childName"}) + public NodeRef getChildByName( + NodeRef nodeRef, + QName assocTypeQName, + String childName); + + /** + * Fetches the primary parent-child relationship. + *

+ * For a root node, the parent node reference will be null. + * + * @param nodeRef + * @return Returns the primary parent-child association of the node + * @throws InvalidNodeRefException if the node could not be found + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) + public ChildAssociationRef getPrimaryParent(NodeRef nodeRef) throws InvalidNodeRefException; + + /** + * + * @param sourceRef a reference to a real node + * @param targetRef a reference to a node + * @param assocTypeQName the qualified name of the association type + * @return Returns a reference to the new association + * @throws InvalidNodeRefException if either of the nodes could not be found + * @throws AssociationExistsException + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"sourceRef", "targetRef", "assocTypeQName"}) + public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) + throws InvalidNodeRefException, AssociationExistsException; + + /** + * + * @param sourceRef the associaton source node + * @param targetRef the association target node + * @param assocTypeQName the qualified name of the association type + * @throws InvalidNodeRefException if either of the nodes could not be found + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"sourceRef", "targetRef", "assocTypeQName"}) + public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) + throws InvalidNodeRefException; + + /** + * Fetches all associations from the given source where the associations' + * qualified names match the pattern provided. + * + * @param sourceRef the association source + * @param qnamePattern the association qname pattern to match against + * @return Returns a list of NodeAssocRef instances for which the + * given node is a source + * @throws InvalidNodeRefException if the source node could not be found + * + * @see QName + * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"sourceRef", "qnamePattern"}) + public List getTargetAssocs(NodeRef sourceRef, QNamePattern qnamePattern) + throws InvalidNodeRefException; + + /** + * Fetches all associations to the given target where the associations' + * qualified names match the pattern provided. + * + * @param targetRef the association target + * @param qnamePattern the association qname pattern to match against + * @return Returns a list of NodeAssocRef instances for which the + * given node is a target + * @throws InvalidNodeRefException + * + * @see QName + * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"targetRef", "qnamePattern"}) + public List getSourceAssocs(NodeRef targetRef, QNamePattern qnamePattern) + throws InvalidNodeRefException; + + /** + * The root node has an entry in the path(s) returned. For this reason, there + * will always be at least one path element in the returned path(s). + * The first element will have a null parent reference and qname. + * + * @param nodeRef + * @return Returns the path to the node along the primary node path + * @throws InvalidNodeRefException if the node could not be found + * + * @see #getPaths(NodeRef, boolean) + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef"}) + public Path getPath(NodeRef nodeRef) throws InvalidNodeRefException; + + /** + * The root node has an entry in the path(s) returned. For this reason, there + * will always be at least one path element in the returned path(s). + * The first element will have a null parent reference and qname. + * + * @param nodeRef + * @param primaryOnly true if only the primary path must be retrieved. If true, the + * result will have exactly one entry. + * @return Returns a List of all possible paths to the given node + * @throws InvalidNodeRefException if the node could not be found + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"nodeRef", "primaryOnly"}) + public List getPaths(NodeRef nodeRef, boolean primaryOnly) throws InvalidNodeRefException; + + /** + * Get the node where archived items will have gone when deleted from the given store. + * + * @param storeRef the store that items were deleted from + * @return Returns the archive node parent + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"storeRef"}) + public NodeRef getStoreArchiveNode(StoreRef storeRef); + + /** + * Restore an individual node (along with its sub-tree nodes) to the target location. + * The archived node must have the {@link org.alfresco.model.ContentModel#ASPECT_ARCHIVED archived aspect} + * set against it. + * + * @param archivedNodeRef the archived node + * @param destinationParentNodeRef the parent to move the node into + * or null to use the original + * @param assocTypeQName the primary association type name to use in the new location + * or null to use the original + * @param assocQName the primary association name to use in the new location + * or null to use the original + * @return Returns the reference to the newly created node + */ + @Auditable(key = Auditable.Key.ARG_0 ,parameters = {"archivedNodeRef", "destinationParentNodeRef", "assocTypeQName", "assocQName"}) + public NodeRef restoreNode( + NodeRef archivedNodeRef, + NodeRef destinationParentNodeRef, + QName assocTypeQName, + QName assocQName); +} diff --git a/source/java/org/alfresco/service/cmr/workflow/WorkflowInstance.java b/source/java/org/alfresco/service/cmr/workflow/WorkflowInstance.java index 6a92981346..5f446f342c 100644 --- a/source/java/org/alfresco/service/cmr/workflow/WorkflowInstance.java +++ b/source/java/org/alfresco/service/cmr/workflow/WorkflowInstance.java @@ -33,17 +33,26 @@ public class WorkflowInstance /** Workflow Instance unique id */ public String id; + /** Workflow Instance description */ + public String description; + /** Is this Workflow instance still "in-flight" or has it completed? */ public boolean active; /** Initiator (cm:person) - null if System initiated */ public NodeRef initiator; - + /** Workflow Start Date */ public Date startDate; /** Workflow End Date */ public Date endDate; + + /** Workflow Package */ + public NodeRef workflowPackage; + + /** Workflow Context */ + public NodeRef context; /** Workflow Definition */ public WorkflowDefinition definition; diff --git a/source/java/org/alfresco/service/cmr/workflow/WorkflowService.java b/source/java/org/alfresco/service/cmr/workflow/WorkflowService.java index 80938eefb3..3a5dd4c3b2 100644 --- a/source/java/org/alfresco/service/cmr/workflow/WorkflowService.java +++ b/source/java/org/alfresco/service/cmr/workflow/WorkflowService.java @@ -100,7 +100,7 @@ public interface WorkflowService * Gets a Workflow Definition by unique Id * * @param workflowDefinitionId the workflow definition id - * @return the deployed workflow definition + * @return the deployed workflow definition (or null if not found) */ @Auditable(parameters = {"workflowDefinitionId"}) public WorkflowDefinition getDefinitionById(String workflowDefinitionId); @@ -109,7 +109,7 @@ public interface WorkflowService * Gets a Workflow Definition by unique name * * @param workflowName workflow name e.g. jbpm://review - * @return the deployed workflow definition + * @return the deployed workflow definition (or null if not found) */ @Auditable(parameters = {"workflowName"}) public WorkflowDefinition getDefinitionByName(String workflowName); @@ -148,6 +148,15 @@ public interface WorkflowService */ @Auditable(parameters = {"workflowDefinitionId"}) public List getActiveWorkflows(String workflowDefinitionId); + + /** + * Gets a specific workflow instances + * + * @param workflowId the id of the workflow to retrieve + * @return the workflow instance (or null if not found) + */ + @Auditable(parameters = {"workflowId"}) + public WorkflowInstance getWorkflowById(String workflowId); /** * Gets all Paths for the specified Workflow instance @@ -195,7 +204,7 @@ public interface WorkflowService * Gets a Task by unique Id * * @param taskId the task id - * @return the task + * @return the task (or null, if not found) */ @Auditable(parameters = {"taskId"}) public WorkflowTask getTaskById(String taskId); @@ -241,6 +250,11 @@ public interface WorkflowService @Auditable(parameters = {"taskId", "transitionId"}) public WorkflowTask endTask(String taskId, String transitionId); + + // + // Package Management + // + /** * Create a Workflow Package (a container of content to route through the Workflow). * @@ -251,5 +265,15 @@ public interface WorkflowService */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"container"}) public NodeRef createPackage(NodeRef container); + + /** + * Gets the Workflows that act upon the specified Repository content. + * + * @param packageItem the repository content item to get workflows for + * @param active true => active workflows only, false => completed workflows only + * @return list of workflows which act upon the specified content + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = {"packageItem", "active"}) + public List getWorkflowsForContent(NodeRef packageItem, boolean active); } diff --git a/source/test-resources/jbpmresources/ehcache.xml b/source/test-resources/jbpmresources/ehcache.xml new file mode 100644 index 0000000000..663cdef302 --- /dev/null +++ b/source/test-resources/jbpmresources/ehcache.xml @@ -0,0 +1,48 @@ + + + + + + + + \ No newline at end of file diff --git a/source/test-resources/jbpmresources/hibernate.cfg.xml b/source/test-resources/jbpmresources/hibernate.cfg.xml new file mode 100644 index 0000000000..c92f1d3786 --- /dev/null +++ b/source/test-resources/jbpmresources/hibernate.cfg.xml @@ -0,0 +1,166 @@ + + + + + + + + + org.hibernate.dialect.HSQLDialect + org.hsqldb.jdbcDriver + jdbc:hsqldb:mem:.;sql.enforce_strict_size=true + sa + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +