diff --git a/config/alfresco/application-context.xml b/config/alfresco/application-context.xml index 422b2108a3..c16c0ee3e8 100644 --- a/config/alfresco/application-context.xml +++ b/config/alfresco/application-context.xml @@ -1,36 +1,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/alfresco/auditConfig.xml b/config/alfresco/auditConfig.xml index 1478d733f1..f639baff74 100644 --- a/config/alfresco/auditConfig.xml +++ b/config/alfresco/auditConfig.xml @@ -1,202 +1,201 @@ - - - - - - - - - - - - - - - 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/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml index 1b1eb69b2b..5354175164 100644 --- a/config/alfresco/bootstrap-context.xml +++ b/config/alfresco/bootstrap-context.xml @@ -35,7 +35,7 @@ - classpath:alfresco/dbscripts/create/1.4/${db.script.dialect}/sample.sql + classpath:alfresco/dbscripts/create/1.4/${db.script.dialect}/post-create-indexes.sql @@ -149,10 +149,6 @@ /${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.scripts.childname} alfresco/bootstrap/example_javascripts.acp - - /${spaces.company_home.childname}/${spaces.dictionary.childname}/${spaces.templates.childname} - alfresco/bootstrap/file_plan.xml - @@ -192,6 +188,10 @@ + + + + diff --git a/config/alfresco/bootstrap/categories.xml b/config/alfresco/bootstrap/categories.xml index 87012bd9cc..5e33800a75 100644 --- a/config/alfresco/bootstrap/categories.xml +++ b/config/alfresco/bootstrap/categories.xml @@ -1098,102 +1098,10 @@ + - + -Records Categoriesrm:recordCategory-root - - Review Periodrm:reviewPeriod-root - - Nonerm:reviewPeriod-0 - TBDrm:reviewPeriod-1 - Annuallyrm:reviewPeriod-2 - Calendar Year Endrm:reviewPeriod-3 - Fiscal Year Endrm:reviewPeriod-4 - Semi-Annuallyrm:reviewPeriod-5 - Quarterlyrm:reviewPeriod-6 - Monthlyrm:reviewPeriod-7 - Weeklyrm:reviewPeriod-8 - Dailyrm:reviewPeriod-9 - - - - Media Typesrm:mediaTypes-root - - TBDrm:mediaTypes-0 - Electronicrm:mediaTypes-1 - Paperrm:mediaTypes-2 - Microformrm:mediaTypes-3 - Portablerm:mediaTypes-4 - - - - Markingsrm:markings-root - - NONErm:markings-0 - - Classificationsrm:markings-1 - - UNCLASSIFIEDrm:markings-1-1 - RESTRICTEDrm:markings-1-2 - CONFIDENTIALrm:markings-1-3 - SECRETrm:markings-1-4 - TOP SECRETrm:markings-1-5 - - - - Handlingrm:markings-2 - - COMSECrm:markings-2-1 - RDrm:markings-2-2 - FRDrm:markings-2-3 - SPECAT-A SIOP-ESIrm:markings-2-4 - SPECAT-Brm:markings-2-5 - US-UK EYES ONLYrm:markings-2-6 - ATOMALrm:markings-2-7 - EXCLUSIVErm:markings-2-8 - CRYPTOrm:markings-2-9 - TRCrm:markings-2-10 - FOR OFFICIAL USE ONLYrm:markings-2-11 - SBUrm:markings-2-12 - DEA SENSITIVErm:markings-2-13 - DOD UCNIrm:markings-2-14 - EXDISrm:markings-2-15 - LIMDISrm:markings-2-16 - NODISrm:markings-2-17 - SOSUSrm:markings-2-18 - EYES ONLYrm:markings-2-19 - - - - Disseminationrm:markings-3 - - ORCONrm:markings-3-1 - PROPINrm:markings-3-2 - NOFORNrm:markings-3-3 - NOCONTRACTrm:markings-3-34 - FOUOrm:markings-3-5 - RELTOrm:markings-3-6 - EYES ONLYrm:markings-3-7 - - - - Reasonrm:markings-4 - - CLASSrm:markings-4-1 - RSNrm:markings-4-2 - DERVrm:markings-4-3 - DNGrm:markings-4-4 - DECLrm:markings-4-5 - - - - - - - - - diff --git a/config/alfresco/bootstrap/example_javascripts.acp b/config/alfresco/bootstrap/example_javascripts.acp index 48bf6636e4..4aea5d4048 100644 Binary files a/config/alfresco/bootstrap/example_javascripts.acp and b/config/alfresco/bootstrap/example_javascripts.acp differ diff --git a/config/alfresco/bootstrap/file_plan.xml b/config/alfresco/bootstrap/file_plan.xml deleted file mode 100644 index 62003b9bb5..0000000000 --- a/config/alfresco/bootstrap/file_plan.xml +++ /dev/null @@ -1,828 +0,0 @@ - - - - admin - 2006-09-02T09:54:43.796+01:00 - 1.4.0 (Dev @build-number@) - /app:company_home/app:dictionary/app:space_templates/cm:File_x0020_Plan - - - - - - - - - - - - - false - N/A - ISF - /app:company_home/app:dictionary/app:content_templates/cm:records_report.ftl - space-icon-cd - 15cc634c-3a5c-11db-ae95-09a9ea11d246 - false - GRS 1 item 1 - /cm:generalclassifiable/cm:Records_x0020_Categories/cm:Review_x0020_Period/cm:Quarterly - /cm:generalclassifiable/cm:Records_x0020_Categories/cm:Media_x0020_Types/cm:Electronic - 1 - false - 2006-09-02T09:21:51.750+01:00 - false - NARA - 1.0 - admin - false - false - false - Obsolete or Superseded - File Plan - SpacesStore - /cm:generalclassifiable/cm:Records_x0020_Categories/cm:Review_x0020_Period/cm:Quarterly - File Plan Template for Records Management - 458 - File Plan Template - false - 5.0 - false - /cm:generalclassifiable/cm:Records_x0020_Categories/cm:Markings/cm:NONE - admin - - false - 2006-09-02T09:53:17.750+01:00 - Destroy/delete when superseded by a like survey or study, or when no longer needed, whichever is later. - workspace - 0000-00 - - Defense Information Systems Agency - false - 2.0 - - - - - - - - - - admin - 2006-09-02T09:41:28.718+01:00 - 7836ac9c-3a5d-11db-ae95-09a9ea11d246 - admin - 459 - workspace - 7836ac9c-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:31:46.093+01:00 - - - - - - - - - - - Add Email Aspect - 783b678e-3a5d-11db-ae95-09a9ea11d246 - 460 - Email Handling - 2006-09-02T09:31:46.109+01:00 - admin - false - 2006-09-02T09:31:46.250+01:00 - true - admin - workspace - false - - - inbound - - - 783b678e-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - false - - - - 78343b97-3a5d-11db-ae95-09a9ea11d246 - 461 - 2006-09-02T09:31:46.140+01:00 - admin - 2006-09-02T09:31:46.250+01:00 - - - - admin - composite-action - workspace - 78343b97-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - admin - 2006-09-02T09:31:46.250+01:00 - 78343b98-3a5d-11db-ae95-09a9ea11d246 - admin - 462 - compare-mime-type - workspace - false - 78343b98-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:31:46.171+01:00 - - - - - - - - - - - message/rfc822 - - admin - value - 2006-09-02T09:31:46.250+01:00 - 78474e6f-3a5d-11db-ae95-09a9ea11d246 - admin - 463 - workspace - 78474e6f-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:31:46.187+01:00 - - - - - - - - - - - - - - - false - - - - 78343b99-3a5d-11db-ae95-09a9ea11d246 - 464 - 2006-09-02T09:31:46.203+01:00 - admin - 2006-09-02T09:31:46.250+01:00 - - - - admin - add-features - workspace - 78343b99-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - - {http://www.alfresco.org/model/content/1.0}emailed - - admin - aspect-name - 2006-09-02T09:31:46.250+01:00 - 784c0960-3a5d-11db-ae95-09a9ea11d246 - admin - 465 - workspace - 784c0960-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:31:46.234+01:00 - - - - - - - - - - - - - - - - - - - - Add record aspect and set up record data - d091637d-3a5d-11db-ae95-09a9ea11d246 - 466 - Record Set-up - 2006-09-02T09:34:14.312+01:00 - admin - false - 2006-09-02T09:34:14.546+01:00 - true - admin - workspace - false - - - inbound - - - d091637d-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - false - - - - d08ca886-3a5d-11db-ae95-09a9ea11d246 - 467 - 2006-09-02T09:34:14.343+01:00 - admin - 2006-09-02T09:34:14.546+01:00 - - - - admin - composite-action - workspace - d08ca886-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - admin - 2006-09-02T09:34:14.546+01:00 - d08ca887-3a5d-11db-ae95-09a9ea11d246 - admin - 468 - is-subtype - workspace - false - d08ca887-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:34:14.375+01:00 - - - - - - - - - - - {http://www.alfresco.org/model/content/1.0}content - - admin - type - 2006-09-02T09:34:14.546+01:00 - d09d4a5f-3a5d-11db-ae95-09a9ea11d246 - admin - 469 - workspace - d09d4a5f-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:34:14.390+01:00 - - - - - - - - - - - - - - - false - - - - d08ca888-3a5d-11db-ae95-09a9ea11d246 - 470 - 2006-09-02T09:34:14.421+01:00 - admin - 2006-09-02T09:34:14.546+01:00 - - - - admin - add-features - workspace - d08ca888-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - - {http://www.alfresco.org/model/record/1.0}record - - admin - aspect-name - 2006-09-02T09:34:14.546+01:00 - d0a47550-3a5d-11db-ae95-09a9ea11d246 - admin - 471 - workspace - d0a47550-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:34:14.453+01:00 - - - - - - - - - - - - - false - - - - d08ca889-3a5d-11db-ae95-09a9ea11d246 - 472 - 2006-09-02T09:34:14.484+01:00 - admin - 2006-09-02T09:34:14.546+01:00 - - - - admin - extract-metadata - workspace - d08ca889-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - false - - - - d08ca88a-3a5d-11db-ae95-09a9ea11d246 - 473 - 2006-09-02T09:34:14.515+01:00 - admin - 2006-09-02T09:34:14.546+01:00 - - - - admin - script - workspace - d08ca88a-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - - /app:company_home/app:dictionary/app:scripts/cm:record_setup.js - - admin - script-ref - 2006-09-02T09:34:14.546+01:00 - d0b2cd31-3a5d-11db-ae95-09a9ea11d246 - admin - 474 - workspace - d0b2cd31-3a5d-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:34:14.531+01:00 - - - - - - - - - - - - - - - - - - - - Set up record folder - 96342c65-3a5e-11db-ae95-09a9ea11d246 - 475 - Records Folder - 2006-09-02T09:39:45.906+01:00 - admin - false - 2006-09-02T09:39:46.093+01:00 - true - admin - workspace - false - - - inbound - - - 96342c65-3a5e-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - false - - - - 9631e26f-3a5e-11db-ae95-09a9ea11d246 - 476 - 2006-09-02T09:39:45.921+01:00 - admin - 2006-09-02T09:39:46.093+01:00 - - - - admin - composite-action - workspace - 9631e26f-3a5e-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - admin - 2006-09-02T09:39:46.093+01:00 - 9631e270-3a5e-11db-ae95-09a9ea11d246 - admin - 477 - is-subtype - workspace - false - 9631e270-3a5e-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:39:45.953+01:00 - - - - - - - - - - - {http://www.alfresco.org/model/content/1.0}folder - - admin - type - 2006-09-02T09:39:46.093+01:00 - 96428447-3a5e-11db-ae95-09a9ea11d246 - admin - 478 - workspace - 96428447-3a5e-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:39:45.984+01:00 - - - - - - - - - - - - - - - false - - - - 9631e271-3a5e-11db-ae95-09a9ea11d246 - 479 - 2006-09-02T09:39:46.000+01:00 - admin - 2006-09-02T09:39:46.093+01:00 - - - - admin - add-features - workspace - 9631e271-3a5e-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - - {http://www.alfresco.org/model/record/1.0}record - - admin - aspect-name - 2006-09-02T09:39:46.093+01:00 - 9649b038-3a5e-11db-ae95-09a9ea11d246 - admin - 480 - workspace - 9649b038-3a5e-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:39:46.031+01:00 - - - - - - - - - - - - - false - - - - 9631e272-3a5e-11db-ae95-09a9ea11d246 - 481 - 2006-09-02T09:39:46.046+01:00 - admin - 2006-09-02T09:39:46.093+01:00 - - - - admin - script - workspace - 9631e272-3a5e-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - - /app:company_home/app:dictionary/app:scripts/cm:record_folder.js - - admin - script-ref - 2006-09-02T09:39:46.093+01:00 - 964e6b29-3a5e-11db-ae95-09a9ea11d246 - admin - 482 - workspace - 964e6b29-3a5e-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:39:46.078+01:00 - - - - - - - - - - - - - - - - - - - - Process record lifecycle based upon the file plan - d36b6897-3a5e-11db-ae95-09a9ea11d246 - 483 - Record Lifecycle - 2006-09-02T09:41:28.609+01:00 - admin - false - 2006-09-02T09:41:28.718+01:00 - true - admin - workspace - false - - - update - - - d36b6897-3a5e-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - false - - - - d36b6892-3a5e-11db-ae95-09a9ea11d246 - 484 - 2006-09-02T09:41:28.640+01:00 - admin - 2006-09-02T09:41:28.734+01:00 - - - - admin - composite-action - workspace - d36b6892-3a5e-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - admin - 2006-09-02T09:41:28.734+01:00 - d36b6893-3a5e-11db-ae95-09a9ea11d246 - admin - 485 - no-condition - workspace - false - d36b6893-3a5e-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:41:28.656+01:00 - - - - - - - - - - - - false - - - - d36b6894-3a5e-11db-ae95-09a9ea11d246 - 486 - 2006-09-02T09:41:28.687+01:00 - admin - 2006-09-02T09:41:28.734+01:00 - - - - admin - script - workspace - d36b6894-3a5e-11db-ae95-09a9ea11d246 - SpacesStore - - - - - - - - - - - /app:company_home/app:dictionary/app:scripts/cm:record_lifecycle.js - - admin - script-ref - 2006-09-02T09:41:28.734+01:00 - d37c3179-3a5e-11db-ae95-09a9ea11d246 - admin - 487 - workspace - d37c3179-3a5e-11db-ae95-09a9ea11d246 - SpacesStore - 2006-09-02T09:41:28.703+01:00 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml index 97c936a8b5..a230559c59 100644 --- a/config/alfresco/content-services-context.xml +++ b/config/alfresco/content-services-context.xml @@ -1,247 +1,247 @@ - - - - - - - - ${dir.contentstore} - - - - - - - ${dir.contentstore.deleted} - - - - - - - - - - - - - - - - - - - - - - - - 14 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - classpath:alfresco/mimetype/mimetype-map.xml - classpath:alfresco/mimetype/mimetype-map-openoffice.xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - application/pdf - text/plain - - - - - - - - - - - - application/msword - text/plain - - - - - - - - - - - - - classpath:alfresco/mimetype/openoffice-document-formats.xml - - - - - - - - - - - - - application/pdf - - - - - - - - - - - - - imconvert "${source}" ${options} "${target}" - - - convert ${source} ${options} ${target} - - - - - - - - - - - - - + + + + + + + + ${dir.contentstore} + + + + + + + ${dir.contentstore.deleted} + + + + + + + + + + + + + + + + + + + + + + + + 14 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + classpath:alfresco/mimetype/mimetype-map.xml + classpath:alfresco/mimetype/mimetype-map-openoffice.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + application/pdf + text/plain + + + + + + + + + + + + application/msword + text/plain + + + + + + + + + + + + + classpath:alfresco/mimetype/openoffice-document-formats.xml + + + + + + + + + + + + + application/pdf + + + + + + + + + + + + + imconvert "${source}" ${options} "${target}" + + + convert ${source} ${options} ${target} + + + + + + + + + + + + + diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index c8740bc99e..47e209f688 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -1,672 +1,672 @@ - - - - - - - - - - - - - - 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 - - - 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} - - - - - + + + + + + + + + + + + + + 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} + + + false + + + + + + + + + + ${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 + alfresco.messages.copy-service + + + + + + + + + + + + ${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 + + + 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/dbscripts/create/1.4/org.hibernate.dialect.Dialect/post-create-indexes.sql b/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.Dialect/post-create-indexes.sql new file mode 100644 index 0000000000..d2bc282c82 --- /dev/null +++ b/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.Dialect/post-create-indexes.sql @@ -0,0 +1,3 @@ +-- +-- Add post-creation indexes. (Generic Schema 1.4) +-- diff --git a/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.Oracle9Dialect/post-create-indexes.sql b/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.Oracle9Dialect/post-create-indexes.sql new file mode 100644 index 0000000000..373194f988 --- /dev/null +++ b/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.Oracle9Dialect/post-create-indexes.sql @@ -0,0 +1,30 @@ +-- +-- Add post-creation indexes. (Oracle Schema 1.4) +-- +CREATE INDEX FKFFF41F9960601995 ON alf_access_control_entry (permission_id); +CREATE INDEX FKFFF41F99B25A50BF ON alf_access_control_entry (authority_id); +CREATE INDEX FKFFF41F99B9553F6C ON alf_access_control_entry (acl_id); +CREATE INDEX FK8A749A657B7FDE43 ON alf_auth_ext_keys (id); +CREATE INDEX FKFFC5468E74173FF4 ON alf_child_assoc (child_node_id); +CREATE INDEX FKFFC5468E8E50E582 ON alf_child_assoc (parent_node_id); +CREATE INDEX FK60EFB626B9553F6C ON alf_node (acl_id); +CREATE INDEX FK60EFB626D24ADD25 ON alf_node (protocol, identifier); +CREATE INDEX FK7D4CF8EC7F2C8017 ON alf_node_properties (node_id); +CREATE INDEX FKD654E027F2C8017 ON alf_node_aspects (node_id); +CREATE INDEX FKE1A550BCB69C43F3 ON alf_node_assoc (source_node_id); +CREATE INDEX FKE1A550BCA8FC7769 ON alf_node_assoc (target_node_id); +CREATE INDEX FK71C2002B7F2C8017 ON alf_node_status (node_id); +CREATE INDEX FKBD4FF53D22DBA5BA ON alf_store (root_node_id); + +-- +-- Transaction tables +-- +CREATE INDEX FK71C2002B9E57C13D ON alf_node_status (transaction_id); +CREATE INDEX FKB8761A3A9AE340B7 ON alf_transaction (server_id); + +-- +-- New audit tables +-- +CREATE INDEX FKEAD1817484342E39 ON alf_audit_fact (audit_date_id); +CREATE INDEX FKEAD18174A0F9B8D9 ON alf_audit_fact (audit_source_id); +CREATE INDEX FKEAD18174F524CFD7 ON alf_audit_fact (audit_conf_id); diff --git a/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.SQLServerDialect/post-create-indexes.sql b/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.SQLServerDialect/post-create-indexes.sql new file mode 100644 index 0000000000..1a385c5260 --- /dev/null +++ b/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.SQLServerDialect/post-create-indexes.sql @@ -0,0 +1,30 @@ +-- +-- Add post-creation indexes. (SQL Server Schema 1.4) +-- +CREATE INDEX FKFFF41F9960601995 ON alf_access_control_entry (permission_id); +CREATE INDEX FKFFF41F99B25A50BF ON alf_access_control_entry (authority_id); +CREATE INDEX FKFFF41F99B9553F6C ON alf_access_control_entry (acl_id); +CREATE INDEX FK8A749A657B7FDE43 ON alf_auth_ext_keys (id); +CREATE INDEX FKFFC5468E74173FF4 ON alf_child_assoc (child_node_id); +CREATE INDEX FKFFC5468E8E50E582 ON alf_child_assoc (parent_node_id); +CREATE INDEX FK60EFB626B9553F6C ON alf_node (acl_id); +CREATE INDEX FK60EFB626D24ADD25 ON alf_node (protocol, identifier); +CREATE INDEX FK7D4CF8EC7F2C8017 ON alf_node_properties (node_id); +CREATE INDEX FKD654E027F2C8017 ON alf_node_aspects (node_id); +CREATE INDEX FKE1A550BCB69C43F3 ON alf_node_assoc (source_node_id); +CREATE INDEX FKE1A550BCA8FC7769 ON alf_node_assoc (target_node_id); +CREATE INDEX FK71C2002B7F2C8017 ON alf_node_status (node_id); +CREATE INDEX FKBD4FF53D22DBA5BA ON alf_store (root_node_id); + +-- +-- Transaction tables +-- +CREATE INDEX FK71C2002B9E57C13D ON alf_node_status (transaction_id); +CREATE INDEX FKB8761A3A9AE340B7 ON alf_transaction (server_id); + +-- +-- New audit tables +-- +CREATE INDEX FKEAD1817484342E39 ON alf_audit_fact (audit_date_id); +CREATE INDEX FKEAD18174A0F9B8D9 ON alf_audit_fact (audit_source_id); +CREATE INDEX FKEAD18174F524CFD7 ON alf_audit_fact (audit_conf_id); diff --git a/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-1.4-1.sql b/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-1.4-1.sql index 9b14fec91c..350604fc57 100644 --- a/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-1.4-1.sql +++ b/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-1.4-1.sql @@ -1,5 +1,5 @@ -- ------------------------------------------------------ --- Alfresco Schema conversion V1.3 to V1.4 Part 1 +-- Alfresco Schema conversion V1.3 to V1.4 Part 1 (MySQL) -- -- Adds the columns required to enforce the duplicate name detection -- @@ -25,6 +25,11 @@ DROP TABLE IF EXISTS T_permission; DROP TABLE IF EXISTS T_store; DROP TABLE IF EXISTS T_version_count; +-- +-- Upgrades to 1.3 of MyIsam tables could have missed the applied_patch table InnoDB +-- +ALTER TABLE applied_patch ENGINE = InnoDB; + -- -- Unique name constraint -- @@ -47,20 +52,70 @@ ALTER TABLE node_assoc -- -- Rename tables to give 'alf_' prefix -- -ALTER TABLE access_control_entry RENAME TO alf_access_control_entry; -ALTER TABLE access_control_list RENAME TO alf_access_control_list; -ALTER TABLE applied_patch RENAME TO alf_applied_patch; -ALTER TABLE auth_ext_keys RENAME TO alf_auth_ext_keys; -ALTER TABLE authority RENAME TO alf_authority; -ALTER TABLE child_assoc RENAME TO alf_child_assoc; -ALTER TABLE node RENAME TO alf_node; -ALTER TABLE node_aspects RENAME TO alf_node_aspects; -ALTER TABLE node_assoc RENAME TO alf_node_assoc; -ALTER TABLE node_properties RENAME TO alf_node_properties; -ALTER TABLE node_status RENAME TO alf_node_status; -ALTER TABLE permission RENAME TO alf_permission; -ALTER TABLE store RENAME TO alf_store; -ALTER TABLE version_count RENAME TO alf_version_count; +ALTER TABLE access_control_entry RENAME TO alf_access_control_entry; +ALTER TABLE access_control_list RENAME TO alf_access_control_list; +ALTER TABLE applied_patch RENAME TO alf_applied_patch; +ALTER TABLE auth_ext_keys RENAME TO alf_auth_ext_keys; +ALTER TABLE authority RENAME TO alf_authority; +ALTER TABLE child_assoc RENAME TO alf_child_assoc; +ALTER TABLE node RENAME TO alf_node; +ALTER TABLE node_aspects RENAME TO alf_node_aspects; +ALTER TABLE node_assoc RENAME TO alf_node_assoc; +ALTER TABLE node_properties RENAME TO alf_node_properties; +ALTER TABLE node_status RENAME TO alf_node_status; +ALTER TABLE permission RENAME TO alf_permission; +ALTER TABLE store RENAME TO alf_store; +ALTER TABLE version_count RENAME TO alf_version_count; + +-- +-- The table renames will cause Hibernate to rehash the FK constraint names. +-- For MySQL, Hibernate will generate scripts to add the appropriate constraints +-- and indexes. +-- +ALTER TABLE alf_access_control_entry + DROP FOREIGN KEY FKF064DF7560601995, + DROP INDEX FKF064DF7560601995, + DROP FOREIGN KEY FKF064DF75B25A50BF, + DROP INDEX FKF064DF75B25A50BF, + DROP FOREIGN KEY FKF064DF75B9553F6C, + DROP INDEX FKF064DF75B9553F6C; +ALTER TABLE alf_auth_ext_keys + DROP FOREIGN KEY FK31D3BA097B7FDE43, + DROP INDEX FK31D3BA097B7FDE43; +ALTER TABLE alf_child_assoc + DROP FOREIGN KEY FKC6EFFF3274173FF4, + DROP INDEX FKC6EFFF3274173FF4, + DROP FOREIGN KEY FKC6EFFF328E50E582, + DROP INDEX FKC6EFFF328E50E582;(optional) +ALTER TABLE alf_child_assoc + DROP FOREIGN KEY FKFFC5468E74173FF4, + DROP INDEX FKFFC5468E74173FF4, + DROP FOREIGN KEY FKFFC5468E8E50E582, + DROP INDEX FKFFC5468E8E50E582;(optional) +ALTER TABLE alf_node + DROP FOREIGN KEY FK33AE02B9553F6C, + DROP INDEX FK33AE02B9553F6C; +ALTER TABLE alf_node + DROP FOREIGN KEY FK33AE02D24ADD25, + DROP INDEX FK33AE02D24ADD25; +ALTER TABLE alf_node_properties + DROP FOREIGN KEY FKC962BF907F2C8017, + DROP INDEX FKC962BF907F2C8017; +ALTER TABLE alf_node_aspects + DROP FOREIGN KEY FK2B91A9DE7F2C8017, + DROP INDEX FK2B91A9DE7F2C8017; +ALTER TABLE alf_node_assoc + DROP FOREIGN KEY FK5BAEF398B69C43F3, + DROP INDEX FK5BAEF398B69C43F3; +ALTER TABLE alf_node_assoc + DROP FOREIGN KEY FK5BAEF398A8FC7769, + DROP INDEX FK5BAEF398A8FC7769; +ALTER TABLE alf_node_status + DROP FOREIGN KEY FK38ECB8CF7F2C8017, + DROP INDEX FK38ECB8CF7F2C8017; +ALTER TABLE alf_store + DROP FOREIGN KEY FK68AF8E122DBA5BA, + DROP INDEX FK68AF8E122DBA5BA; -- -- Record script finish diff --git a/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-1.4-2.sql b/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-1.4-2.sql index 9a3c77833f..60ad676333 100644 --- a/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-1.4-2.sql +++ b/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-1.4-2.sql @@ -1,5 +1,5 @@ -- ------------------------------------------------------ --- Alfresco Schema conversion V1.3 to V1.4 Part 2 +-- Alfresco Schema conversion V1.3 to V1.4 Part 2 (MySQL) -- -- Adds the alf_transaction and alf_server tables to keep track of the sources -- of transactions. @@ -25,7 +25,6 @@ CREATE TABLE alf_transaction ( change_txn_id varchar(56) NOT NULL, PRIMARY KEY (id), KEY FKB8761A3A9AE340B7 (server_id), - KEY IDX_CHANGE_TXN (change_txn_id), CONSTRAINT FKB8761A3A9AE340B7 FOREIGN KEY (server_id) REFERENCES alf_server (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into alf_transaction @@ -44,7 +43,11 @@ UPDATE alf_node_status ns SET ns.transaction_id = ); ALTER TABLE alf_node_status DROP COLUMN change_txn_id, - ADD CONSTRAINT FK71C2002B9E57C13D FOREIGN KEY (transaction_id) REFERENCES alf_transaction (id); + ADD CONSTRAINT FK71C2002B9E57C13D FOREIGN KEY (transaction_id) REFERENCES alf_transaction (id), + ADD INDEX FK71C2002B9E57C13D (transaction_id); +ALTER TABLE alf_node_status + DROP COLUMN deleted + ;(optional) -- -- Record script finish diff --git a/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.Oracle9Dialect/AlfrescoSchemaUpdate-1.4-1.sql b/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.Oracle9Dialect/AlfrescoSchemaUpdate-1.4-1.sql new file mode 100644 index 0000000000..f2fdd876b9 --- /dev/null +++ b/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.Oracle9Dialect/AlfrescoSchemaUpdate-1.4-1.sql @@ -0,0 +1,92 @@ +-- ------------------------------------------------------ +-- Alfresco Schema conversion V1.3 to V1.4 Part 1 (Oracle) +-- +-- Adds the columns required to enforce the duplicate name detection +-- +-- Author: Derek Hulley +-- ------------------------------------------------------ + +-- +-- Unique name constraint +-- + +-- Apply new schema changes to child assoc table +ALTER TABLE child_assoc ADD + ( + child_node_name VARCHAR2(50 CHAR) DEFAULT 'V1.4 upgrade' NOT NULL, + child_node_name_crc NUMBER(19,0) DEFAULT -1 NOT NULL + ); + +UPDATE child_assoc + SET child_node_name_crc = id * -1; + +CREATE UNIQUE INDEX IDX_CHILD_NAMECRC ON child_assoc (parent_node_id, type_qname, child_node_name, child_node_name_crc); + +-- Apply unique index for node associations +CREATE UNIQUE INDEX IDX_ASSOC ON node_assoc (source_node_id, type_qname, target_node_id); + +-- +-- Rename tables to give 'alf_' prefix +-- +ALTER TABLE access_control_entry RENAME TO alf_access_control_entry; +ALTER TABLE access_control_list RENAME TO alf_access_control_list; +ALTER TABLE applied_patch RENAME TO alf_applied_patch; +ALTER TABLE auth_ext_keys RENAME TO alf_auth_ext_keys; +ALTER TABLE authority RENAME TO alf_authority; +ALTER TABLE child_assoc RENAME TO alf_child_assoc; +ALTER TABLE node RENAME TO alf_node; +ALTER TABLE node_aspects RENAME TO alf_node_aspects; +ALTER TABLE node_assoc RENAME TO alf_node_assoc; +ALTER TABLE node_properties RENAME TO alf_node_properties; +ALTER TABLE node_status RENAME TO alf_node_status; +ALTER TABLE permission RENAME TO alf_permission; +ALTER TABLE store RENAME TO alf_store; +ALTER TABLE version_count RENAME TO alf_version_count; + +-- +-- The table renames will cause Hibernate to rehash the FK constraint names +-- +ALTER TABLE alf_access_control_entry RENAME CONSTRAINT FKF064DF7560601995 TO FKFFF41F9960601995; +ALTER TABLE alf_access_control_entry RENAME CONSTRAINT FKF064DF75B25A50BF TO FKFFF41F99B25A50BF; +ALTER TABLE alf_access_control_entry RENAME CONSTRAINT FKF064DF75B9553F6C TO FKFFF41F99B9553F6C; +ALTER TABLE alf_auth_ext_keys RENAME CONSTRAINT FK31D3BA097B7FDE43 TO FK8A749A657B7FDE43; +ALTER TABLE alf_child_assoc RENAME CONSTRAINT FKC6EFFF3274173FF4 TO FKFFC5468E74173FF4; +ALTER TABLE alf_child_assoc RENAME CONSTRAINT FKC6EFFF328E50E582 TO FKFFC5468E8E50E582; +ALTER TABLE alf_node RENAME CONSTRAINT FK33AE02B9553F6C TO FK60EFB626B9553F6C; +ALTER TABLE alf_node RENAME CONSTRAINT FK33AE02D24ADD25 TO FK60EFB626D24ADD25; +ALTER TABLE alf_node_properties RENAME CONSTRAINT FKC962BF907F2C8017 TO FK7D4CF8EC7F2C8017; +ALTER TABLE alf_node_aspects RENAME CONSTRAINT FK2B91A9DE7F2C8017 TO FKD654E027F2C8017; +ALTER TABLE alf_node_assoc RENAME CONSTRAINT FK5BAEF398B69C43F3 TO FKE1A550BCB69C43F3; +ALTER TABLE alf_node_assoc RENAME CONSTRAINT FK5BAEF398A8FC7769 TO FKE1A550BCA8FC7769; +ALTER TABLE alf_node_status RENAME CONSTRAINT FK38ECB8CF7F2C8017 TO FK71C2002B7F2C8017; +ALTER TABLE alf_store RENAME CONSTRAINT FK68AF8E122DBA5BA TO FKBD4FF53D22DBA5BA; + +-- +-- Rename the indexes to keep in synch with the new table names. For Oracle, Hibernate doesn't create or add these +-- +ALTER INDEX FKF064DF7560601995 RENAME TO FKFFF41F9960601995; +ALTER INDEX FKF064DF75B25A50BF RENAME TO FKFFF41F99B25A50BF; +ALTER INDEX FKF064DF75B9553F6C RENAME TO FKFFF41F99B9553F6C; +ALTER INDEX FK31D3BA097B7FDE43 RENAME TO FK8A749A657B7FDE43; +ALTER INDEX FKC6EFFF3274173FF4 RENAME TO FKFFC5468E74173FF4; +ALTER INDEX FKC6EFFF328E50E582 RENAME TO FKFFC5468E8E50E582; +ALTER INDEX FK33AE02B9553F6C RENAME TO FK60EFB626B9553F6C; +ALTER INDEX FK33AE02D24ADD25 RENAME TO FK60EFB626D24ADD25; +ALTER INDEX FKC962BF907F2C8017 RENAME TO FK7D4CF8EC7F2C8017; +ALTER INDEX FK2B91A9DE7F2C8017 RENAME TO FKD654E027F2C8017; +ALTER INDEX FK5BAEF398B69C43F3 RENAME TO FKE1A550BCB69C43F3; +ALTER INDEX FK5BAEF398A8FC7769 RENAME TO FKE1A550BCA8FC7769; +ALTER INDEX FK38ECB8CF7F2C8017 RENAME TO FK71C2002B7F2C8017; +ALTER INDEX FK68AF8E122DBA5BA RENAME TO FKBD4FF53D22DBA5BA; + +-- +-- Record script finish +-- +delete from alf_applied_patch where id = 'patch.schemaUpdateScript-V1.4-1'; +insert into alf_applied_patch + (id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report) + values + ( + 'patch.schemaUpdateScript-V1.4-1', 'Manually execute script upgrade V1.4 part 1', + 0, 19, -1, 20, sysdate, 'UNKOWN', 1, 1, 'Script completed' + ); diff --git a/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.Oracle9Dialect/AlfrescoSchemaUpdate-1.4-2.sql b/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.Oracle9Dialect/AlfrescoSchemaUpdate-1.4-2.sql new file mode 100644 index 0000000000..ee3de98dad --- /dev/null +++ b/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.Oracle9Dialect/AlfrescoSchemaUpdate-1.4-2.sql @@ -0,0 +1,69 @@ +-- ------------------------------------------------------ +-- Alfresco Schema conversion V1.3 to V1.4 Part 2 (Oracle) +-- +-- Adds the alf_transaction and alf_server tables to keep track of the sources +-- of transactions. +-- +-- Author: Derek Hulley +-- ------------------------------------------------------ + +-- +-- Create server and transaction tables +-- + +create table alf_server +( + id number(19,0) not null, + ip_address varchar2(15 char) not null, + primary key (id), + unique (ip_address) +); +insert into alf_server (id, ip_address) values (0, '0.0.0.0'); + +create table alf_transaction +( + id number(19,0) not null, + server_id number(19,0), + change_txn_id varchar2(56 char) not null, + primary key (id) +); +alter table alf_transaction add constraint FKB8761A3A9AE340B7 foreign key (server_id) references alf_server; +create index FKB8761A3A9AE340B7 on alf_transaction (server_id); + +insert into alf_transaction + ( + id, server_id, change_txn_id + ) + select + hibernate_sequence.nextval, + (select max(id) from alf_server), + change_txn_id + from alf_node_status; + +-- Alter node status +alter table alf_node_status add + ( + transaction_id number(19,0) DEFAULT 0 NOT NULL + ); +-- Update FK column +update alf_node_status ns SET ns.transaction_id = + ( + select t.id from alf_transaction t + where t.change_txn_id = ns.change_txn_id and rownum = 1 + ); +alter table alf_node_status DROP COLUMN change_txn_id; +alter table alf_node_status ADD CONSTRAINT FK71C2002B9E57C13D FOREIGN KEY (transaction_id) REFERENCES alf_transaction (id); +create index FK71C2002B9E57C13D on alf_node_status (transaction_id); +alter table alf_node_status DROP COLUMN deleted;(optional) + +-- +-- Record script finish +-- +delete from alf_applied_patch where id = 'patch.schemaUpdateScript-V1.4-2'; +insert into alf_applied_patch + (id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report) + values + ( + 'patch.schemaUpdateScript-V1.4-2', 'Manually execute script upgrade V1.4 part 2', + 0, 20, -1, 21, sysdate, 'UNKOWN', 1, 1, 'Script completed' + ); diff --git a/config/alfresco/desktop/Alfresco.exe b/config/alfresco/desktop/Alfresco.exe index 2bc8239ab1..1b2dfaf205 100644 Binary files a/config/alfresco/desktop/Alfresco.exe and b/config/alfresco/desktop/Alfresco.exe differ diff --git a/config/alfresco/desktop/showDetails.js b/config/alfresco/desktop/showDetails.js new file mode 100644 index 0000000000..0173a110b3 --- /dev/null +++ b/config/alfresco/desktop/showDetails.js @@ -0,0 +1,26 @@ +// Main action + +function runAction() +{ + var urlStr = webURL + "navigate/showDocDetails/workspace/SpacesStore/" + deskParams.getTarget(0).getNode().getId() + + "?ticket=" + deskParams.getTicket(); + + return urlStr; +} + +// 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," + +var response = "7," + runAction(); +response; diff --git a/config/alfresco/desktop/urlLink.js b/config/alfresco/desktop/urlLink.js new file mode 100644 index 0000000000..f498fb1549 --- /dev/null +++ b/config/alfresco/desktop/urlLink.js @@ -0,0 +1,29 @@ +// Main action + +function runAction() +{ + out.println("URL link to " + deskParams.getFolder()); + + var urlStr = webURL + "navigate/browse/workspace/SpacesStore/" + deskParams.getFolderNode().getId() + + "?ticket=" + deskParams.getTicket(); + out.println( " url=" + urlStr); + + return urlStr; +} + +// 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," + +var response = "7," + runAction(); +response; diff --git a/config/alfresco/domain/hibernate-cfg.properties b/config/alfresco/domain/hibernate-cfg.properties index 68da4ebd1c..5da910a9cd 100644 --- a/config/alfresco/domain/hibernate-cfg.properties +++ b/config/alfresco/domain/hibernate-cfg.properties @@ -1,16 +1,15 @@ -# -# Hibernate configuration -# -hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect - -hibernate.jdbc.use_streams_for_binary=true -hibernate.hbm2ddl.auto=update -hibernate.show_sql=false -hibernate.cache.use_query_cache=true -hibernate.max_fetch_depth=10 -hibernate.cache.provider_class=org.alfresco.repo.cache.InternalEhCacheManagerFactoryBean -hibernate.cache.use_second_level_cache=true -hibernate.default_batch_fetch_size=1 -hibernate.jdbc.batch_size=32 -hibernate.connection.release_mode=auto +# +# Hibernate configuration +# +hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect + +hibernate.jdbc.use_streams_for_binary=true +hibernate.show_sql=false +hibernate.cache.use_query_cache=true +hibernate.max_fetch_depth=10 +hibernate.cache.provider_class=org.alfresco.repo.cache.InternalEhCacheManagerFactoryBean +hibernate.cache.use_second_level_cache=true +hibernate.default_batch_fetch_size=1 +hibernate.jdbc.batch_size=32 +hibernate.connection.release_mode=auto hibernate.connection.isolation=4 \ No newline at end of file diff --git a/config/alfresco/ehcache-default.xml b/config/alfresco/ehcache-default.xml index a280c23786..df55450b15 100644 --- a/config/alfresco/ehcache-default.xml +++ b/config/alfresco/ehcache-default.xml @@ -1,184 +1,184 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/extension/custom-connection-pool-context.xml.sample b/config/alfresco/extension/custom-connection-pool-context.xml.sample new file mode 100644 index 0000000000..546c1d3ac1 --- /dev/null +++ b/config/alfresco/extension/custom-connection-pool-context.xml.sample @@ -0,0 +1,57 @@ + + + + + + + + + + + ${db.driver} + + + ${db.url} + + + ${db.username} + + + ${db.password} + + + false + + + + ${db.pool.initial} + + + ${db.pool.max} + + + 300000 + + + -1 + + + false + + + 50000 + + + true + + + select 1 + + + + diff --git a/config/alfresco/extension/custom-db-connection.properties.sample b/config/alfresco/extension/custom-db-connection.properties.sample index 175328c81f..de46bd2233 100644 --- a/config/alfresco/extension/custom-db-connection.properties.sample +++ b/config/alfresco/extension/custom-db-connection.properties.sample @@ -9,7 +9,13 @@ #db.pool.max=100 # -# MySQL connection (This is default and requires mysql-connector-java-3.1.12-bin.jar, which ships with the Alfresco server) +# HSQL connection +# +#db.driver=org.hsqldb.jdbcDriver +#db.url=jdbc:hsqldb:file:alf_data/hsql_data/alfresco;ifexists=true;shutdown=true; + +# +# MySQL connection (This is default and requires mysql-connector-java-5.0.3-bin.jar, which ships with the Alfresco server) # #db.driver=org.gjt.mm.mysql.Driver #db.url=jdbc:mysql://localhost/alfresco diff --git a/config/alfresco/extension/custom-hibernate-dialect.properties.sample b/config/alfresco/extension/custom-hibernate-dialect.properties.sample index 611a40ca78..e3563689d5 100644 --- a/config/alfresco/extension/custom-hibernate-dialect.properties.sample +++ b/config/alfresco/extension/custom-hibernate-dialect.properties.sample @@ -7,6 +7,11 @@ # For a full list: http://www.hibernate.org/hib_docs/v3/reference/en/html_single/#configuration-optional-dialects # +# +# HSQL dialect +# +#hibernate.dialect=org.hibernate.dialect.HSQLDialect + # # MySQL dialect (default) # diff --git a/config/alfresco/extension/file-servers-custom.xml b/config/alfresco/extension/file-servers-custom.xml new file mode 100644 index 0000000000..95bf3f6d5f --- /dev/null +++ b/config/alfresco/extension/file-servers-custom.xml @@ -0,0 +1,55 @@ + + + + + + + + + + workspace://SpacesStore + /app:company_home + + + + __Alfresco.url + http://${localname}:8080/alfresco/ + + + + + + + + + + alfresco/desktop/Alfresco.exe + http://${localname}:8080/alfresco/ + + + org.alfresco.filesys.smb.server.repo.desk.CheckInOutDesktopAction + CheckInOut + __CheckInOut.exe + + + org.alfresco.filesys.smb.server.repo.desk.JavaScriptDesktopAction + JavaScriptURL + __ShowDetails.exe + + anyFiles + copyToTarget + + + + + + + + + + diff --git a/config/alfresco/extension/index-tracking-context.xml.sample b/config/alfresco/extension/index-tracking-context.xml.sample new file mode 100644 index 0000000000..5c1343bec2 --- /dev/null +++ b/config/alfresco/extension/index-tracking-context.xml.sample @@ -0,0 +1,71 @@ + + + + + + + + + + + org.alfresco.repo.node.index.IndexRecoveryJob + + + + + + + + + + + + + + + 0,30 * * * * ? + + + + + + true + + + + + + + + + + org.alfresco.repo.node.index.IndexRecoveryJob + + + + + + + + + + + + + + + + 5 + + + 0 + + + + diff --git a/config/alfresco/file-servers.xml b/config/alfresco/file-servers.xml index e26cd80af5..b1583473fc 100644 --- a/config/alfresco/file-servers.xml +++ b/config/alfresco/file-servers.xml @@ -38,25 +38,28 @@ __AlfrescoClient.url - http://localhost:8080/alfresco/ + http://${localname}:8080/alfresco/ - - - - - - + + + + + + + + + diff --git a/config/alfresco/hibernate-context.xml b/config/alfresco/hibernate-context.xml index 115539c043..095330aa22 100644 --- a/config/alfresco/hibernate-context.xml +++ b/config/alfresco/hibernate-context.xml @@ -1,277 +1,277 @@ - - - - - - - - - - classpath:alfresco/domain/hibernate-cfg.properties - - - - - - - true - - - - classpath:alfresco/domain/cache-strategies.properties - - - - - - - - - - - - - true - - - - - - - - org/alfresco/repo/domain/hibernate/Node.hbm.xml - org/alfresco/repo/domain/hibernate/Store.hbm.xml - org/alfresco/repo/domain/hibernate/Transaction.hbm.xml - org/alfresco/repo/domain/hibernate/VersionCount.hbm.xml - org/alfresco/repo/domain/hibernate/AppliedPatch.hbm.xml - org/alfresco/repo/domain/hibernate/Permission.hbm.xml - org/alfresco/repo/avm/hibernate/AVM.hbm.xml - - - - org/alfresco/repo/audit/hibernate/Audit.hbm.xml - - - - - - - - org/jbpm/graph/action/Script.hbm.xml - org/jbpm/db/hibernate.queries.hbm.xml - org/jbpm/graph/def/ProcessDefinition.hbm.xml - org/jbpm/graph/def/Node.hbm.xml - org/jbpm/graph/def/Transition.hbm.xml - org/jbpm/graph/def/Event.hbm.xml - org/jbpm/graph/def/Action.hbm.xml - org/jbpm/graph/def/SuperState.hbm.xml - org/jbpm/graph/def/ExceptionHandler.hbm.xml - org/jbpm/instantiation/Delegation.hbm.xml - org/jbpm/graph/node/StartState.hbm.xml - org/jbpm/graph/node/EndState.hbm.xml - org/jbpm/graph/node/ProcessState.hbm.xml - org/jbpm/graph/node/Decision.hbm.xml - org/jbpm/graph/node/Fork.hbm.xml - org/jbpm/graph/node/Join.hbm.xml - org/jbpm/graph/node/State.hbm.xml - org/jbpm/graph/node/TaskNode.hbm.xml - org/jbpm/context/def/ContextDefinition.hbm.xml - org/jbpm/context/def/VariableAccess.hbm.xml - org/jbpm/taskmgmt/def/TaskMgmtDefinition.hbm.xml - org/jbpm/taskmgmt/def/Swimlane.hbm.xml - org/jbpm/taskmgmt/def/Task.hbm.xml - org/jbpm/taskmgmt/def/TaskController.hbm.xml - org/jbpm/module/def/ModuleDefinition.hbm.xml - org/jbpm/bytes/ByteArray.hbm.xml - org/jbpm/file/def/FileDefinition.hbm.xml - org/jbpm/scheduler/def/CreateTimerAction.hbm.xml - org/jbpm/scheduler/def/CancelTimerAction.hbm.xml - org/jbpm/graph/exe/Comment.hbm.xml - org/jbpm/graph/exe/ProcessInstance.hbm.xml - org/jbpm/graph/exe/Token.hbm.xml - org/jbpm/graph/exe/RuntimeAction.hbm.xml - org/jbpm/module/exe/ModuleInstance.hbm.xml - org/jbpm/context/exe/ContextInstance.hbm.xml - org/jbpm/context/exe/TokenVariableMap.hbm.xml - org/jbpm/context/exe/VariableInstance.hbm.xml - org/jbpm/context/exe/variableinstance/ByteArrayInstance.hbm.xml - org/jbpm/context/exe/variableinstance/DateInstance.hbm.xml - org/jbpm/context/exe/variableinstance/DoubleInstance.hbm.xml - org/jbpm/context/exe/variableinstance/HibernateLongInstance.hbm.xml - org/jbpm/context/exe/variableinstance/HibernateStringInstance.hbm.xml - org/jbpm/context/exe/variableinstance/LongInstance.hbm.xml - org/jbpm/context/exe/variableinstance/NullInstance.hbm.xml - org/jbpm/context/exe/variableinstance/StringInstance.hbm.xml - org/jbpm/msg/Message.hbm.xml - org/jbpm/msg/db/TextMessage.hbm.xml - org/jbpm/command/ExecuteActionCommand.hbm.xml - org/jbpm/command/ExecuteNodeCommand.hbm.xml - org/jbpm/command/SignalCommand.hbm.xml - org/jbpm/command/TaskInstanceEndCommand.hbm.xml - org/jbpm/taskmgmt/exe/TaskMgmtInstance.hbm.xml - org/jbpm/taskmgmt/exe/TaskInstance.hbm.xml - org/jbpm/taskmgmt/exe/PooledActor.hbm.xml - org/jbpm/taskmgmt/exe/SwimlaneInstance.hbm.xml - org/jbpm/scheduler/exe/Timer.hbm.xml - org/jbpm/logging/log/ProcessLog.hbm.xml - org/jbpm/logging/log/MessageLog.hbm.xml - org/jbpm/logging/log/CompositeLog.hbm.xml - org/jbpm/graph/log/ActionLog.hbm.xml - org/jbpm/graph/log/NodeLog.hbm.xml - org/jbpm/graph/log/ProcessInstanceCreateLog.hbm.xml - org/jbpm/graph/log/ProcessInstanceEndLog.hbm.xml - org/jbpm/graph/log/SignalLog.hbm.xml - org/jbpm/graph/log/TokenCreateLog.hbm.xml - org/jbpm/graph/log/TokenEndLog.hbm.xml - org/jbpm/graph/log/TransitionLog.hbm.xml - org/jbpm/context/log/VariableLog.hbm.xml - org/jbpm/context/log/VariableCreateLog.hbm.xml - org/jbpm/context/log/VariableDeleteLog.hbm.xml - org/jbpm/context/log/VariableUpdateLog.hbm.xml - org/jbpm/context/log/variableinstance/ByteArrayUpdateLog.hbm.xml - org/jbpm/context/log/variableinstance/DateUpdateLog.hbm.xml - org/jbpm/context/log/variableinstance/DoubleUpdateLog.hbm.xml - org/jbpm/context/log/variableinstance/HibernateLongUpdateLog.hbm.xml - org/jbpm/context/log/variableinstance/HibernateStringUpdateLog.hbm.xml - org/jbpm/context/log/variableinstance/LongUpdateLog.hbm.xml - org/jbpm/context/log/variableinstance/StringUpdateLog.hbm.xml - org/jbpm/taskmgmt/log/TaskLog.hbm.xml - org/jbpm/taskmgmt/log/TaskCreateLog.hbm.xml - org/jbpm/taskmgmt/log/TaskAssignLog.hbm.xml - org/jbpm/taskmgmt/log/TaskEndLog.hbm.xml - org/jbpm/taskmgmt/log/SwimlaneLog.hbm.xml - org/jbpm/taskmgmt/log/SwimlaneCreateLog.hbm.xml - org/jbpm/taskmgmt/log/SwimlaneAssignLog.hbm.xml - - - org/alfresco/repo/workflow/jbpm/WorkflowTaskInstance.hbm.xml - - - - - - ${cache.strategy} - ${cache.strategy} - ${cache.strategy} - ${cache.strategy} - ${cache.strategy} - ${cache.strategy} - ${cache.strategy} - ${cache.strategy} - ${cache.strategy} - - ${cache.strategy} - ${cache.strategy} - ${cache.strategy} - ${cache.strategy} - - ${cache.strategy} - ${cache.strategy} - ${cache.strategy} - - - - - ${cache.strategy} - ${cache.strategy} - ${cache.strategy} - - ${cache.strategy} - ${cache.strategy} - - - - - - - - SYNCHRONIZATION_ALWAYS - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - org.alfresco.repo.node.db.NodeDaoService - - - - - - - dbNodeDaoServiceTxnRegistration - - - - - - - - - - - - - - + + + + + + + + + + classpath:alfresco/domain/hibernate-cfg.properties + + + + + + + true + + + + classpath:alfresco/domain/cache-strategies.properties + + + + + + + + + + + + + true + + + + + + + + org/alfresco/repo/domain/hibernate/Node.hbm.xml + org/alfresco/repo/domain/hibernate/Store.hbm.xml + org/alfresco/repo/domain/hibernate/Transaction.hbm.xml + org/alfresco/repo/domain/hibernate/VersionCount.hbm.xml + org/alfresco/repo/domain/hibernate/AppliedPatch.hbm.xml + org/alfresco/repo/domain/hibernate/Permission.hbm.xml + org/alfresco/repo/avm/hibernate/AVM.hbm.xml + + + + org/alfresco/repo/audit/hibernate/Audit.hbm.xml + + + + + + + + org/jbpm/graph/action/Script.hbm.xml + org/jbpm/db/hibernate.queries.hbm.xml + org/jbpm/graph/def/ProcessDefinition.hbm.xml + org/jbpm/graph/def/Node.hbm.xml + org/jbpm/graph/def/Transition.hbm.xml + org/jbpm/graph/def/Event.hbm.xml + org/jbpm/graph/def/Action.hbm.xml + org/jbpm/graph/def/SuperState.hbm.xml + org/jbpm/graph/def/ExceptionHandler.hbm.xml + org/jbpm/instantiation/Delegation.hbm.xml + org/jbpm/graph/node/StartState.hbm.xml + org/jbpm/graph/node/EndState.hbm.xml + org/jbpm/graph/node/ProcessState.hbm.xml + org/jbpm/graph/node/Decision.hbm.xml + org/jbpm/graph/node/Fork.hbm.xml + org/jbpm/graph/node/Join.hbm.xml + org/jbpm/graph/node/State.hbm.xml + org/jbpm/graph/node/TaskNode.hbm.xml + org/jbpm/context/def/ContextDefinition.hbm.xml + org/jbpm/context/def/VariableAccess.hbm.xml + org/jbpm/taskmgmt/def/TaskMgmtDefinition.hbm.xml + org/jbpm/taskmgmt/def/Swimlane.hbm.xml + org/jbpm/taskmgmt/def/Task.hbm.xml + org/jbpm/taskmgmt/def/TaskController.hbm.xml + org/jbpm/module/def/ModuleDefinition.hbm.xml + org/jbpm/bytes/ByteArray.hbm.xml + org/jbpm/file/def/FileDefinition.hbm.xml + org/jbpm/scheduler/def/CreateTimerAction.hbm.xml + org/jbpm/scheduler/def/CancelTimerAction.hbm.xml + org/jbpm/graph/exe/Comment.hbm.xml + org/jbpm/graph/exe/ProcessInstance.hbm.xml + org/jbpm/graph/exe/Token.hbm.xml + org/jbpm/graph/exe/RuntimeAction.hbm.xml + org/jbpm/module/exe/ModuleInstance.hbm.xml + org/jbpm/context/exe/ContextInstance.hbm.xml + org/jbpm/context/exe/TokenVariableMap.hbm.xml + org/jbpm/context/exe/VariableInstance.hbm.xml + org/jbpm/context/exe/variableinstance/ByteArrayInstance.hbm.xml + org/jbpm/context/exe/variableinstance/DateInstance.hbm.xml + org/jbpm/context/exe/variableinstance/DoubleInstance.hbm.xml + org/jbpm/context/exe/variableinstance/HibernateLongInstance.hbm.xml + org/jbpm/context/exe/variableinstance/HibernateStringInstance.hbm.xml + org/jbpm/context/exe/variableinstance/LongInstance.hbm.xml + org/jbpm/context/exe/variableinstance/NullInstance.hbm.xml + org/jbpm/context/exe/variableinstance/StringInstance.hbm.xml + org/jbpm/msg/Message.hbm.xml + org/jbpm/msg/db/TextMessage.hbm.xml + org/jbpm/command/ExecuteActionCommand.hbm.xml + org/jbpm/command/ExecuteNodeCommand.hbm.xml + org/jbpm/command/SignalCommand.hbm.xml + org/jbpm/command/TaskInstanceEndCommand.hbm.xml + org/jbpm/taskmgmt/exe/TaskMgmtInstance.hbm.xml + org/jbpm/taskmgmt/exe/TaskInstance.hbm.xml + org/jbpm/taskmgmt/exe/PooledActor.hbm.xml + org/jbpm/taskmgmt/exe/SwimlaneInstance.hbm.xml + org/jbpm/scheduler/exe/Timer.hbm.xml + org/jbpm/logging/log/ProcessLog.hbm.xml + org/jbpm/logging/log/MessageLog.hbm.xml + org/jbpm/logging/log/CompositeLog.hbm.xml + org/jbpm/graph/log/ActionLog.hbm.xml + org/jbpm/graph/log/NodeLog.hbm.xml + org/jbpm/graph/log/ProcessInstanceCreateLog.hbm.xml + org/jbpm/graph/log/ProcessInstanceEndLog.hbm.xml + org/jbpm/graph/log/SignalLog.hbm.xml + org/jbpm/graph/log/TokenCreateLog.hbm.xml + org/jbpm/graph/log/TokenEndLog.hbm.xml + org/jbpm/graph/log/TransitionLog.hbm.xml + org/jbpm/context/log/VariableLog.hbm.xml + org/jbpm/context/log/VariableCreateLog.hbm.xml + org/jbpm/context/log/VariableDeleteLog.hbm.xml + org/jbpm/context/log/VariableUpdateLog.hbm.xml + org/jbpm/context/log/variableinstance/ByteArrayUpdateLog.hbm.xml + org/jbpm/context/log/variableinstance/DateUpdateLog.hbm.xml + org/jbpm/context/log/variableinstance/DoubleUpdateLog.hbm.xml + org/jbpm/context/log/variableinstance/HibernateLongUpdateLog.hbm.xml + org/jbpm/context/log/variableinstance/HibernateStringUpdateLog.hbm.xml + org/jbpm/context/log/variableinstance/LongUpdateLog.hbm.xml + org/jbpm/context/log/variableinstance/StringUpdateLog.hbm.xml + org/jbpm/taskmgmt/log/TaskLog.hbm.xml + org/jbpm/taskmgmt/log/TaskCreateLog.hbm.xml + org/jbpm/taskmgmt/log/TaskAssignLog.hbm.xml + org/jbpm/taskmgmt/log/TaskEndLog.hbm.xml + org/jbpm/taskmgmt/log/SwimlaneLog.hbm.xml + org/jbpm/taskmgmt/log/SwimlaneCreateLog.hbm.xml + org/jbpm/taskmgmt/log/SwimlaneAssignLog.hbm.xml + + + org/alfresco/repo/workflow/jbpm/WorkflowTaskInstance.hbm.xml + + + + + + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} + + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} + + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} + + + + + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} + + ${cache.strategy} + ${cache.strategy} + + + + + + + + SYNCHRONIZATION_ALWAYS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.alfresco.repo.node.db.NodeDaoService + + + + + + + dbNodeDaoServiceTxnRegistration + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/import-export-context.xml b/config/alfresco/import-export-context.xml index 6b09562fe9..7dacdad59a 100644 --- a/config/alfresco/import-export-context.xml +++ b/config/alfresco/import-export-context.xml @@ -171,8 +171,8 @@ - - + + @@ -227,6 +227,9 @@ --> + + + diff --git a/config/alfresco/messages/bpm-messages.properties b/config/alfresco/messages/bpm-messages.properties index 69419ae91b..ddfee4d3d2 100644 --- a/config/alfresco/messages/bpm-messages.properties +++ b/config/alfresco/messages/bpm-messages.properties @@ -4,8 +4,8 @@ bpm_businessprocessmodel.title=Business Process Model bpm_businessprocessmodel.description=Base definitions of all Business Processes # Default transition -bpm_businessprocessmodel.transition.title=Done -bpm_businessprocessmodel.transition.description=Done +bpm_businessprocessmodel.transition.title=Task Done +bpm_businessprocessmodel.transition.description=Task Done # Base Task bpm_businessprocessmodel.type.bpm_task.title=Task diff --git a/config/alfresco/messages/copy-service.properties b/config/alfresco/messages/copy-service.properties new file mode 100644 index 0000000000..ce041e4bae --- /dev/null +++ b/config/alfresco/messages/copy-service.properties @@ -0,0 +1,3 @@ +# copy service externalised display strings + +copy_service.copy_of_label=Copy of {0} \ No newline at end of file diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties index c2a5bf70ef..aad05f496d 100644 --- a/config/alfresco/messages/patch-service.properties +++ b/config/alfresco/messages/patch-service.properties @@ -27,8 +27,8 @@ patch.savedSearchesPermission.description=Sets required permissions on 'Saved Se patch.savedSearchesPermission.result.applied=Granted CONTRIBUTOR role to EVERYONE on ''Saved Searches'' folder: {0}. patch.savedSearchesPermission.err.not_found='Saved Searches' folder could not be found. -patch.updatePermissionData.description=Update permission entries from 'folder' to 'cmobject'. -patch.updatePermissionData.upgrade=Please follow an upgrade path via server version 1.2.1 +patch.updatePermissionData.description=Update permissions from 'folder' to 'cmobject' [JIRA: AR-344]. +patch.updatePermissionData.result=Changed {0} 'folder' access control entries to 'cmobject'. patch.authoritiesFolder.description=Ensures the existence of the user authorities folder [JIRA: AR-497]. @@ -39,7 +39,7 @@ patch.fixNodeSerializableValues.description=Ensure that property values are not patch.fixNodeSerializableValues.result=Fixed {0} node property serialized values patch.updateGuestPermission.description=Rename guest permission from 'Guest' to 'Consumer' -patch.updateGuestPermission.upgrade=Please follow an upgrade path via server version 1.2.1 +patch.updateGuestPermission.result=Changed {0} 'Guest' access control entries to 'Consumer'. patch.categoryRootPermission.description=Sets required permissions on 'Category Root' folder. patch.categoryRootPermission.result=Granted CONSUMER role to GUEST on ''Category Root'' folder: {0}. @@ -52,7 +52,7 @@ patch.spacesRootPermission.description=Change Spaces store root permission from patch.spacesRootPermission.result=Updated Spaces store root permission from 'Consumer' to 'Read' patch.contentPermission.description=Update permission entries from 'cm:content' to 'sys:base'. -patch.contentPermission.upgrade=Please follow an upgrade path via server version 1.2.1 +patch.contentPermission.result=Changed {0} 'cm:content' access control entries to 'sys:base'. patch.forumsIcons.description=Updates forums icon references patch.forumsIcons.result=Updated {0} icon references @@ -96,6 +96,6 @@ patch.schemaUpgradeScript.description=Ensures that the database upgrade script h patch.schemaUpgradeScript.err.not_executed=The schema upgrade script, ''{0}'', has not been run against this database. patch.uniqueChildName.description=Checks and renames duplicate children. -patch.uniqueChildName.copyOf=({0}) +patch.uniqueChildName.copyOf=({0}-{1}) patch.uniqueChildName.result=Checked {0} associations and fixed {1} duplicates. See file {2} for details. - +patch.uniqueChildName.err.unable_to_fix=Auto-fixing of duplicate names failed. See file {0} for details. diff --git a/config/alfresco/messages/schema-update.properties b/config/alfresco/messages/schema-update.properties index 5cebba18a2..425124efa3 100644 --- a/config/alfresco/messages/schema-update.properties +++ b/config/alfresco/messages/schema-update.properties @@ -1,6 +1,8 @@ # Schema update messages schema.update.msg.executing_script=Executing database script: {0} +schema.update.msg.optional_statement_failed=Optional statement execution failed:\n SQL: {0}\n Error: {1}\n File: {2}\n Line: {3} +schema.update.err.statement_failed=Statement execution failed:\n SQL: {0}\n Error: {1}\n File: {2}\n Line: {3} schema.update.err.update_failed=Schema auto-update failed schema.update.err.validation_failed=Schema validation failed schema.update.err.update_script_not_run=The following schema upgrade script needs to be executed manually: {0} diff --git a/config/alfresco/messages/workflow-interpreter-help.properties b/config/alfresco/messages/workflow-interpreter-help.properties new file mode 100644 index 0000000000..398b1b772b --- /dev/null +++ b/config/alfresco/messages/workflow-interpreter-help.properties @@ -0,0 +1 @@ +workflow_console.help=alfresco/messages/workflow-interpreter-help.txt diff --git a/config/alfresco/messages/workflow-interpreter-help.txt b/config/alfresco/messages/workflow-interpreter-help.txt new file mode 100644 index 0000000000..d8ed5405e6 --- /dev/null +++ b/config/alfresco/messages/workflow-interpreter-help.txt @@ -0,0 +1,174 @@ +## +## Meta commands +## + +ok> help + + List this help. + +ok> r + + Repeat last command. + +ok> user [] + + Switch to specified . If is omitted, the currently + selected user is shown. + +ok> use + + Show current workflow context. + +## +## Workflow Definition Commands +## + +ok> deploy + + Deploy workflow definition to Alfresco server. + + class path to workflow definition. + +ok> redeploy + + Redeploy the last workflow definition. + +ok> show definitions + + List all deployed workflow definitions. + +ok> use definition [] + + Switch to use the workflow definition identified by . If + is ommited, the currently selected workflow definition + is shown. + +## +## Variable Commands +## + +ok> var + + Show all defined variables. + +ok> var [*]= + + Define or update a variable. + + variable name + [*] if specified, define a collection + variable value (comma-seperate to specify a list of values) + + e.g. + + set bpm:assignee*=admin,fred + set wf:notifyMe=true + +ok> var [*] person + + Define or update a (cm:person) node ref variable. + + variable name + [*] if specified, define a collection + variable value (comma-seperate to specify a list of values) + + e.g. + + set bpm:assignee* person admin,fred + +ok> var = + + Delete an existing variable. + + variable name + +## +## Workflow Commands +## + +ok> start []]* + + Start a new workflow using the currently selected workflow definition. Start + Task parameters are provided as name/value pairs or references to pre-defined + variables. + + e.g. + + start bpm:assignee=david wf:predefined + +ok> show workflows + + Display the list of active workflows for the currently selected workflow + definition. + +ok> use workflow + + Use the specified . + +ok> show paths [] + + Display the workflow paths for the specified . If + is omitted, the paths for the currently started workflow are shown. + +ok> show transitions [] + + Display all available transitions for the specified . If + is omitted, the transitions for the currently started workflow + are shown. + +ok> signal [] + + Signal transition on specified . If is omitted, the + default transition is taken. + +ok> desc workflow + + Describe the specified . + +ok> end workflow + + End (cancel) the specified . + +## +## Task Commands +## + +ok> show my tasks + + List tasks assigned to the currently selected user. + +ok> show my completed + + List tasks completed by the currently selected user. + +ok> show tasks [] + + List tasks associated with the specified workflow . If is + omitted, the tasks associated with the currently selected workflow path are + shown. + +ok> desc task + + Describe the task identified by . + +ok> update task []]* + + Update the state of the specified . Task properties are provided as + name/value pairs or references to pre-defined variables. + + variable name + [*] if specified, define a collection + variable value (comma-seperate to specify a list of values) + + e.g. + + update task jbpm$122 bpm:assignee=fred wf:notifyMe=false + +ok> end task [] + + End the task identified by . If is omitted, the + default transition is taken. + +## +## end +## diff --git a/config/alfresco/model/contentModel.xml b/config/alfresco/model/contentModel.xml index e6523fb8d9..ddbfc66083 100644 --- a/config/alfresco/model/contentModel.xml +++ b/config/alfresco/model/contentModel.xml @@ -1,711 +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 - 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 - - - - - - - + + + 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/network-protocol-context.xml b/config/alfresco/network-protocol-context.xml index 10fa179cfe..f5d0408e00 100644 --- a/config/alfresco/network-protocol-context.xml +++ b/config/alfresco/network-protocol-context.xml @@ -57,6 +57,7 @@ + diff --git a/config/alfresco/public-services-context.xml b/config/alfresco/public-services-context.xml index 9138bd9d63..5cda07fcef 100644 --- a/config/alfresco/public-services-context.xml +++ b/config/alfresco/public-services-context.xml @@ -1,1186 +1,1194 @@ - - - - - - - - - - http://www.alfresco.org - - - - - - - - org.alfresco.service.ServiceRegistry - - - - - - - - - - - - - - org.alfresco.service.ServiceRegistry - - - Repository service registry - - - - - - - - - - - - org.alfresco.service.descriptor.DescriptorService - - - - - - - - - - - - - - - org.alfresco.service.descriptor.DescriptorService - - - Descriptor service - - - - - - - - - - - false - - - - - - - - - org.alfresco.service.namespace.NamespaceService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.namespace.NamespaceService - - - Namespace service - - - - - - - - - - - - org.alfresco.service.cmr.dictionary.DictionaryService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.dictionary.DictionaryService - - - Dictionary Service - - - - - - - - - org.alfresco.service.ServiceDescriptor - org.alfresco.service.cmr.repository.NodeService - - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.readOnly} - ${server.transaction.mode.readOnly} - ${server.transaction.mode.readOnly} - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.repository.NodeService - - - Node Service - - - - - - - - org.alfresco.service.cmr.repository.ContentService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.repository.ContentService - - - Content Service - - - - - - - - org.alfresco.service.cmr.repository.MimetypeService - - - - - - - - - - - - - - - - - org.alfresco.service.cmr.repository.MimetypeService - - - Mime Type Service - - - - - - - - org.alfresco.service.cmr.search.SearchService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.search.SearchService - - - Search Service - - - - - - - - org.alfresco.service.cmr.search.CategoryService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.search.CategoryService - - - Category Service - - - - - - - - org.alfresco.service.cmr.repository.CopyService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.repository.CopyService - - - Copy Service - - - - - - - - org.alfresco.service.cmr.lock.LockService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.lock.LockService - - - Lock Service - - - - - - - - org.alfresco.service.cmr.version.VersionService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.version.VersionService - - - Version Service - - - - - - - - org.alfresco.service.cmr.coci.CheckOutCheckInService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.coci.CheckOutCheckInService - - - Version Service - - - - - - - - org.alfresco.service.cmr.rule.RuleService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.rule.RuleService - - - Rule Service - - - - - - - - org.alfresco.service.cmr.view.ImporterService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.view.ImporterService - - - Importer Service - - - - - - - - org.alfresco.service.cmr.view.ExporterService - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.view.ExporterService - - - Exporter Service - - - - - - - - org.alfresco.service.cmr.action.ActionService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.action.ActionService - - - Action Service - - - - - - - - org.alfresco.service.cmr.security.PermissionService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.security.PermissionService - - - Permission Service - - - - - - - - org.alfresco.service.cmr.security.AuthorityService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.security.AuthorityService - - - Authority Service - - - - - - - - org.alfresco.service.cmr.security.OwnableService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.security.OwnableService - - - OwnableService Service - - - - - - - - org.alfresco.service.cmr.security.PersonService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.security.PersonService - - - PersonService Service - - - - - - - - org.alfresco.service.cmr.security.AuthenticationService - - - - - - - - - - - - - - - - - - - - - - PROPAGATION_NOT_SUPPORTED, readOnly - PROPAGATION_NOT_SUPPORTED, readOnly - PROPAGATION_NOT_SUPPORTED, readOnly - PROPAGATION_NOT_SUPPORTED, readOnly - PROPAGATION_NOT_SUPPORTED, readOnly - PROPAGATION_NOT_SUPPORTED, readOnly - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.security.AuthenticationService - - - AuthenticationService Service - - - - - - - - org.alfresco.service.cmr.repository.TemplateService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.repository.TemplateService - - - TemplateService Service - - - - - - - - org.alfresco.service.cmr.repository.ScriptService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.repository.ScriptService - - - ScriptService Service - - - - - - - - org.alfresco.service.cmr.model.FileFolderService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.readOnly} - ${server.transaction.mode.readOnly} - ${server.transaction.mode.readOnly} - ${server.transaction.mode.readOnly} - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.model.FileFolderService - - - FileFolderService Service - - - - - - - - - - - - - - org.alfresco.service.cmr.avm.AVMService - - - - - - - - - - - - - - - org.alfresco.service.cmr.avm.AVMService - - - AVM Service - - - - - - - - - - ${server.transaction.mode.readOnly} - ${server.transaction.mode.default} - ${server.transaction.mode.default} - ${server.transaction.mode.default} - ${server.transaction.mode.readOnly} - ${server.transaction.mode.readOnly} - ${server.transaction.mode.default} - - - - - - - - - - - - - - - - - - org.alfresco.service.cmr.avmsync.AVMSyncService - - - AVM Tree Synchronization Service - - - - - - - - - - ${server.transaction.mode.readOnly} - ${server.transaction.mode.default} - ${server.transaction.mode.default} - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.avmsync.AVMSyncService - - - - - - - - - - - - - - - - - org.alfresco.service.cmr.workflow.WorkflowService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.workflow.WorkflowService - - - Workflow Service - - - - - - - - - org.alfresco.service.cmr.audit.AuditService - - - - - - - - - - - - - - - - - - - - - - ${server.transaction.mode.default} - - - - - - - org.alfresco.service.cmr.audit.AuditService - - - Audit Service - - - - + + + + + + + + + + http://www.alfresco.org + + + + + + + + org.alfresco.service.ServiceRegistry + + + + + + + + + + + + + + org.alfresco.service.ServiceRegistry + + + Repository service registry + + + + + + + + + + + + org.alfresco.service.descriptor.DescriptorService + + + + + + + + + + + + + + + org.alfresco.service.descriptor.DescriptorService + + + Descriptor service + + + + + + + + + + + false + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.namespace.NamespaceService + + + Namespace service + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.dictionary.DictionaryService + + + Dictionary Service + + + + + + + + + org.alfresco.service.ServiceDescriptor + org.alfresco.service.cmr.repository.NodeService + + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.readOnly} + ${server.transaction.mode.readOnly} + ${server.transaction.mode.readOnly} + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.repository.NodeService + + + Node Service + + + + + + + + org.alfresco.service.cmr.repository.ContentService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.repository.ContentService + + + Content Service + + + + + + + + org.alfresco.service.cmr.repository.MimetypeService + + + + + + + + + + + + + + + + + org.alfresco.service.cmr.repository.MimetypeService + + + Mime Type Service + + + + + + + + org.alfresco.service.cmr.search.SearchService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.search.SearchService + + + Search Service + + + + + + + + org.alfresco.service.cmr.search.CategoryService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.search.CategoryService + + + Category Service + + + + + + + + org.alfresco.service.cmr.repository.CopyService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.repository.CopyService + + + Copy Service + + + + + + + + org.alfresco.service.cmr.lock.LockService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.lock.LockService + + + Lock Service + + + + + + + + org.alfresco.service.cmr.version.VersionService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.version.VersionService + + + Version Service + + + + + + + + org.alfresco.service.cmr.coci.CheckOutCheckInService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.coci.CheckOutCheckInService + + + Version Service + + + + + + + + org.alfresco.service.cmr.rule.RuleService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.rule.RuleService + + + Rule Service + + + + + + + + org.alfresco.service.cmr.view.ImporterService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.view.ImporterService + + + Importer Service + + + + + + + + org.alfresco.service.cmr.view.ExporterService + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.view.ExporterService + + + Exporter Service + + + + + + + + org.alfresco.service.cmr.action.ActionService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.action.ActionService + + + Action Service + + + + + + + + org.alfresco.service.cmr.security.PermissionService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.security.PermissionService + + + Permission Service + + + + + + + + org.alfresco.service.cmr.security.AuthorityService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.security.AuthorityService + + + Authority Service + + + + + + + + org.alfresco.service.cmr.security.OwnableService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.security.OwnableService + + + OwnableService Service + + + + + + + + org.alfresco.service.cmr.security.PersonService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.security.PersonService + + + PersonService Service + + + + + + + + org.alfresco.service.cmr.security.AuthenticationService + + + + + + + + + + + + + + + + + + + + + + PROPAGATION_NOT_SUPPORTED, readOnly + PROPAGATION_NOT_SUPPORTED, readOnly + PROPAGATION_NOT_SUPPORTED, readOnly + PROPAGATION_NOT_SUPPORTED, readOnly + PROPAGATION_NOT_SUPPORTED, readOnly + PROPAGATION_NOT_SUPPORTED, readOnly + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.security.AuthenticationService + + + AuthenticationService Service + + + + + + + + org.alfresco.service.cmr.repository.TemplateService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.repository.TemplateService + + + TemplateService Service + + + + + + + + org.alfresco.service.cmr.repository.ScriptService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.repository.ScriptService + + + ScriptService Service + + + + + + + + org.alfresco.service.cmr.model.FileFolderService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.readOnly} + ${server.transaction.mode.readOnly} + ${server.transaction.mode.readOnly} + ${server.transaction.mode.readOnly} + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.model.FileFolderService + + + FileFolderService Service + + + + + + + + + + + + + + org.alfresco.service.cmr.avm.AVMService + + + + + + + + + + + + + + + org.alfresco.service.cmr.avm.AVMService + + + AVM Service + + + + + + + + + + ${server.transaction.mode.readOnly} + ${server.transaction.mode.default} + ${server.transaction.mode.default} + ${server.transaction.mode.default} + ${server.transaction.mode.readOnly} + ${server.transaction.mode.readOnly} + ${server.transaction.mode.default} + + + + + + + + + + + + + + + + + + org.alfresco.service.cmr.avmsync.AVMSyncService + + + AVM Tree Synchronization Service + + + + + + + + + + ${server.transaction.mode.readOnly} + ${server.transaction.mode.default} + ${server.transaction.mode.default} + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.avmsync.AVMSyncService + + + + + + + + + + + + + + + + + org.alfresco.service.cmr.workflow.WorkflowService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.workflow.WorkflowService + + + Workflow Service + + + + + + + + + org.alfresco.service.cmr.audit.AuditService + + + + + + + + + + + + + + + + + + + + + + ${server.transaction.mode.default} + + + + + + + org.alfresco.service.cmr.audit.AuditService + + + Audit Service + + + + diff --git a/config/alfresco/public-services-security-context.xml b/config/alfresco/public-services-security-context.xml index fcf2b92d31..1ed94603a2 100644 --- a/config/alfresco/public-services-security-context.xml +++ b/config/alfresco/public-services-security-context.xml @@ -325,7 +325,7 @@ org.alfresco.service.cmr.repository.NodeService.getStores=AFTER_ACL_NODE.sys:base.Read org.alfresco.service.cmr.repository.NodeService.createStore=ACL_METHOD.ROLE_ADMINISTRATOR - org.alfresco.service.cmr.repository.NodeService.exists=ACL_NODE.0.sys:base.Read + org.alfresco.service.cmr.repository.NodeService.exists=ACL_ALLOW org.alfresco.service.cmr.repository.NodeService.getNodeStatus=ACL_NODE.0.sys:base.Read org.alfresco.service.cmr.repository.NodeService.getRootNode=ACL_NODE.0.sys:base.Read org.alfresco.service.cmr.repository.NodeService.createNode=ACL_NODE.0.sys:base.CreateChildren @@ -374,7 +374,7 @@ org.alfresco.service.cmr.model.FileFolderService.listFolders=ACL_NODE.0.sys:base.ReadChildren,AFTER_ACL_NODE.sys:base.Read org.alfresco.service.cmr.model.FileFolderService.search=ACL_NODE.0.sys:base.ReadChildren,AFTER_ACL_NODE.sys:base.Read org.alfresco.service.cmr.model.FileFolderService.searchSimple=ACL_NODE.0.sys:base.ReadChildren,AFTER_ACL_NODE.sys:base.Read - org.alfresco.service.cmr.model.FileFolderService.rename=ACL_PARENT.0.sys:base.CreateChildren,AFTER_ACL_NODE.sys:base.WriteProperties + org.alfresco.service.cmr.model.FileFolderService.rename=AFTER_ACL_NODE.sys:base.WriteProperties org.alfresco.service.cmr.model.FileFolderService.move=ACL_NODE.0.sys:base.DeleteNode,ACL_NODE.1.sys:base.CreateChildren org.alfresco.service.cmr.model.FileFolderService.copy=ACL_NODE.0.sys:base.Read,ACL_NODE.1.sys:base.CreateChildren org.alfresco.service.cmr.model.FileFolderService.create=ACL_NODE.0.sys:base.CreateChildren diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties index bfa073e697..af47e22408 100644 --- a/config/alfresco/repository.properties +++ b/config/alfresco/repository.properties @@ -1,138 +1,137 @@ -# 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 - +# 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 + +# 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/rule-services-context.xml b/config/alfresco/rule-services-context.xml index 79955d57a9..d5697b927f 100644 --- a/config/alfresco/rule-services-context.xml +++ b/config/alfresco/rule-services-context.xml @@ -21,6 +21,9 @@ + + + false diff --git a/config/alfresco/script-services-context.xml b/config/alfresco/script-services-context.xml index fbbd6777a0..66e51cc9eb 100644 --- a/config/alfresco/script-services-context.xml +++ b/config/alfresco/script-services-context.xml @@ -2,9 +2,38 @@ + + + + + + + + + + + logger + + + + + + utils + + + + + + actions + + + + + + diff --git a/config/alfresco/templates/content/examples/show_audit.ftl b/config/alfresco/templates/content/examples/show_audit.ftl new file mode 100644 index 0000000000..d439d7c9ee --- /dev/null +++ b/config/alfresco/templates/content/examples/show_audit.ftl @@ -0,0 +1,173 @@ + <#-- Shows some general audit info about the current document --> + <#if document?exists> +

Current Docuement Audit Info

+ Name: ${document.name}
+ + + + + + + + + + + + + + + + + + + <#list document.auditTrail as t> + + + + <#if t.auditService?exists> + + <#else> + + + <#if t.auditMethod?exists> + + <#else> + + + + <#if t.fail?exists> + + <#else> + + + <#if t.message?exists> + + <#else> + + + <#if t.methodArgumentsAsStrings[0]?exists> + + <#else> + + + <#if t.methodArgumentsAsStrings[1]?exists> + + <#else> + + + <#if t.methodArgumentsAsStrings[2]?exists> + + <#else> + + + <#if t.methodArgumentsAsStrings[3]?exists> + + <#else> + + + <#if t.methodArgumentsAsStrings[4]?exists> + + <#else> + + + <#if t.returnObjectAsString?exists> + + <#else> + + + <#if t.throwableAsString?exists> + + <#else> + + + + + +
User NameApplicationServiceMethodTimestampFailedMessageArg 1Arg 2Arg 3Arg 4Arg 5ReturnThowableTX
${t.userIdentifier}${t.auditApplication}${t.auditService} ${t.auditMethod} ${t.date}${t.fail?string("FAILED", "OK")} ${t.message} ${t.methodArgumentsAsStrings[0]} ${t.methodArgumentsAsStrings[1]} ${t.methodArgumentsAsStrings[2]} ${t.methodArgumentsAsStrings[3]} ${t.methodArgumentsAsStrings[4]} ${t.returnObjectAsString} ${t.throwableAsString} ${t.txId}
+ <#elseif space?exists> +

Current Space Audit Info:

+ Name: ${space.name}
+ + + + + + + + + + + + + + + + + + + + <#list space.auditTrail as t> + + + + <#if t.auditService?exists> + + <#else> + + + <#if t.auditMethod?exists> + + <#else> + + + + <#if t.fail?exists> + + <#else> + + + <#if t.message?exists> + + <#else> + + + <#if t.methodArgumentsAsStrings[0]?exists> + + <#else> + + + <#if t.methodArgumentsAsStrings[1]?exists> + + <#else> + + + <#if t.methodArgumentsAsStrings[2]?exists> + + <#else> + + + <#if t.methodArgumentsAsStrings[3]?exists> + + <#else> + + + <#if t.methodArgumentsAsStrings[4]?exists> + + <#else> + + + <#if t.returnObjectAsString?exists> + + <#else> + + + <#if t.throwableAsString?exists> + + <#else> + + + + + +
User NameApplicationServiceMethodTimestampFailedMessageArg 1Arg 2Arg 3Arg 4Arg 5ReturnThowableTX
${t.userIdentifier}${t.auditApplication}${t.auditService} ${t.auditMethod} ${t.date}${t.fail?string("FAILED", "OK")} ${t.message} ${t.methodArgumentsAsStrings[0]} ${t.methodArgumentsAsStrings[1]} ${t.methodArgumentsAsStrings[2]} ${t.methodArgumentsAsStrings[3]} ${t.methodArgumentsAsStrings[4]} ${t.returnObjectAsString} ${t.throwableAsString} ${t.txId}
+ \ No newline at end of file diff --git a/config/alfresco/templates/content_template_examples.xml b/config/alfresco/templates/content_template_examples.xml index 85ac61c026..c5947af0cb 100644 --- a/config/alfresco/templates/content_template_examples.xml +++ b/config/alfresco/templates/content_template_examples.xml @@ -126,17 +126,17 @@ - + true - Displays the current state of records in a file plan space or a space containing a file plan. - contentUrl=classpath:alfresco/templates/content/examples/records_report.ftl|mimetype=text/plain|size=6134|encoding=UTF-8 - records_report.ftl - records_report.ftl + Displays the audit trail for an object. + contentUrl=classpath:alfresco/templates/content/examples/show_audit.ftl|mimetype=text/plain|size=6134|encoding=UTF-8 + show_audit.ftl + show_audit.ftl diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties index 681bec09e2..bbaa2c9aa9 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=RC1 +version.label= # Edition label diff --git a/config/alfresco/workflow-context.xml b/config/alfresco/workflow-context.xml index 468f5d350a..ae0f4a3ece 100644 --- a/config/alfresco/workflow-context.xml +++ b/config/alfresco/workflow-context.xml @@ -23,26 +23,33 @@ + + + + + + + + + + + alfresco.messages.workflow-interpreter-help + + + + - - true - - - - - - - - - - + true + + + @@ -73,7 +80,7 @@ - + diff --git a/source/cpp/CAlfrescoApp/source/alfresco/Alfresco.cpp b/source/cpp/CAlfrescoApp/source/alfresco/Alfresco.cpp index 31f08bcf3e..b35d4e6922 100644 --- a/source/cpp/CAlfrescoApp/source/alfresco/Alfresco.cpp +++ b/source/cpp/CAlfrescoApp/source/alfresco/Alfresco.cpp @@ -309,7 +309,7 @@ DesktopResponse AlfrescoInterface::runAction(AlfrescoActionInfo& action, Desktop // Build the run action I/O control request DataBuffer reqbuf( 1024); - DataBuffer respbuf( 256); + DataBuffer respbuf( 4096); reqbuf.putFixedString( IOSignature, IOSignatureLen); reqbuf.putString( action.getName()); diff --git a/source/java/org/alfresco/filesys/CIFSServer.java b/source/java/org/alfresco/filesys/CIFSServer.java index b62f92fff4..34fa3fe64a 100644 --- a/source/java/org/alfresco/filesys/CIFSServer.java +++ b/source/java/org/alfresco/filesys/CIFSServer.java @@ -26,12 +26,11 @@ import org.alfresco.filesys.netbios.server.NetBIOSNameServer; import org.alfresco.filesys.server.NetworkServer; import org.alfresco.filesys.server.config.ServerConfiguration; import org.alfresco.filesys.smb.server.SMBServer; +import org.alfresco.util.AbstractLifecycleBean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.support.ClassPathXmlApplicationContext; /** @@ -41,7 +40,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; * * @author GKSpencer */ -public class CIFSServer implements ApplicationListener +public class CIFSServer extends AbstractLifecycleBean { private static final Log logger = LogFactory.getLog("org.alfresco.smb.server"); @@ -81,29 +80,6 @@ public class CIFSServer implements ApplicationListener return (filesysConfig != null && filesysConfig.isSMBServerEnabled()); } - /* - * (non-Javadoc) - * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) - */ - public void onApplicationEvent(ApplicationEvent event) - { - if (event instanceof ContextRefreshedEvent) - { - try - { - startServer(); - } - catch (SocketException e) - { - throw new AlfrescoRuntimeException("Failed to start CIFS server", e); - } - catch (IOException e) - { - throw new AlfrescoRuntimeException("Failed to start CIFS server", e); - } - } - } - /** * Start the CIFS server components * @@ -264,5 +240,27 @@ public class CIFSServer implements ApplicationListener System.exit(1); } + @Override + protected void onBootstrap(ApplicationEvent event) + { + try + { + startServer(); + } + catch (SocketException e) + { + throw new AlfrescoRuntimeException("Failed to start CIFS server", e); + } + catch (IOException e) + { + throw new AlfrescoRuntimeException("Failed to start CIFS server", e); + } + } + + @Override + protected void onShutdown(ApplicationEvent event) + { + stopServer(); + } } diff --git a/source/java/org/alfresco/filesys/FTPServer.java b/source/java/org/alfresco/filesys/FTPServer.java index f77cb0b67d..270b209373 100644 --- a/source/java/org/alfresco/filesys/FTPServer.java +++ b/source/java/org/alfresco/filesys/FTPServer.java @@ -24,11 +24,11 @@ import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.filesys.ftp.FTPNetworkServer; import org.alfresco.filesys.server.NetworkServer; import org.alfresco.filesys.server.config.ServerConfiguration; +import org.alfresco.util.AbstractLifecycleBean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.support.ClassPathXmlApplicationContext; @@ -39,7 +39,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; * * @author GKSpencer */ -public class FTPServer implements ApplicationListener +public class FTPServer extends AbstractLifecycleBean { private static final Log logger = LogFactory.getLog("org.alfresco.ftp.server"); @@ -79,29 +79,6 @@ public class FTPServer implements ApplicationListener return (filesysConfig != null && filesysConfig.isFTPServerEnabled()); } - /* - * (non-Javadoc) - * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) - */ - public void onApplicationEvent(ApplicationEvent event) - { - if (event instanceof ContextRefreshedEvent) - { - try - { - startServer(); - } - catch (SocketException e) - { - throw new AlfrescoRuntimeException("Failed to start FTP server", e); - } - catch (IOException e) - { - throw new AlfrescoRuntimeException("Failed to start FTP server", e); - } - } - } - /** * Start the FTP server components * @@ -251,4 +228,28 @@ public class FTPServer implements ApplicationListener } System.exit(1); } + + @Override + protected void onBootstrap(ApplicationEvent event) + { + try + { + startServer(); + } + catch (SocketException e) + { + throw new AlfrescoRuntimeException("Failed to start FTP server", e); + } + catch (IOException e) + { + throw new AlfrescoRuntimeException("Failed to start FTP server", e); + } + } + + @Override + protected void onShutdown(ApplicationEvent event) + { + stopServer(); + } + } diff --git a/source/java/org/alfresco/filesys/ftp/FTPSrvSession.java b/source/java/org/alfresco/filesys/ftp/FTPSrvSession.java index 16a9daa11c..afd55c32a8 100644 --- a/source/java/org/alfresco/filesys/ftp/FTPSrvSession.java +++ b/source/java/org/alfresco/filesys/ftp/FTPSrvSession.java @@ -852,7 +852,7 @@ public class FTPSrvSession extends SrvSession implements Runnable // DEBUG if ( logger.isDebugEnabled()) - logger.debug("Logon failed", ex); + logger.debug("Logon failed for user " + cInfo.getUserName()); } // Check if the logon was successful diff --git a/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java index 817e7b361b..f26a8bfdd2 100644 --- a/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java +++ b/source/java/org/alfresco/filesys/server/auth/AlfrescoAuthenticator.java @@ -17,10 +17,17 @@ package org.alfresco.filesys.server.auth; import java.security.NoSuchAlgorithmException; +import net.sf.acegisecurity.Authentication; import org.alfresco.filesys.server.SrvSession; +import org.alfresco.filesys.server.auth.AuthContext; +import org.alfresco.filesys.server.auth.CifsAuthenticator; +import org.alfresco.filesys.server.auth.ClientInfo; +import org.alfresco.filesys.server.auth.NTLanManAuthContext; import org.alfresco.filesys.smb.server.SMBSrvSession; +import org.alfresco.filesys.util.HexDump; import org.alfresco.repo.security.authentication.NTLMMode; +import org.alfresco.repo.security.authentication.ntlm.NTLMPassthruToken; /** * Alfresco Authenticator Class @@ -88,10 +95,7 @@ public class AlfrescoAuthenticator extends CifsAuthenticator { // Use the existing authentication token - if ( client.isGuest()) - m_authComponent.setGuestUserAsCurrentUser(); - else - m_authComponent.setCurrentUser(mapUserNameToPerson(client.getUserName())); + m_authComponent.setCurrentUser(client.getUserName()); // Debug @@ -107,7 +111,7 @@ public class AlfrescoAuthenticator extends CifsAuthenticator int authSts = AUTH_DISALLOW; - if ( client.isGuest() || client.getUserName().equalsIgnoreCase(GUEST_USERNAME)) + if ( client.isGuest() || client.getUserName().equalsIgnoreCase(getGuestUserName())) { // Check if guest logons are allowed @@ -140,7 +144,13 @@ public class AlfrescoAuthenticator extends CifsAuthenticator authSts = doMD4UserAuthentication(client, sess, alg); } - + else + { + // Perform passthru authentication password check + + authSts = doPassthruUserAuthentication(client, sess, alg); + } + // Check if the logon status indicates a guest logon if ( authSts == AUTH_GUEST) @@ -172,6 +182,64 @@ public class AlfrescoAuthenticator extends CifsAuthenticator return authSts; } + /** + * Return an authentication context for the new session + * + * @return AuthContext + */ + public AuthContext getAuthContext( SMBSrvSession sess) + { + // Check if the client is already authenticated, and it is not a null logon + + AuthContext authCtx = null; + + if ( sess.hasAuthenticationContext() && sess.hasAuthenticationToken() && + sess.getClientInformation().getLogonType() != ClientInfo.LogonNull) + { + // Return the previous challenge, user is already authenticated + + authCtx = (NTLanManAuthContext) sess.getAuthenticationContext(); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Re-using existing challenge, already authenticated"); + } + else if ( m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER) + { + // Create a new authentication context for the session + + authCtx = new NTLanManAuthContext(); + sess.setAuthenticationContext( authCtx); + } + else + { + // Create an authentication token for the session + + NTLMPassthruToken authToken = new NTLMPassthruToken(); + + // Run the first stage of the passthru authentication to get the challenge + + m_authComponent.authenticate( authToken); + + // Save the authentication token for the second stage of the authentication + + sess.setAuthenticationToken(authToken); + + // Get the challenge from the token + + if ( authToken.getChallenge() != null) + { + authCtx = new NTLanManAuthContext( authToken.getChallenge().getBytes()); + sess.setAuthenticationContext( authCtx); + } + } + + // Return the authentication context + + return authCtx; + } + /** * Perform MD4 user authentication * @@ -217,6 +285,20 @@ public class AlfrescoAuthenticator extends CifsAuthenticator // Validate the password byte[] clientHash = client.getPassword(); + if ( clientHash == null || clientHash.length != 24) + { + // Use the secondary password hash from the client + + clientHash = client.getANSIPassword(); + + // DEBUG + + if ( logger.isDebugEnabled()) + { + logger.debug( "Using secondary password hash - " + HexDump.hexString(clientHash)); + logger.debug( " Local hash - " + HexDump.hexString( localHash)); + } + } if ( clientHash == null || clientHash.length != localHash.length) return CifsAuthenticator.AUTH_BADPASSWORD; @@ -229,7 +311,7 @@ public class AlfrescoAuthenticator extends CifsAuthenticator // Set the current user to be authenticated, save the authentication token - client.setAuthenticationToken( m_authComponent.setCurrentUser(mapUserNameToPerson(client.getUserName()))); + client.setAuthenticationToken( m_authComponent.setCurrentUser(client.getUserName())); // Get the users home folder node, if available @@ -259,4 +341,101 @@ public class AlfrescoAuthenticator extends CifsAuthenticator return allowGuest() ? CifsAuthenticator.AUTH_GUEST : CifsAuthenticator.AUTH_DISALLOW; } + + /** + * Perform passthru user authentication + * + * @param client Client information + * @param sess Server session + * @param alg Encryption algorithm + * @return int + */ + private final int doPassthruUserAuthentication(ClientInfo client, SrvSession sess, int alg) + { + // Get the authentication token for the session + + NTLMPassthruToken authToken = (NTLMPassthruToken) sess.getAuthenticationToken(); + + if ( authToken == null) + return CifsAuthenticator.AUTH_DISALLOW; + + // Get the appropriate hashed password for the algorithm + + int authSts = CifsAuthenticator.AUTH_DISALLOW; + byte[] hashedPassword = null; + + if ( alg == NTLM1) + hashedPassword = client.getPassword(); + else if ( alg == LANMAN) + hashedPassword = client.getANSIPassword(); + else + { + // Invalid/unsupported algorithm specified + + return CifsAuthenticator.AUTH_DISALLOW; + } + + // Set the username and hashed password in the authentication token + + authToken.setUserAndPassword( client.getUserName(), hashedPassword, alg); + + // Authenticate the user + + Authentication genAuthToken = null; + + try + { + // Run the second stage of the passthru authentication + + genAuthToken = m_authComponent.authenticate( authToken); + + // Check if the user has been logged on as a guest + + if (authToken.isGuestLogon()) + { + + // Check if the local server allows guest access + + if (allowGuest() == true) + { + + // Allow the user access as a guest + + authSts = CifsAuthenticator.AUTH_GUEST; + } + } + else + { + + // Allow the user full access to the server + + authSts = CifsAuthenticator.AUTH_ALLOW; + } + + // Set the current user to be authenticated, save the authentication token + + client.setAuthenticationToken( genAuthToken); + + // Get the users home folder node, if available + + getHomeFolderForUser( client); + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Auth token " + genAuthToken); + } + catch ( Exception ex) + { + logger.error("Error during passthru authentication", ex); + } + + // Clear the authentication token + + sess.setAuthenticationToken(null); + + // Return the authentication status + + return authSts; + } } \ No newline at end of file diff --git a/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java index 7815a7cf8f..3effae1145 100644 --- a/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java +++ b/source/java/org/alfresco/filesys/server/auth/CifsAuthenticator.java @@ -470,7 +470,7 @@ public abstract class CifsAuthenticator // Store the client maximum buffer size, maximum multiplexed requests count and client // capability flags - sess.setClientMaximumBufferSize(maxBufSize); + sess.setClientMaximumBufferSize(maxBufSize != 0 ? maxBufSize : SMBSrvSession.DefaultBufferSize); sess.setClientMaximumMultiplex(maxMpx); sess.setClientCapabilities(capabs); diff --git a/source/java/org/alfresco/filesys/server/auth/ClientInfo.java b/source/java/org/alfresco/filesys/server/auth/ClientInfo.java index 56eec14aeb..421c840583 100644 --- a/source/java/org/alfresco/filesys/server/auth/ClientInfo.java +++ b/source/java/org/alfresco/filesys/server/auth/ClientInfo.java @@ -71,6 +71,10 @@ public class ClientInfo private Authentication m_authToken; + // Authentication ticket, used for web access without having to re-authenticate + + private String m_authTicket; + // Home folder node private NodeRef m_homeNode; @@ -286,6 +290,26 @@ public class ClientInfo { return m_authToken; } + + /** + * Check if the client has an authentication ticket + * + * @return boolean + */ + public final boolean hasAuthenticationTicket() + { + return m_authTicket != null ? true : false; + } + + /** + * Return the authentication ticket + * + * @return String + */ + public final String getAuthenticationTicket() + { + return m_authTicket; + } /** * Check if the client has a home folder node @@ -409,6 +433,16 @@ public class ClientInfo { m_authToken = token; } + + /** + * Set the authentication ticket + * + * @param ticket String + */ + public final void setAuthenticationTicket(String ticket) + { + m_authTicket = ticket; + } /** * Set the home folder node @@ -448,6 +482,12 @@ public class ClientInfo str.append(",token="); str.append(getAuthenticationToken()); } + + if ( hasAuthenticationTicket()) + { + str.append(",ticket="); + str.append(getAuthenticationTicket()); + } if (isGuest()) str.append(",Guest"); diff --git a/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java index c5647faff4..4f034ee1c7 100644 --- a/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java +++ b/source/java/org/alfresco/filesys/server/auth/EnterpriseCifsAuthenticator.java @@ -584,7 +584,7 @@ public class EnterpriseCifsAuthenticator extends CifsAuthenticator implements Ca // Store the client maximum buffer size, maximum multiplexed requests count and client capability flags - sess.setClientMaximumBufferSize(maxBufSize); + sess.setClientMaximumBufferSize(maxBufSize != 0 ? maxBufSize : SMBSrvSession.DefaultBufferSize); sess.setClientMaximumMultiplex(maxMpx); sess.setClientCapabilities(capabs); diff --git a/source/java/org/alfresco/filesys/server/auth/ntlm/AlfrescoAuthenticator.java b/source/java/org/alfresco/filesys/server/auth/ntlm/AlfrescoAuthenticator.java deleted file mode 100644 index 5b77d4171d..0000000000 --- a/source/java/org/alfresco/filesys/server/auth/ntlm/AlfrescoAuthenticator.java +++ /dev/null @@ -1,427 +0,0 @@ -/* - * 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.filesys.server.auth.ntlm; - -import java.security.NoSuchAlgorithmException; -import net.sf.acegisecurity.Authentication; - -import org.alfresco.filesys.server.SrvSession; -import org.alfresco.filesys.server.auth.AuthContext; -import org.alfresco.filesys.server.auth.CifsAuthenticator; -import org.alfresco.filesys.server.auth.ClientInfo; -import org.alfresco.filesys.server.auth.NTLanManAuthContext; -import org.alfresco.filesys.smb.server.SMBSrvSession; -import org.alfresco.filesys.util.DataPacker; -import org.alfresco.repo.security.authentication.NTLMMode; -import org.alfresco.repo.security.authentication.ntlm.NTLMPassthruToken; - -/** - * Alfresco Authenticator Class - * - *

The Alfresco authenticator implementation enables user level security mode using the Alfresco authentication - * component. - * - *

Note: Switching off encrypted password support will cause later NT4 service pack releases and - * Win2000 to refuse to connect to the server without a registry update on the client. - * - * @author GKSpencer - */ -public class AlfrescoAuthenticator extends CifsAuthenticator -{ - /** - * Default Constructor - * - *

Default to user mode security with encrypted password support. - */ - public AlfrescoAuthenticator() - { - } - - /** - * Validate that the authentication component supports the required mode - * - * @return boolean - */ - protected boolean validateAuthenticationMode() - { - // Make sure the authentication component supports MD4 hashed passwords or passthru mode - - if ( m_authComponent.getNTLMMode() != NTLMMode.MD4_PROVIDER && - m_authComponent.getNTLMMode() != NTLMMode.PASS_THROUGH) - return false; - return true; - } - - /** - * Authenticate a user - * - * @param client Client information - * @param sess Server session - * @param alg Encryption algorithm - */ - public int authenticateUser(ClientInfo client, SrvSession sess, int alg) - { - // Check if this is an SMB/CIFS null session logon. - // - // The null session will only be allowed to connect to the IPC$ named pipe share. - - if (client.isNullSession() && sess instanceof SMBSrvSession) - { - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("Null CIFS logon allowed"); - - return CifsAuthenticator.AUTH_ALLOW; - } - - // Check if the client is already authenticated, and it is not a null logon - - if ( client.getAuthenticationToken() != null && client.getLogonType() != ClientInfo.LogonNull) - { - // Use the existing authentication token - - m_authComponent.setCurrentUser(client.getUserName()); - - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("Re-using existing authentication token"); - - // Return the authentication status - - return client.getLogonType() != ClientInfo.LogonGuest ? AUTH_ALLOW : AUTH_GUEST; - } - - // Check if this is a guest logon - - int authSts = AUTH_DISALLOW; - - if ( client.isGuest() || client.getUserName().equalsIgnoreCase(getGuestUserName())) - { - // Check if guest logons are allowed - - if ( allowGuest() == false) - return AUTH_DISALLOW; - - // Get a guest authentication token - - doGuestLogon( client, sess); - - // Indicate logged on as guest - - authSts = AUTH_GUEST; - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Authenticated user " + client.getUserName() + " sts=" + getStatusAsString(authSts)); - - // Return the guest status - - return authSts; - } - - // Check if MD4 or passthru mode is configured - - else if ( m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER) - { - // Perform local MD4 password check - - authSts = doMD4UserAuthentication(client, sess, alg); - } - else - { - // Perform passthru authentication password check - - authSts = doPassthruUserAuthentication(client, sess, alg); - } - - // Check if the logon status indicates a guest logon - - if ( authSts == AUTH_GUEST) - { - // Only allow the guest logon if user mapping is enabled - - if ( mapUnknownUserToGuest()) - { - // Logon as guest, setup the security context - - doGuestLogon( client, sess); - } - else - { - // Do not allow the guest logon - - authSts = AUTH_DISALLOW; - } - } - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Authenticated user " + client.getUserName() + " sts=" + getStatusAsString(authSts) + - " via " + (m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER ? "MD4" : "Passthru")); - - // Return the authentication status - - return authSts; - } - - /** - * Return an authentication context for the new session - * - * @return AuthContext - */ - public AuthContext getAuthContext( SMBSrvSession sess) - { - // Check if the client is already authenticated, and it is not a null logon - - AuthContext authCtx = null; - - if ( sess.hasAuthenticationContext() && sess.hasAuthenticationToken() && - sess.getClientInformation().getLogonType() != ClientInfo.LogonNull) - { - // Return the previous challenge, user is already authenticated - - authCtx = (NTLanManAuthContext) sess.getAuthenticationContext(); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Re-using existing challenge, already authenticated"); - } - else if ( m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER) - { - // Create a new authentication context for the session - - authCtx = new NTLanManAuthContext(); - sess.setAuthenticationContext( authCtx); - } - else - { - // Create an authentication token for the session - - NTLMPassthruToken authToken = new NTLMPassthruToken(); - - // Run the first stage of the passthru authentication to get the challenge - - m_authComponent.authenticate( authToken); - - // Save the authentication token for the second stage of the authentication - - sess.setAuthenticationToken(authToken); - - // Get the challenge from the token - - if ( authToken.getChallenge() != null) - { - authCtx = new NTLanManAuthContext( authToken.getChallenge().getBytes()); - sess.setAuthenticationContext( authCtx); - } - } - - // Return the authentication context - - return authCtx; - } - - /** - * Perform MD4 user authentication - * - * @param client Client information - * @param sess Server session - * @param alg Encryption algorithm - * @return int - */ - private final int doMD4UserAuthentication(ClientInfo client, SrvSession sess, int alg) - { - // Get the stored MD4 hashed password for the user, or null if the user does not exist - - String md4hash = m_authComponent.getMD4HashedPassword(client.getUserName()); - - if ( md4hash != null) - { - // Check if the client has supplied an NTLM hashed password, if not then do not allow access - - if ( client.getPassword() == null) - return CifsAuthenticator.AUTH_BADPASSWORD; - - try - { - // Generate the local encrypted password using the challenge that was sent to the client - - byte[] p21 = new byte[21]; - byte[] md4byts = m_md4Encoder.decodeHash(md4hash); - System.arraycopy(md4byts, 0, p21, 0, 16); - - // Get the challenge that was sent to the client - - NTLanManAuthContext authCtx = null; - - if ( sess.hasAuthenticationContext() && sess.getAuthenticationContext() instanceof NTLanManAuthContext) - authCtx = (NTLanManAuthContext) sess.getAuthenticationContext(); - else - return CifsAuthenticator.AUTH_DISALLOW; - - // Generate the local hash of the password using the same challenge - - byte[] localHash = getEncryptor().doNTLM1Encryption(p21, authCtx.getChallenge()); - - // Validate the password - - byte[] clientHash = client.getPassword(); - - if ( clientHash == null || clientHash.length != localHash.length) - return CifsAuthenticator.AUTH_BADPASSWORD; - - for ( int i = 0; i < clientHash.length; i++) - { - if ( clientHash[i] != localHash[i]) - return CifsAuthenticator.AUTH_BADPASSWORD; - } - - // Set the current user to be authenticated, save the authentication token - - client.setAuthenticationToken( m_authComponent.setCurrentUser(client.getUserName())); - - // Get the users home folder node, if available - - getHomeFolderForUser( client); - - // Passwords match, grant access - - return CifsAuthenticator.AUTH_ALLOW; - } - catch (NoSuchAlgorithmException ex) - { - } - - // Error during password check, do not allow access - - return CifsAuthenticator.AUTH_DISALLOW; - } - - // Check if this is an SMB/CIFS null session logon. - // - // The null session will only be allowed to connect to the IPC$ named pipe share. - - if (client.isNullSession() && sess instanceof SMBSrvSession) - return CifsAuthenticator.AUTH_ALLOW; - - // User does not exist, check if guest access is allowed - - return allowGuest() ? CifsAuthenticator.AUTH_GUEST : CifsAuthenticator.AUTH_DISALLOW; - } - - /** - * Perform passthru user authentication - * - * @param client Client information - * @param sess Server session - * @param alg Encryption algorithm - * @return int - */ - private final int doPassthruUserAuthentication(ClientInfo client, SrvSession sess, int alg) - { - // Get the authentication token for the session - - NTLMPassthruToken authToken = (NTLMPassthruToken) sess.getAuthenticationToken(); - - if ( authToken == null) - return CifsAuthenticator.AUTH_DISALLOW; - - // Get the appropriate hashed password for the algorithm - - int authSts = CifsAuthenticator.AUTH_DISALLOW; - byte[] hashedPassword = null; - - if ( alg == NTLM1) - hashedPassword = client.getPassword(); - else if ( alg == LANMAN) - hashedPassword = client.getANSIPassword(); - else - { - // Invalid/unsupported algorithm specified - - return CifsAuthenticator.AUTH_DISALLOW; - } - - // Set the username and hashed password in the authentication token - - authToken.setUserAndPassword( client.getUserName(), hashedPassword, alg); - - // Authenticate the user - - Authentication genAuthToken = null; - - try - { - // Run the second stage of the passthru authentication - - genAuthToken = m_authComponent.authenticate( authToken); - - // Check if the user has been logged on as a guest - - if (authToken.isGuestLogon()) - { - - // Check if the local server allows guest access - - if (allowGuest() == true) - { - - // Allow the user access as a guest - - authSts = CifsAuthenticator.AUTH_GUEST; - } - } - else - { - - // Allow the user full access to the server - - authSts = CifsAuthenticator.AUTH_ALLOW; - } - - // Set the current user to be authenticated, save the authentication token - - client.setAuthenticationToken( genAuthToken); - - // Get the users home folder node, if available - - getHomeFolderForUser( client); - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug("Auth token " + genAuthToken); - } - catch ( Exception ex) - { - logger.error("Error during passthru authentication", ex); - } - - // Clear the authentication token - - sess.setAuthenticationToken(null); - - // Return the authentication status - - return authSts; - } -} \ No newline at end of file diff --git a/source/java/org/alfresco/filesys/server/auth/ntlm/NTLMLogonDetails.java b/source/java/org/alfresco/filesys/server/auth/ntlm/NTLMLogonDetails.java index c5c8f7f314..4615408bd5 100644 --- a/source/java/org/alfresco/filesys/server/auth/ntlm/NTLMLogonDetails.java +++ b/source/java/org/alfresco/filesys/server/auth/ntlm/NTLMLogonDetails.java @@ -39,6 +39,10 @@ public class NTLMLogonDetails private String m_authSrvAddr; + // Date/time authentication was started + + private long m_createTime; + // Date/time the user was authenticated private long m_authTime; @@ -61,6 +65,7 @@ public class NTLMLogonDetails */ public NTLMLogonDetails() { + m_createTime = System.currentTimeMillis(); } /** @@ -74,6 +79,8 @@ public class NTLMLogonDetails */ public NTLMLogonDetails(String user, String wks, String domain, boolean guest, String authSrv) { + m_createTime = System.currentTimeMillis(); + setDetails(user, wks, domain, guest, authSrv); } @@ -117,6 +124,16 @@ public class NTLMLogonDetails return m_authSrvAddr; } + /** + * Return the date/time the authentication was started + * + * @return long + */ + public final long createdAt() + { + return m_createTime; + } + /** * Return the date/time the user was authenticated * diff --git a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java index 46c7e16839..a48040b950 100644 --- a/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java +++ b/source/java/org/alfresco/filesys/server/config/ServerConfiguration.java @@ -81,11 +81,10 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.AbstractLifecycleBean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; /** *

@@ -93,7 +92,7 @@ import org.springframework.context.event.ContextRefreshedEvent; * * @author Gary K. Spencer */ -public class ServerConfiguration implements ApplicationListener +public class ServerConfiguration extends AbstractLifecycleBean { // Debug logging @@ -425,18 +424,6 @@ public class ServerConfiguration implements ApplicationListener return initialised; } - /* - * (non-Javadoc) - * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) - */ - public void onApplicationEvent(ApplicationEvent event) - { - if (event instanceof ContextRefreshedEvent) - { - init(); - } - } - /** * Initialize the configuration using the configuration service */ @@ -1791,9 +1778,7 @@ public class ServerConfiguration implements ApplicationListener // Load the Alfresco authenticator dynamically - auth = loadAuthenticatorClass("org.alfresco.filesys.server.auth.ntlm.AlfrescoAuthenticator"); - if ( auth == null) - auth = loadAuthenticatorClass("org.alfresco.filesys.server.auth.AlfrescoAuthenticator"); + auth = loadAuthenticatorClass("org.alfresco.filesys.server.auth.AlfrescoAuthenticator"); if ( auth == null) throw new AlfrescoRuntimeException("Failed to load Alfresco authenticator"); @@ -3359,4 +3344,17 @@ public class ServerConfiguration implements ApplicationListener return srvAuth; } + + @Override + protected void onBootstrap(ApplicationEvent event) + { + init(); + } + + @Override + protected void onShutdown(ApplicationEvent event) + { + // NO-OP + } + } \ No newline at end of file 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 049e5d4e7d..7ce6b8705f 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/ContentDiskDriver.java @@ -18,6 +18,7 @@ package org.alfresco.filesys.smb.server.repo; import java.io.FileNotFoundException; import java.io.IOException; +import java.net.InetAddress; import java.util.List; import javax.transaction.UserTransaction; @@ -58,7 +59,6 @@ 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; import org.alfresco.service.cmr.repository.NodeRef; @@ -66,6 +66,7 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.transaction.TransactionService; @@ -91,6 +92,10 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface private static final String KEY_ROOT_PATH = "rootPath"; private static final String KEY_RELATIVE_PATH = "relativePath"; + // Token name to substitute current servers DNS name or TCP/IP address into the webapp URL + + private static final String TokenLocalName = "${localname}"; + // Services and helpers private CifsHelper cifsHelper; @@ -102,6 +107,7 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface private PermissionService permissionService; private AuthenticationComponent authComponent; + private AuthenticationService authService; // Service registry for desktop actions @@ -127,6 +133,16 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface return this.cifsHelper; } + /** + * Return the authentication service + * + * @return AuthenticationService + */ + public final AuthenticationService getAuthenticationService() + { + return authService; + } + /** * Return the transaction service * @@ -185,7 +201,7 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface { return this.serviceRegistry; } - + /** * @param contentService the content service */ @@ -255,6 +271,16 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface { this.authComponent = authComponent; } + + /** + * Set the authentication service + * + * @param authService AuthenticationService + */ + public void setAuthenticationService(AuthenticationService authService) + { + this.authService = authService; + } /** * Parse and validate the parameter string and create a device context object for this instance @@ -418,7 +444,39 @@ public class ContentDiskDriver implements DiskInterface, IOCtlInterface if ( pseudoName.getValue().endsWith(".url") == false) throw new DeviceContextException("URL link file must end with .url, " + pseudoName.getValue()); - // Set the URL link file name and web path + // Check if the URL path name contains the local name token + + int pos = path.indexOf(TokenLocalName); + if (pos != -1) + { + + // Get the local server name + + String srvName = "localhost"; + + try + { + srvName = InetAddress.getLocalHost().getHostName(); + } + catch ( Exception ex) + { + } + + // Rebuild the host name substituting the token with the local server name + + StringBuilder hostStr = new StringBuilder(); + + hostStr.append( path.substring(0, pos)); + hostStr.append(srvName); + + pos += TokenLocalName.length(); + if (pos < path.length()) + hostStr.append( path.substring(pos)); + + path = hostStr.toString(); + } + + // Set the URL link file name and web path context.setURLFileName( pseudoName.getValue()); context.setURLPrefix( path); diff --git a/source/java/org/alfresco/filesys/smb/server/repo/ContentIOControlHandler.java b/source/java/org/alfresco/filesys/smb/server/repo/ContentIOControlHandler.java index d9cb60e028..f83cad068a 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/ContentIOControlHandler.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/ContentIOControlHandler.java @@ -19,6 +19,7 @@ package org.alfresco.filesys.smb.server.repo; import java.io.FileNotFoundException; import org.alfresco.filesys.server.SrvSession; +import org.alfresco.filesys.server.auth.ClientInfo; import org.alfresco.filesys.server.filesys.IOControlNotImplementedException; import org.alfresco.filesys.server.filesys.NetworkFile; import org.alfresco.filesys.server.filesys.TreeConnection; @@ -30,10 +31,12 @@ import org.alfresco.filesys.smb.server.repo.ContentDiskDriver; import org.alfresco.filesys.smb.server.repo.IOControlHandler; import org.alfresco.filesys.util.DataBuffer; import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationException; import org.alfresco.service.cmr.lock.LockType; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -85,6 +88,16 @@ public class ContentIOControlHandler implements IOControlHandler return contentDriver.getCifsHelper(); } + /** + * Return the authentication service + * + * @return AuthenticationService + */ + public final AuthenticationService getAuthenticationService() + { + return contentDriver.getAuthenticationService(); + } + /** * Return the transaction service * @@ -511,6 +524,11 @@ public class ContentIOControlHandler implements IOControlHandler // Start a transaction sess.beginTransaction( getTransactionService(), true); + + // Get an authentication ticket for the client, or validate the existing ticket. The ticket can be used when + // generating URLs for the client-side application so that the user does not have to re-authenticate + + getTicketForClient( sess); // Get the list of targets for the action @@ -624,4 +642,65 @@ public class ContentIOControlHandler implements IOControlHandler return respBuf; } + + /** + * Get, or validate, an authentication ticket for the client + * + * @param sess SrvSession + */ + private final void getTicketForClient(SrvSession sess) + { + // Get the client information and check if there is a ticket allocated + + ClientInfo cInfo = sess.getClientInformation(); + if ( cInfo == null) + return; + + boolean needTicket = true; + + if ( cInfo.hasAuthenticationTicket()) + { + // Validate the existing ticket, it may have expired + + try + { + // Validate the existing ticket + + getAuthenticationService().validate( cInfo.getAuthenticationTicket()); + needTicket = false; + } + catch ( AuthenticationException ex) + { + // Invalidate the current ticket + + try + { + getAuthenticationService().invalidateTicket( cInfo.getAuthenticationTicket()); + cInfo.setAuthenticationTicket( null); + } + catch (Exception ex2) + { + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Error during invalidate ticket", ex2); + } + + // DEBUG + + if ( logger.isDebugEnabled()) + logger.debug("Auth ticket expired or invalid"); + } + } + + // Check if a ticket needs to be allocated + + if ( needTicket == true) + { + // Allocate a new ticket and store in the client information for this session + + String ticket = getAuthenticationService().getCurrentTicket(); + cInfo.setAuthenticationTicket( ticket); + } + } } 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 1bcc759564..e5ca0a28e7 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/DesktopAction.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/DesktopAction.java @@ -19,10 +19,12 @@ package org.alfresco.filesys.smb.server.repo; import java.io.File; import java.io.UnsupportedEncodingException; +import java.net.InetAddress; import java.net.URL; import java.net.URLDecoder; import org.alfresco.config.ConfigElement; +import org.alfresco.error.AlfrescoRuntimeException; 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; @@ -88,7 +90,11 @@ public abstract class DesktopAction { public static final int StsLaunchURL = 7; public static final int StsCommandLine = 8; - // Action name + // Token name to substitute current servers DNS name or TCP/IP address into the webapp URL + + private static final String TokenLocalName = "${localname}"; + + // Action name private String m_name; @@ -109,6 +115,10 @@ public abstract class DesktopAction { private ContentDiskDriver m_contentDriver; private ContentContext m_contentContext; + // Webapp URL + + private String m_webappURL; + // Debug enable flag private boolean m_debug; @@ -254,6 +264,26 @@ public abstract class DesktopAction { return m_debug; } + /** + * Check if the webapp URL is set + * + * @return boolean + */ + public final boolean hasWebappURL() + { + return m_webappURL != null ? true : false; + } + + /** + * Return the webapp URL + * + * @return String + */ + public final String getWebappURL() + { + return m_webappURL; + } + /** * Initialize the desktop action * @@ -348,7 +378,50 @@ public abstract class DesktopAction { if ( findConfigElement("noConfirm", global, config) != null && hasPreProcessAction(PreConfirmAction)) setPreProcessActions(getPreProcessActions() - PreConfirmAction); + + // Check if the webapp URL has been specified + + ConfigElement webURL = findConfigElement("webpath", global, config); + if ( webURL != null) + { + // Check if the path name contains the local name token + + String webPath = webURL.getValue(); + if ( webPath.endsWith("/") == false) + webPath = webPath + "/"; + int pos = webPath.indexOf(TokenLocalName); + if (pos != -1) + { + + // Get the local server name + + String srvName = "localhost"; + + try + { + srvName = InetAddress.getLocalHost().getHostName(); + } + catch ( Exception ex) + { + } + + // Rebuild the host name substituting the token with the local server name + + StringBuilder hostStr = new StringBuilder(); + + hostStr.append(webPath.substring(0, pos)); + hostStr.append(srvName); + + pos += TokenLocalName.length(); + if (pos < webPath.length()) + hostStr.append(webPath.substring(pos)); + + webPath = hostStr.toString(); + setWebappURL( webPath); + } + } + // Check if debug output is enabled for the action ConfigElement debug = findConfigElement("debug", global, config); @@ -511,6 +584,16 @@ public abstract class DesktopAction { m_debug = ena; } + /** + * Set the webapp URL + * + * @param urlStr String + */ + public final void setWebappURL(String urlStr) + { + m_webappURL = urlStr; + } + /** * Equality check * diff --git a/source/java/org/alfresco/filesys/smb/server/repo/DesktopParams.java b/source/java/org/alfresco/filesys/smb/server/repo/DesktopParams.java index 1a2e294135..6a45926dc2 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/DesktopParams.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/DesktopParams.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; import org.alfresco.filesys.server.SrvSession; +import org.alfresco.filesys.server.auth.ClientInfo; import org.alfresco.filesys.server.filesys.NetworkFile; import org.alfresco.service.cmr.repository.NodeRef; @@ -88,6 +89,19 @@ public class DesktopParams { { return m_session; } + + /** + * Return the authentication ticket for the user/session + * + * @return String + */ + public final String getTicket() + { + ClientInfo cInfo = m_session.getClientInformation(); + if ( cInfo != null) + return cInfo.getAuthenticationTicket(); + return null; + } /** * Return the working directory node 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 index 303ff36272..1a361e62f2 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/desk/JavaScriptDesktopAction.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/desk/JavaScriptDesktopAction.java @@ -284,6 +284,11 @@ public class JavaScriptDesktopAction extends DesktopAction { model.put("deskParams", params); model.put("out", System.out); + // Add the webapp URL, if valid + + if ( hasWebappURL()) + model.put("webURL", getWebappURL()); + // Start a transaction params.getSession().beginTransaction(getTransactionService(), false); diff --git a/source/java/org/alfresco/filesys/smb/server/repo/desk/URLDesktopAction.java b/source/java/org/alfresco/filesys/smb/server/repo/desk/URLDesktopAction.java index ca63252963..2a91523ae7 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/desk/URLDesktopAction.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/desk/URLDesktopAction.java @@ -16,6 +16,9 @@ */ package org.alfresco.filesys.smb.server.repo.desk; +import java.net.InetAddress; +import java.net.UnknownHostException; + import org.alfresco.filesys.smb.server.repo.DesktopAction; import org.alfresco.filesys.smb.server.repo.DesktopParams; import org.alfresco.filesys.smb.server.repo.DesktopResponse; @@ -45,8 +48,29 @@ public class URLDesktopAction extends DesktopAction { @Override public DesktopResponse runAction(DesktopParams params) { - // Return a URL in the status message + // Get the local IP address - return new DesktopResponse(StsLaunchURL, "http://www.alfresco.com"); + String ipAddr = null; + + try + { + ipAddr = InetAddress.getLocalHost().getHostAddress(); + } + catch (UnknownHostException ex) + { + } + + // Return a URL in the status message to browse to the folder node + + StringBuilder urlStr = new StringBuilder(); + + urlStr.append( "http://"); + urlStr.append(ipAddr); + urlStr.append(":8080/alfresco/navigate/browse/workspace/SpacesStore/"); + urlStr.append( params.getFolderNode().getId()); + urlStr.append("?ticket="); + urlStr.append(params.getTicket()); + + return new DesktopResponse(StsLaunchURL, urlStr.toString()); } } diff --git a/source/java/org/alfresco/filesys/smb/server/repo/pseudo/MemoryNetworkFile.java b/source/java/org/alfresco/filesys/smb/server/repo/pseudo/MemoryNetworkFile.java index 76d7cafe63..8eb403b31f 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/pseudo/MemoryNetworkFile.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/pseudo/MemoryNetworkFile.java @@ -19,7 +19,6 @@ package org.alfresco.filesys.smb.server.repo.pseudo; import java.io.IOException; -import org.alfresco.filesys.server.filesys.AccessDeniedException; import org.alfresco.filesys.server.filesys.FileInfo; import org.alfresco.filesys.server.filesys.NetworkFile; import org.alfresco.filesys.smb.SeekType; @@ -222,9 +221,7 @@ public class MemoryNetworkFile extends NetworkFile */ public void truncateFile(long siz) throws IOException { - // Do not allow the file to be written to - - throw new AccessDeniedException("Cannot truncate pseudo file"); + // Allow the truncate, do not alter the pseduo file data } /** @@ -236,9 +233,7 @@ public class MemoryNetworkFile extends NetworkFile */ public void writeFile(byte[] buf, int len, int pos) throws java.io.IOException { - // Do not allow the file to be written to - - throw new AccessDeniedException("Cannot write to pseudo file"); + // Allow the write, just do not do anything } /** @@ -252,8 +247,6 @@ public class MemoryNetworkFile extends NetworkFile */ public void writeFile(byte[] buf, int len, int pos, long offset) throws java.io.IOException { - // Do not allow the file to be written to - - throw new AccessDeniedException("Cannot write to pseudo file"); + // Allow the write, just do not do anything } } diff --git a/source/java/org/alfresco/filesys/smb/server/repo/pseudo/PseudoNetworkFile.java b/source/java/org/alfresco/filesys/smb/server/repo/pseudo/PseudoNetworkFile.java index 0ae631897c..4bcd2cefe0 100644 --- a/source/java/org/alfresco/filesys/smb/server/repo/pseudo/PseudoNetworkFile.java +++ b/source/java/org/alfresco/filesys/smb/server/repo/pseudo/PseudoNetworkFile.java @@ -21,7 +21,6 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; -import org.alfresco.filesys.server.filesys.AccessDeniedException; import org.alfresco.filesys.server.filesys.NetworkFile; import org.alfresco.filesys.smb.SeekType; @@ -272,9 +271,7 @@ public class PseudoNetworkFile extends NetworkFile */ public void truncateFile(long siz) throws IOException { - // Do not allow the file to be written to - - throw new AccessDeniedException("Cannot truncate pseudo file"); + // Allow the truncate, just do not do anything } /** @@ -286,9 +283,7 @@ public class PseudoNetworkFile extends NetworkFile */ public void writeFile(byte[] buf, int len, int pos) throws java.io.IOException { - // Do not allow the file to be written to - - throw new AccessDeniedException("Cannot write to pseudo file"); + // Allow the write, just do not do anything } /** @@ -302,8 +297,6 @@ public class PseudoNetworkFile extends NetworkFile */ public void writeFile(byte[] buf, int len, int pos, long offset) throws java.io.IOException { - // Do not allow the file to be written to - - throw new AccessDeniedException("Cannot write to pseudo file"); + // Allow the write, just do not do anything } } diff --git a/source/java/org/alfresco/jcr/exporter/JCRSystemXMLExporter.java b/source/java/org/alfresco/jcr/exporter/JCRSystemXMLExporter.java index a9d3b3e9bf..8f973ed183 100644 --- a/source/java/org/alfresco/jcr/exporter/JCRSystemXMLExporter.java +++ b/source/java/org/alfresco/jcr/exporter/JCRSystemXMLExporter.java @@ -178,7 +178,7 @@ public class JCRSystemXMLExporter implements Exporter Value[] mixinValues = mixinTypes.getValues(); for (int i = 0; i < mixinValues.length; i++) { - value(nodeRef, JCRMixinTypesProperty.PROPERTY_NAME, mixinValues[i], i); + value(nodeRef, JCRMixinTypesProperty.PROPERTY_NAME, mixinValues[i].getString(), i); } endProperty(nodeRef, JCRMixinTypesProperty.PROPERTY_NAME); diff --git a/source/java/org/alfresco/model/ContentModel.java b/source/java/org/alfresco/model/ContentModel.java index 7873190322..e74aaf3652 100644 --- a/source/java/org/alfresco/model/ContentModel.java +++ b/source/java/org/alfresco/model/ContentModel.java @@ -1,268 +1,268 @@ -/* - * 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.model; - -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; - - -/** - * Content Model Constants - */ -public interface ContentModel -{ - // - // System Model Definitions - // - - // base type constants - static final QName TYPE_BASE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "base"); - static final QName ASPECT_REFERENCEABLE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "referenceable"); - static final QName PROP_STORE_PROTOCOL = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "store-protocol"); - static final QName PROP_STORE_IDENTIFIER = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "store-identifier"); - static final QName PROP_NODE_UUID = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "node-uuid"); - static final QName PROP_NODE_DBID = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "node-dbid"); - - // tag for incomplete nodes - static final QName ASPECT_INCOMPLETE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "incomplete"); - - // tag for temporary nodes - static final QName ASPECT_TEMPORARY = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "temporary"); - - // archived nodes aspect constants - static final QName ASPECT_ARCHIVED = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archived"); - static final QName PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedOriginalParentAssoc"); - static final QName PROP_ARCHIVED_BY = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedBy"); - static final QName PROP_ARCHIVED_DATE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedDate"); - static final QName PROP_ARCHIVED_ORIGINAL_OWNER = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedOriginalOwner"); - static final QName ASPECT_ARCHIVED_ASSOCS = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archived-assocs"); - static final QName PROP_ARCHIVED_PARENT_ASSOCS = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedParentAssocs"); - static final QName PROP_ARCHIVED_CHILD_ASSOCS = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedChildAssocs"); - static final QName PROP_ARCHIVED_SOURCE_ASSOCS = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedSourceAssocs"); - static final QName PROP_ARCHIVED_TARGET_ASSOCS = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedTargetAssocs"); - - // 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"); - static final QName PROP_SYS_VERSION_REVISION = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionRevision"); - static final QName PROP_SYS_VERSION_LABEL = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionLabel"); - 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 - // - - // content management type constants - static final QName TYPE_CMOBJECT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "cmobject"); - static final QName PROP_NAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "name"); - - // 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"); - - // content type and aspect constants - static final QName TYPE_CONTENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "content"); - static final QName PROP_CONTENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "content"); - - // title aspect - static final QName ASPECT_TITLED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "titled"); - static final QName PROP_TITLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "title"); - static final QName PROP_DESCRIPTION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "description"); - - // auditable aspect - static final QName ASPECT_AUDITABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "auditable"); - static final QName PROP_CREATED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "created"); - static final QName PROP_CREATOR = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "creator"); - static final QName PROP_MODIFIED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modified"); - static final QName PROP_MODIFIER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modifier"); - static final QName PROP_ACCESSED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "accessed"); - - // author aspect - static final QName ASPECT_AUTHOR = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "author"); - static final QName PROP_AUTHOR = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "author"); - - // categories - static final QName TYPE_CATEGORYROOT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "category_root"); - static final QName ASPECT_CLASSIFIABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "classifiable"); - //static final QName ASPECT_CATEGORISATION = QName.createQName(NamespaceService.ALFRESCO_URI, "aspect_categorisation"); - static final QName ASPECT_GEN_CLASSIFIABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "generalclassifiable"); - static final QName TYPE_CATEGORY = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "category"); - 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"); - /** child association type supported by {@link #TYPE_FOLDER} */ - static final QName ASSOC_CONTAINS = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "contains"); - - // person - static final QName TYPE_PERSON = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "person"); - static final QName PROP_USERNAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "userName"); - static final QName PROP_HOMEFOLDER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "homeFolder"); - static final QName PROP_FIRSTNAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "firstName"); - 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"); - static final QName PROP_OWNER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "owner"); - - // Templatable aspect - static final QName ASPECT_TEMPLATABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "templatable"); - static final QName PROP_TEMPLATE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "template"); - - // Dictionary model - public static final QName TYPE_DICTIONARY_MODEL = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "dictionaryModel"); - public static final QName PROP_MODEL_NAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modelName"); - public static final QName PROP_MODEL_DESCRIPTION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modelDescription"); - public static final QName PROP_MODEL_AUTHOR = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modelAuthor"); - public static final QName PROP_MODEL_PUBLISHED_DATE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modelPublishedDate"); - public static final QName PROP_MODEL_VERSION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modelVersion"); - public static final QName PROP_MODEL_ACTIVE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modelActive"); - - // referencing aspect - public static final QName ASPECT_REFERENCING = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "referencing"); - public static final QName ASSOC_REFERENCES = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "references"); - - // link object - public static final QName TYPE_LINK = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "link"); - public static final QName PROP_LINK_DESTINATION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "destination"); - - // email aspect - public static final QName ASPECT_MAILED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "emailed"); - public static final QName PROP_SENTDATE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "sentdate"); - public static final QName PROP_ORIGINATOR = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "originator"); - public static final QName PROP_ADDRESSEE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "addressee"); - public static final QName PROP_ADDRESSEES = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "addressees"); - public static final QName PROP_SUBJECT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "subjectline"); - - // countable aspect - public static final QName ASPECT_COUNTABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "countable"); - 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"); - - // 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"); - - // - // Application Model Definitions - // - - // workflow - static final QName ASPECT_SIMPLE_WORKFLOW = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "simpleworkflow"); - static final QName PROP_APPROVE_STEP = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "approveStep"); - static final QName PROP_APPROVE_FOLDER = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "approveFolder"); - static final QName PROP_APPROVE_MOVE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "approveMove"); - 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"); - static final QName ASSOC_CONFIGURATIONS = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "configurations"); - - // object links - static final QName TYPE_FILELINK = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "filelink"); - static final QName TYPE_FOLDERLINK = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "folderlink"); - - // feed source aspect - static final QName ASPECT_FEEDSOURCE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "feedsource"); - static final QName PROP_FEEDTEMPLATE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "template"); - - // AVM web folder - static final QName TYPE_AVMWEBFOLDER = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "webfolder"); - static final QName PROP_AVMSTORE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "avmstore"); - static final QName ASSOC_WEBUSER = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "webuser"); - static final QName TYPE_WEBUSER = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "webuser"); - static final QName PROP_WEBUSERNAME = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "username"); - static final QName PROP_WEBUSERROLE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "role"); - - - // - // User Model Definitions - // - - static final String USER_MODEL_URI = "http://www.alfresco.org/model/user/1.0"; - static final String USER_MODEL_PREFIX = "usr"; - - static final QName TYPE_USER = QName.createQName(USER_MODEL_URI, "user"); - static final QName PROP_USER_USERNAME = QName.createQName(USER_MODEL_URI, "username"); - static final QName PROP_PASSWORD = QName.createQName(USER_MODEL_URI, "password"); - static final QName PROP_ENABLED = QName.createQName(USER_MODEL_URI, "enabled"); - static final QName PROP_ACCOUNT_EXPIRES = QName.createQName(USER_MODEL_URI, "accountExpires"); - static final QName PROP_ACCOUNT_EXPIRY_DATE = QName.createQName(USER_MODEL_URI, "accountExpiryDate"); - static final QName PROP_CREDENTIALS_EXPIRE = QName.createQName(USER_MODEL_URI, "credentialsExpire"); - 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"); - static final QName PROP_AUTHORITY_NAME = QName.createQName(USER_MODEL_URI, "authorityName"); - static final QName ASSOC_MEMBER = QName.createQName(USER_MODEL_URI, "member"); - static final QName PROP_MEMBERS = QName.createQName(USER_MODEL_URI, "members"); -} +/* + * 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.model; + +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + + +/** + * Content Model Constants + */ +public interface ContentModel +{ + // + // System Model Definitions + // + + // base type constants + static final QName TYPE_BASE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "base"); + static final QName ASPECT_REFERENCEABLE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "referenceable"); + static final QName PROP_STORE_PROTOCOL = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "store-protocol"); + static final QName PROP_STORE_IDENTIFIER = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "store-identifier"); + static final QName PROP_NODE_UUID = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "node-uuid"); + static final QName PROP_NODE_DBID = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "node-dbid"); + + // tag for incomplete nodes + static final QName ASPECT_INCOMPLETE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "incomplete"); + + // tag for temporary nodes + static final QName ASPECT_TEMPORARY = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "temporary"); + + // archived nodes aspect constants + static final QName ASPECT_ARCHIVED = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archived"); + static final QName PROP_ARCHIVED_ORIGINAL_PARENT_ASSOC = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedOriginalParentAssoc"); + static final QName PROP_ARCHIVED_BY = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedBy"); + static final QName PROP_ARCHIVED_DATE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedDate"); + static final QName PROP_ARCHIVED_ORIGINAL_OWNER = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedOriginalOwner"); + static final QName ASPECT_ARCHIVED_ASSOCS = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archived-assocs"); + static final QName PROP_ARCHIVED_PARENT_ASSOCS = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedParentAssocs"); + static final QName PROP_ARCHIVED_CHILD_ASSOCS = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedChildAssocs"); + static final QName PROP_ARCHIVED_SOURCE_ASSOCS = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedSourceAssocs"); + static final QName PROP_ARCHIVED_TARGET_ASSOCS = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "archivedTargetAssocs"); + + // 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"); + static final QName PROP_SYS_VERSION_REVISION = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionRevision"); + static final QName PROP_SYS_VERSION_LABEL = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "versionLabel"); + 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 + // + + // content management type constants + static final QName TYPE_CMOBJECT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "cmobject"); + static final QName PROP_NAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "name"); + + // 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"); + + // content type and aspect constants + static final QName TYPE_CONTENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "content"); + static final QName PROP_CONTENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "content"); + + // title aspect + static final QName ASPECT_TITLED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "titled"); + static final QName PROP_TITLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "title"); + static final QName PROP_DESCRIPTION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "description"); + + // auditable aspect + static final QName ASPECT_AUDITABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "auditable"); + static final QName PROP_CREATED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "created"); + static final QName PROP_CREATOR = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "creator"); + static final QName PROP_MODIFIED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modified"); + static final QName PROP_MODIFIER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modifier"); + static final QName PROP_ACCESSED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "accessed"); + + // author aspect + static final QName ASPECT_AUTHOR = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "author"); + static final QName PROP_AUTHOR = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "author"); + + // categories + static final QName TYPE_CATEGORYROOT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "category_root"); + static final QName ASPECT_CLASSIFIABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "classifiable"); + //static final QName ASPECT_CATEGORISATION = QName.createQName(NamespaceService.ALFRESCO_URI, "aspect_categorisation"); + static final QName ASPECT_GEN_CLASSIFIABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "generalclassifiable"); + static final QName TYPE_CATEGORY = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "category"); + 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"); + /** child association type supported by {@link #TYPE_FOLDER} */ + static final QName ASSOC_CONTAINS = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "contains"); + + // person + static final QName TYPE_PERSON = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "person"); + static final QName PROP_USERNAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "userName"); + static final QName PROP_HOMEFOLDER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "homeFolder"); + static final QName PROP_FIRSTNAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "firstName"); + 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"); + static final QName PROP_OWNER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "owner"); + + // Templatable aspect + static final QName ASPECT_TEMPLATABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "templatable"); + static final QName PROP_TEMPLATE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "template"); + + // Dictionary model + public static final QName TYPE_DICTIONARY_MODEL = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "dictionaryModel"); + public static final QName PROP_MODEL_NAME = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modelName"); + public static final QName PROP_MODEL_DESCRIPTION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modelDescription"); + public static final QName PROP_MODEL_AUTHOR = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modelAuthor"); + public static final QName PROP_MODEL_PUBLISHED_DATE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modelPublishedDate"); + public static final QName PROP_MODEL_VERSION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modelVersion"); + public static final QName PROP_MODEL_ACTIVE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "modelActive"); + + // referencing aspect + public static final QName ASPECT_REFERENCING = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "referencing"); + public static final QName ASSOC_REFERENCES = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "references"); + + // link object + public static final QName TYPE_LINK = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "link"); + public static final QName PROP_LINK_DESTINATION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "destination"); + + // email aspect + public static final QName ASPECT_MAILED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "emailed"); + public static final QName PROP_SENTDATE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "sentdate"); + public static final QName PROP_ORIGINATOR = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "originator"); + public static final QName PROP_ADDRESSEE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "addressee"); + public static final QName PROP_ADDRESSEES = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "addressees"); + public static final QName PROP_SUBJECT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "subjectline"); + + // countable aspect + public static final QName ASPECT_COUNTABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "countable"); + 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"); + + // 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"); + + // + // Application Model Definitions + // + + // workflow + static final QName ASPECT_SIMPLE_WORKFLOW = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "simpleworkflow"); + static final QName PROP_APPROVE_STEP = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "approveStep"); + static final QName PROP_APPROVE_FOLDER = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "approveFolder"); + static final QName PROP_APPROVE_MOVE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "approveMove"); + 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"); + static final QName ASSOC_CONFIGURATIONS = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "configurations"); + + // object links + static final QName TYPE_FILELINK = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "filelink"); + static final QName TYPE_FOLDERLINK = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "folderlink"); + + // feed source aspect + static final QName ASPECT_FEEDSOURCE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "feedsource"); + static final QName PROP_FEEDTEMPLATE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "template"); + + // AVM web folder + static final QName TYPE_AVMWEBFOLDER = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "webfolder"); + static final QName PROP_AVMSTORE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "avmstore"); + static final QName ASSOC_WEBUSER = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "webuser"); + static final QName TYPE_WEBUSER = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "webuser"); + static final QName PROP_WEBUSERNAME = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "username"); + static final QName PROP_WEBUSERROLE = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "role"); + + + // + // User Model Definitions + // + + static final String USER_MODEL_URI = "http://www.alfresco.org/model/user/1.0"; + static final String USER_MODEL_PREFIX = "usr"; + + static final QName TYPE_USER = QName.createQName(USER_MODEL_URI, "user"); + static final QName PROP_USER_USERNAME = QName.createQName(USER_MODEL_URI, "username"); + static final QName PROP_PASSWORD = QName.createQName(USER_MODEL_URI, "password"); + static final QName PROP_ENABLED = QName.createQName(USER_MODEL_URI, "enabled"); + static final QName PROP_ACCOUNT_EXPIRES = QName.createQName(USER_MODEL_URI, "accountExpires"); + static final QName PROP_ACCOUNT_EXPIRY_DATE = QName.createQName(USER_MODEL_URI, "accountExpiryDate"); + static final QName PROP_CREDENTIALS_EXPIRE = QName.createQName(USER_MODEL_URI, "credentialsExpire"); + 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"); + static final QName PROP_AUTHORITY_NAME = QName.createQName(USER_MODEL_URI, "authorityName"); + static final QName ASSOC_MEMBER = QName.createQName(USER_MODEL_URI, "member"); + static final QName PROP_MEMBERS = QName.createQName(USER_MODEL_URI, "members"); +} diff --git a/source/java/org/alfresco/repo/action/executer/CopyActionExecuter.java b/source/java/org/alfresco/repo/action/executer/CopyActionExecuter.java index 1c1d92ebc4..229a844a9e 100644 --- a/source/java/org/alfresco/repo/action/executer/CopyActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/CopyActionExecuter.java @@ -162,7 +162,7 @@ public class CopyActionExecuter extends ActionExecuterAbstractBase else { // Create a new copy of the node - this.copyService.copy( + this.copyService.copyAndRename( actionedUponNodeRef, destinationParent, destinationAssocTypeQName, diff --git a/source/java/org/alfresco/repo/admin/patch/AbstractPatch.java b/source/java/org/alfresco/repo/admin/patch/AbstractPatch.java index 4375b6e101..b921a3e0f7 100644 --- a/source/java/org/alfresco/repo/admin/patch/AbstractPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/AbstractPatch.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.node.integrity.IntegrityChecker; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.transaction.TransactionUtil; import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; @@ -329,6 +330,9 @@ public abstract class AbstractPatch implements Patch { public String doWork() throws Exception { + // downgrade integrity checking + IntegrityChecker.setWarnInTransaction(); + String report = applyInternal(); // done return report; @@ -389,7 +393,8 @@ public abstract class AbstractPatch implements Patch /** * This method does the work. All transactions and thread-safety will be taken care of by this class. - * Any exception will result in the transaction being rolled back. + * Any exception will result in the transaction being rolled back. Integrity checks are downgraded + * for the duration of the transaction. * * @return Returns the report (only success messages). * @see #apply() diff --git a/source/java/org/alfresco/repo/admin/patch/PatchExecuter.java b/source/java/org/alfresco/repo/admin/patch/PatchExecuter.java index d0f2655d69..dbb5e0b592 100644 --- a/source/java/org/alfresco/repo/admin/patch/PatchExecuter.java +++ b/source/java/org/alfresco/repo/admin/patch/PatchExecuter.java @@ -21,11 +21,10 @@ import java.util.List; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.i18n.I18NUtil; +import org.alfresco.util.AbstractLifecycleBean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; /** * This component is responsible for ensuring that patches are applied @@ -33,7 +32,7 @@ import org.springframework.context.event.ContextRefreshedEvent; * * @author Derek Hulley */ -public class PatchExecuter implements ApplicationListener +public class PatchExecuter extends AbstractLifecycleBean { private static final String MSG_CHECKING = "patch.executer.checking"; private static final String MSG_NO_PATCHES_REQUIRED = "patch.executer.no_patches_required"; @@ -101,16 +100,16 @@ public class PatchExecuter implements ApplicationListener } } - /* - * (non-Javadoc) - * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) - */ - public void onApplicationEvent(ApplicationEvent event) + @Override + protected void onBootstrap(ApplicationEvent event) { - if (event instanceof ContextRefreshedEvent) - { - applyOutstandingPatches(); - } + applyOutstandingPatches(); + } + + @Override + protected void onShutdown(ApplicationEvent event) + { + // NOOP } } diff --git a/source/java/org/alfresco/repo/admin/patch/impl/AbstractPermissionChangePatch.java b/source/java/org/alfresco/repo/admin/patch/impl/AbstractPermissionChangePatch.java new file mode 100644 index 0000000000..7f0cc516de --- /dev/null +++ b/source/java/org/alfresco/repo/admin/patch/impl/AbstractPermissionChangePatch.java @@ -0,0 +1,169 @@ +/* + * 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.admin.patch.impl; + +import java.util.List; + +import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.domain.DbAccessControlEntry; +import org.alfresco.repo.domain.DbPermission; +import org.alfresco.repo.domain.hibernate.DbPermissionImpl; +import org.alfresco.service.namespace.QName; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.springframework.orm.hibernate3.HibernateCallback; +import org.springframework.orm.hibernate3.support.HibernateDaoSupport; + +/** + * Provides common functionality to change a permission type and/or name. + * + * @author Derek Hulley + */ +public abstract class AbstractPermissionChangePatch extends AbstractPatch +{ + private HibernateHelper helper; + + public AbstractPermissionChangePatch() + { + helper = new HibernateHelper(); + } + + public void setSessionFactory(SessionFactory sessionFactory) + { + this.helper.setSessionFactory(sessionFactory); + } + + /** + * Helper method to rename (move) a permission. This involves checking for the existence of the + * new permission and then moving all the entries to point to the new permission. + * + * @param oldTypeQName the old permission type + * @param oldName the old permission name + * @param newTypeQName the new permission type + * @param newName the new permission name + * @return Returns the number of permission entries modified + */ + protected int renamePermission(QName oldTypeQName, String oldName, QName newTypeQName, String newName) + { + return helper.createAndUpdatePermission(oldTypeQName, oldName, newTypeQName, newName); + } + + /** Helper to get a permission entity */ + private static class GetPermissionCallback implements HibernateCallback + { + private QName typeQName; + private String name; + public GetPermissionCallback(QName typeQName, String name) + { + this.typeQName = typeQName; + this.name = name; + } + public Object doInHibernate(Session session) + { + // flush any outstanding entities + session.flush(); + + Query query = session.getNamedQuery(HibernateHelper.QUERY_GET_PERMISSION); + query.setParameter("permissionTypeQName", typeQName) + .setString("permissionName", name); + return query.uniqueResult(); + } + } + + private static class HibernateHelper extends HibernateDaoSupport + { + private static final String QUERY_GET_PERMISSION = "permission.GetPermission"; + private static final String QUERY_GET_ENTRIES_TO_CHANGE = "permission.patch.GetAccessControlEntriesToChangePermissionOn"; + + public int createAndUpdatePermission( + final QName oldTypeQName, + final String oldName, + final QName newTypeQName, + final String newName) + { + if (oldTypeQName.equals(newTypeQName) && oldName.equals(newName)) + { + throw new IllegalArgumentException("Cannot move permission to itself: " + oldTypeQName + "-" + oldName); + } + + HibernateCallback getNewPermissionCallback = new GetPermissionCallback(newTypeQName, newName); + DbPermission permission = (DbPermission) getHibernateTemplate().execute(getNewPermissionCallback); + if (permission == null) + { + // create the permission + permission = new DbPermissionImpl(); + permission.setTypeQname(newTypeQName); + permission.setName(newName); + // save + getHibernateTemplate().save(permission); + } + final DbPermission newPermission = permission; + // now update all entries that refer to the old permission + HibernateCallback updateEntriesCallback = new HibernateCallback() + { + private static final int MAX_RESULTS = 1000; + @SuppressWarnings("unchecked") + public Object doInHibernate(Session session) + { + int count = 0; + while (true) + { + // flush any outstanding entities + session.flush(); + + Query query = session.getNamedQuery(HibernateHelper.QUERY_GET_ENTRIES_TO_CHANGE); + query.setParameter("oldTypeQName", oldTypeQName) + .setParameter("oldName", oldName) + .setMaxResults(MAX_RESULTS); + List entries = (List) query.list(); + // if there are no results, then we're done + if (entries.size() == 0) + { + break; + } + for (DbAccessControlEntry entry : entries) + { + entry.setPermission(newPermission); + count++; + session.evict(entry); + } + // flush and evict all the entries + session.flush(); + for (DbAccessControlEntry entry : entries) + { + session.evict(entry); + } + // next set of results + } + // done + return count; + } + }; + int updateCount = (Integer) getHibernateTemplate().execute(updateEntriesCallback); + // now delete the old permission + HibernateCallback getOldPermissionCallback = new GetPermissionCallback(oldTypeQName, oldName); + DbPermission oldPermission = (DbPermission) getHibernateTemplate().execute(getOldPermissionCallback); + if (oldPermission != null) + { + getHibernateTemplate().delete(oldPermission); + } + // done + return updateCount; + } + } +} diff --git a/source/java/org/alfresco/repo/admin/patch/impl/ActionRuleDecouplingPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/ActionRuleDecouplingPatch.java index 8f4aab96c8..71d86005a3 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/ActionRuleDecouplingPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/ActionRuleDecouplingPatch.java @@ -54,6 +54,10 @@ public class ActionRuleDecouplingPatch extends AbstractPatch for (NodeRef origRuleNodeRef : resultSet.getNodeRefs()) { // Check that this rule need updated + if (!this.nodeService.exists(origRuleNodeRef)) + { + continue; + } Map origProperties = this.nodeService.getProperties(origRuleNodeRef); if (origProperties.containsKey(RuleModel.PROP_EXECUTE_ASYNC) == false) { @@ -79,21 +83,21 @@ public class ActionRuleDecouplingPatch extends AbstractPatch Map newProperties = this.nodeService.getProperties(newRuleNodeRef); // Set the rule type, execute async and applyToChildren properties on the rule - String ruleType = (String)origProperties.get(RuleModel.PROP_RULE_TYPE); + Serializable ruleType = origProperties.get(RuleModel.PROP_RULE_TYPE); origProperties.remove(RuleModel.PROP_RULE_TYPE); newProperties.put(RuleModel.PROP_RULE_TYPE, ruleType); - Boolean executeAsync = (Boolean)origProperties.get(ActionModel.PROP_EXECUTE_ASYNCHRONOUSLY); + Serializable executeAsync = origProperties.get(ActionModel.PROP_EXECUTE_ASYNCHRONOUSLY); origProperties.remove(ActionModel.PROP_EXECUTE_ASYNCHRONOUSLY); newProperties.put(RuleModel.PROP_EXECUTE_ASYNC, executeAsync); - Boolean applyToChildren = (Boolean)origProperties.get(RuleModel.PROP_APPLY_TO_CHILDREN); + Serializable applyToChildren = origProperties.get(RuleModel.PROP_APPLY_TO_CHILDREN); origProperties.remove(RuleModel.PROP_APPLY_TO_CHILDREN); newProperties.put(RuleModel.PROP_APPLY_TO_CHILDREN, applyToChildren); origProperties.remove(QName.createQName(RuleModel.RULE_MODEL_URI, "owningNodeRef")); // Move the action and description values from the composite action onto the rule - String title = (String)origProperties.get(ActionModel.PROP_ACTION_TITLE); + Serializable title = origProperties.get(ActionModel.PROP_ACTION_TITLE); origProperties.remove(ActionModel.PROP_ACTION_TITLE); - String description = (String)origProperties.get(ActionModel.PROP_ACTION_DESCRIPTION); + Serializable description = origProperties.get(ActionModel.PROP_ACTION_DESCRIPTION); origProperties.remove(ActionModel.PROP_ACTION_DESCRIPTION); newProperties.put(ContentModel.PROP_TITLE, title); newProperties.put(ContentModel.PROP_DESCRIPTION, description); diff --git a/source/java/org/alfresco/repo/admin/patch/impl/ContentPermissionPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/ContentPermissionPatch.java index 6f428ccd92..031589d26c 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/ContentPermissionPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/ContentPermissionPatch.java @@ -16,33 +16,40 @@ */ package org.alfresco.repo.admin.patch.impl; -import org.alfresco.repo.admin.patch.AbstractPatch; -import org.alfresco.service.cmr.admin.PatchException; -import org.hibernate.SessionFactory; +import org.alfresco.i18n.I18NUtil; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; /** * Roles defined in permissionsDefinition.xml moved from cm:content to sys:base. - * This effects the data stored in the node_perm_entry table. - *

- * WILL NOT EXECUTE ANYMORE + * This effects the data stored in the permission table. * * @author Derek Hulley */ -public class ContentPermissionPatch extends AbstractPatch +public class ContentPermissionPatch extends AbstractPermissionChangePatch { - private static final String MSG_UPGRADE = "patch.contentPermission.upgrade"; - - public ContentPermissionPatch() - { - } - - public void setSessionFactory(SessionFactory sessionFactory) - { - } + private static final String MSG_SUCCESS = "patch.contentPermission.result"; + private static final QName TYPE_QNAME_OLD = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "content"); + private static final QName TYPE_QNAME_NEW = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "base"); + private static final String[] NAMES = new String[] {"Execute", "ReadContent", "WriteContent", "ExecuteContent"}; + @Override protected String applyInternal() throws Exception { - throw new PatchException(MSG_UPGRADE); + int updateCount = 0; + for (String permissionName : NAMES) + { + updateCount += super.renamePermission( + ContentPermissionPatch.TYPE_QNAME_OLD, + permissionName, + ContentPermissionPatch.TYPE_QNAME_NEW, + permissionName); + } + + // build the result message + String msg = I18NUtil.getMessage(MSG_SUCCESS, updateCount); + // done + return msg; } } diff --git a/source/java/org/alfresco/repo/admin/patch/impl/PermissionDataPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/PermissionDataPatch.java index 8c815a7d1f..5d18fb4549 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/PermissionDataPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/PermissionDataPatch.java @@ -16,35 +16,42 @@ */ package org.alfresco.repo.admin.patch.impl; -import org.alfresco.repo.admin.patch.AbstractPatch; -import org.alfresco.service.cmr.admin.PatchException; -import org.hibernate.SessionFactory; +import org.alfresco.i18n.I18NUtil; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; /** * The roles defined in permissionsDefinition.xml moved from cm:folder to cm:cmobject. - * This effects the data stored in the node_perm_entry table. + * This effects the data stored in the permission table. *

* JIRA: {@link http://www.alfresco.org/jira/browse/AR-344 AR-344} - *

- * WILL NOT EXECUTE ANYMORE * * @author Derek Hulley */ -public class PermissionDataPatch extends AbstractPatch +public class PermissionDataPatch extends AbstractPermissionChangePatch { - private static final String MSG_UPGRADE = "patch.updatePermissionData.upgrade"; - - public PermissionDataPatch() - { - } - - public void setSessionFactory(SessionFactory sessionFactory) - { - } + private static final String MSG_SUCCESS = "patch.updatePermissionData.result"; + private static final QName TYPE_QNAME_OLD = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "folder"); + private static final QName TYPE_QNAME_NEW = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "cmobject"); + private static final String[] NAMES = new String[] {"Coordinator", "Contributor", "Editor", "Guest"}; + @Override protected String applyInternal() throws Exception { - throw new PatchException(MSG_UPGRADE); + int updateCount = 0; + for (String permissionName : NAMES) + { + updateCount += super.renamePermission( + PermissionDataPatch.TYPE_QNAME_OLD, + permissionName, + PermissionDataPatch.TYPE_QNAME_NEW, + permissionName); + } + + // build the result message + String msg = I18NUtil.getMessage(MSG_SUCCESS, updateCount); + // done + return msg; } } diff --git a/source/java/org/alfresco/repo/admin/patch/impl/UniqueChildNamePatch.java b/source/java/org/alfresco/repo/admin/patch/impl/UniqueChildNamePatch.java index 28a77aadd3..4fde56eac5 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/UniqueChildNamePatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/UniqueChildNamePatch.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import java.util.Collection; import java.util.Date; import java.util.List; @@ -30,6 +31,7 @@ import org.alfresco.repo.admin.patch.AbstractPatch; import org.alfresco.repo.domain.ChildAssoc; import org.alfresco.repo.domain.Node; import org.alfresco.repo.node.db.NodeDaoService; +import org.alfresco.service.cmr.admin.PatchException; import org.alfresco.service.cmr.dictionary.AssociationDefinition; import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; @@ -51,6 +53,7 @@ import org.springframework.orm.hibernate3.support.HibernateDaoSupport; public class UniqueChildNamePatch extends AbstractPatch { private static final String MSG_SUCCESS = "patch.uniqueChildName.result"; + private static final String ERR_UNABLE_TO_FIX = "patch.uniqueChildName.err.unable_to_fix"; private static final String MSG_COPY_OF = "patch.uniqueChildName.copyOf"; /** the number of associations to process at a time */ private static final int MAX_RESULTS = 1000; @@ -143,6 +146,7 @@ public class UniqueChildNamePatch extends AbstractPatch @SuppressWarnings("unused") List assocTypeQNames = getUsedAssocQNames(); + boolean unableToFix = false; int fixed = 0; int processed = 0; // check loop through all associations, looking for duplicates @@ -185,8 +189,10 @@ public class UniqueChildNamePatch extends AbstractPatch String usedChildName = childName; processed++; boolean duplicate = false; + int duplicateNumber = 0; while(true) { + duplicateNumber++; try { // push the name back to the node @@ -195,11 +201,46 @@ public class UniqueChildNamePatch extends AbstractPatch } catch (DuplicateChildNodeNameException e) { - // there was a duplicate, so adjust the name and change the node property - duplicate = true; - // assign a new name - usedChildName = childName + I18NUtil.getMessage(MSG_COPY_OF, processed); - // try again + if (duplicateNumber == 10) + { + // Try removing the secondary parent associations + writeLine(" Removing secondary parents of node " + childNode.getId()); + Collection parentAssocs = childNode.getParentAssocs(); + for (ChildAssoc parentAssoc : parentAssocs) + { + if (!parentAssoc.getIsPrimary()) + { + write(" - ").writeLine(parentAssoc); + // remove it + getSession().delete(parentAssoc); + } + } + // flush to ensure the database gets the changes + getSession().flush(); + // try again to be sure + continue; + } + else if (duplicateNumber > 10) + { + // after 10 attempts, we have to admit defeat. Perhaps there is a larger issue. + Collection parentAssocs = childNode.getParentAssocs(); + write(" Unable to set child name '" + usedChildName + "' for node " + childNode.getId()); + writeLine(" with parent associations:"); + for (ChildAssoc parentAssoc : parentAssocs) + { + write(" - ").writeLine(parentAssoc); + } + duplicate = false; + unableToFix = true; + break; + } + else + { + // there was a duplicate, so adjust the name and change the node property + duplicate = true; + // assign a new name + usedChildName = childName + I18NUtil.getMessage(MSG_COPY_OF, processed, duplicateNumber); + } } } // if duplicated, report it @@ -209,11 +250,11 @@ public class UniqueChildNamePatch extends AbstractPatch // get the node path NodeRef parentNodeRef = childAssoc.getParent().getNodeRef(); Path path = nodeService.getPath(parentNodeRef); - writeLine(" Changed duplicated child name:"); - writeLine(" Parent: " + parentNodeRef); - writeLine(" Parent path: " + path); - writeLine(" Duplicate name: " + childName); - writeLine(" Replaced with: " + usedChildName); + writeLine(" Changed duplicated child name:"); + writeLine(" Parent: " + parentNodeRef); + writeLine(" Parent path: " + path); + writeLine(" Duplicate name: " + childName); + writeLine(" Replaced with: " + usedChildName); } } // clear the session to preserve memory @@ -222,10 +263,17 @@ public class UniqueChildNamePatch extends AbstractPatch } } - - // build the result message - String msg = I18NUtil.getMessage(MSG_SUCCESS, processed, fixed, logFile); - return msg; + // check if it was successful or not + if (unableToFix) + { + throw new PatchException(ERR_UNABLE_TO_FIX, logFile); + } + else + { + // build the result message + String msg = I18NUtil.getMessage(MSG_SUCCESS, processed, fixed, logFile); + return msg; + } } @SuppressWarnings("unchecked") diff --git a/source/java/org/alfresco/repo/admin/patch/impl/UpdateGuestPermissionPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/UpdateGuestPermissionPatch.java index 58fd936812..374a393835 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/UpdateGuestPermissionPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/UpdateGuestPermissionPatch.java @@ -16,32 +16,27 @@ */ package org.alfresco.repo.admin.patch.impl; -import org.alfresco.repo.admin.patch.AbstractPatch; -import org.alfresco.service.cmr.admin.PatchException; -import org.hibernate.SessionFactory; +import org.alfresco.i18n.I18NUtil; +import org.alfresco.model.ContentModel; /** * The permission 'Guest' has been renamed to 'Consumer'. - *

- * WILL NOT EXECUTE ANYMORE * * @author David Caruana + * @author Derek Hulley */ -public class UpdateGuestPermissionPatch extends AbstractPatch +public class UpdateGuestPermissionPatch extends AbstractPermissionChangePatch { - private static final String MSG_UPGRADE = "patch.updateGuestPermission.upgrade"; - - public UpdateGuestPermissionPatch() - { - } - - public void setSessionFactory(SessionFactory sessionFactory) - { - } + private static final String MSG_SUCCESS = "patch.updateGuestPermission.result"; @Override protected String applyInternal() throws Exception { - throw new PatchException(MSG_UPGRADE); + int updateCount = super.renamePermission(ContentModel.TYPE_CMOBJECT, "Guest", ContentModel.TYPE_CMOBJECT, "Consumer"); + + // build the result message + String msg = I18NUtil.getMessage(MSG_SUCCESS, updateCount); + // done + return msg; } } diff --git a/source/java/org/alfresco/repo/admin/patch/util/ImportFileUpdater.java b/source/java/org/alfresco/repo/admin/patch/util/ImportFileUpdater.java new file mode 100644 index 0000000000..4148f74de8 --- /dev/null +++ b/source/java/org/alfresco/repo/admin/patch/util/ImportFileUpdater.java @@ -0,0 +1,573 @@ +/** + * + */ +package org.alfresco.repo.admin.patch.util; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.action.ActionModel; +import org.alfresco.repo.rule.RuleModel; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.util.GUID; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.XMLWriter; +import org.xml.sax.helpers.AttributesImpl; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; + +/** + * Updates a XML import file to be compatable with the current version of the repository. + * + * @author royw + */ +public class ImportFileUpdater +{ + /** Indent size **/ + private static int INDENT_SIZE = 2; + + /** The destination export version number **/ + private static String EXPORT_VERSION = "1.4.0"; + + /** Element names **/ + private static String NAME_EXPORTER_VERSION = "exporterVersion"; + private static String NAME_RULE = "rule"; + + /** The current import version number **/ + private String version; + + /** + * Updates the passed import file into the equivalent 1.4 format. + * + * @param source the source import file + * @param destination the destination import file + */ + public void updateImportFile(String source, String destination) + { + XmlPullParser reader = getReader(source); + XMLWriter writer = getWriter(destination); + + try + { + // Start the documentation + writer.startDocument(); + + // Start reading the document + int eventType = reader.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) + { + if (eventType == XmlPullParser.START_TAG) + { + ImportFileUpdater.this.outputCurrentElement(reader, writer, new OutputChildren()); + } + eventType = reader.next(); + } + + // End and close the document + writer.endDocument(); + writer.close(); + } + catch (Exception exception) + { + throw new AlfrescoRuntimeException("Unable to update import file.", exception); + } + + } + + /** + * Get the reader for the source import file + * + * @param source the source import file + * @return the XML pull parser used to read the file + */ + private XmlPullParser getReader(String source) + { + try + { + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null); + factory.setNamespaceAware(true); + + XmlPullParser xpp = factory.newPullParser(); + xpp.setInput(new FileReader(source)); + + return xpp; + } + catch (XmlPullParserException exception) + { + throw new AlfrescoRuntimeException("Unable to update import file.", exception); + } + catch (FileNotFoundException fileNotFound) + { + throw new AlfrescoRuntimeException("The source file could not be loaded.", fileNotFound); + } + } + + /** + * Get the writer for the import file + * + * @param destination the destination XML import file + * @return the XML writer + */ + private XMLWriter getWriter(String destination) + { + try + { + // Define output format + OutputFormat format = OutputFormat.createPrettyPrint(); + format.setNewLineAfterDeclaration(false); + format.setIndentSize(INDENT_SIZE); + format.setEncoding("UTF-8"); + + return new XMLWriter(new FileOutputStream(destination), format); + } + catch (Exception exception) + { + throw new AlfrescoRuntimeException("Unable to create XML writer.", exception); + } + } + + private void outputCurrentElement(XmlPullParser reader, XMLWriter writer, Work work) + throws Exception + { + outputCurrentElement(reader, writer, work, true); + } + + private void outputCurrentElement(XmlPullParser reader, XMLWriter writer, Work work, boolean checkForCallbacks) + throws Exception + { + if (checkForCallbacks == false || checkForCallbacks(reader, writer) == false) + { + // Get the name details of the element + String name = reader.getName(); + String namespace = reader.getNamespace(); + String prefix = reader.getPrefix(); + + // Sort out namespaces + Map nss = new HashMap(); + int nsStart = reader.getNamespaceCount(reader.getDepth()-1); + int nsEnd = reader.getNamespaceCount(reader.getDepth()); + for (int i = nsStart; i < nsEnd; i++) + { + String nsPrefix = reader.getNamespacePrefix(i); + String ns = reader.getNamespaceUri(i); + nss.put(nsPrefix, ns); + } + + // Sort out attributes + AttributesImpl attributes = new AttributesImpl(); + for (int i = 0; i < reader.getAttributeCount(); i++) + { + String attributeName = reader.getAttributeName(i); + String attributeNamespace = reader.getAttributeNamespace(i); + String attributePrefix = reader.getAttributePrefix(i); + String attributeType = reader.getAttributeType(i); + String attributeValue = reader.getAttributeValue(i); + + attributes.addAttribute(attributeNamespace, attributeName, attributePrefix+":"+attributeName, attributeType, attributeValue); + } + + // Start the namespace prefixes + for (Map.Entry entry : nss.entrySet()) + { + writer.startPrefixMapping(entry.getKey(), entry.getValue()); + } + + // Write the start of the element + writer.startElement(namespace, name, prefix+":"+name, attributes); + + // Do the work + work.doWork(reader, writer); + + // Write the end of the element + writer.endElement(namespace, name, prefix+":"+name); + + // End the namespace prefixes + for (String nsPrefix : nss.keySet()) + { + writer.endPrefixMapping(nsPrefix); + } + } + } + + private boolean checkForCallbacks(XmlPullParser reader, XMLWriter writer) + throws Exception + { + boolean result = false; + if (reader.getName().equals(NAME_EXPORTER_VERSION) == true) + { + new ImportVersionLabelCallback().doCallback(reader, writer); + result = true; + } + else if (reader.getName().equals(NAME_RULE) == true) + { + if (this.version.startsWith("1.3") == true) + { + new RuleCallback().doCallback(reader, writer); + result = true; + } + } + return result; + } + + private interface Work + { + void doWork(XmlPullParser reader, XMLWriter writer) + throws Exception; + } + + private class OutputChildren implements Work + { + public void doWork(XmlPullParser reader, XMLWriter writer) + throws Exception + { + // Deal with the contents of the tag + int eventType = reader.getEventType(); + while (eventType != XmlPullParser.END_TAG) + { + eventType = reader.next(); + if (eventType == XmlPullParser.START_TAG) + { + ImportFileUpdater.this.outputCurrentElement(reader, writer, new OutputChildren()); + } + else if (eventType == XmlPullParser.TEXT) + { + // Write the text to the output file + writer.write(reader.getText()); + } + } + } + } + + @SuppressWarnings("unused") + private class IgnoreChildren implements Work + { + public void doWork(XmlPullParser reader, XMLWriter writer) + throws Exception + { + int eventType = reader.getEventType(); + while (eventType != XmlPullParser.END_TAG) + { + eventType = reader.next(); + if (eventType == XmlPullParser.START_TAG) + { + doWork(reader, writer); + } + } + } + } + + private interface ImportUpdaterCallback + { + void doCallback(XmlPullParser reader, XMLWriter writer) + throws Exception; + } + + private class ImportVersionLabelCallback implements ImportUpdaterCallback + { + public void doCallback(XmlPullParser reader, XMLWriter writer) + throws Exception + { + ImportFileUpdater.this.outputCurrentElement(reader, writer, + new Work() + { + public void doWork(XmlPullParser reader, XMLWriter writer) throws Exception + { + reader.next(); + ImportFileUpdater.this.version = reader.getText(); + writer.write(EXPORT_VERSION); + reader.next(); + } + }, false); + } + } + + private class RuleCallback implements ImportUpdaterCallback + { + public void doCallback(XmlPullParser reader, XMLWriter writer) + throws Exception + { + // Get the name details of the element + String name = reader.getName(); + String namespace = reader.getNamespace(); + String prefix = reader.getPrefix(); + + // Rename the child assoc appropriately + AttributesImpl attributes = new AttributesImpl(); + String attributeName = reader.getAttributeName(0); + String attributeNamespace = reader.getAttributeNamespace(0); + String attributePrefix = reader.getAttributePrefix(0); + String attributeType = reader.getAttributeType(0); + String attributeValue = reader.getAttributeValue(0) + GUID.generate(); + attributes.addAttribute(attributeNamespace, attributeName, attributePrefix+":"+attributeName, attributeType, attributeValue); + + // Output the rules element + writer.startElement(namespace, name, prefix+":"+name, attributes); + + int eventType = reader.getEventType(); + while (eventType != XmlPullParser.END_TAG) + { + eventType = reader.next(); + if (eventType == XmlPullParser.START_TAG) + { + String childName = reader.getName(); + if (childName.equals("aspects") == true) + { + ImportFileUpdater.this.outputCurrentElement(reader, writer, + new Work() + { + public void doWork(XmlPullParser reader, XMLWriter writer) throws Exception + { + // Add titled aspect + writer.startElement( + ContentModel.ASPECT_TITLED.getNamespaceURI(), + ContentModel.ASPECT_TITLED.getLocalName(), + NamespaceService.CONTENT_MODEL_PREFIX + ":" + ContentModel.ASPECT_TITLED.getLocalName(), + new AttributesImpl()); + writer.endElement( + ContentModel.ASPECT_TITLED.getNamespaceURI(), + ContentModel.ASPECT_TITLED.getLocalName(), + NamespaceService.CONTENT_MODEL_PREFIX + ":" + ContentModel.ASPECT_TITLED.getLocalName()); + + // Read the rest of the elements and output + int eventType = reader.getEventType(); + while (eventType != XmlPullParser.END_TAG) + { + eventType = reader.next(); + if (eventType == XmlPullParser.START_TAG) + { + ImportFileUpdater.this.outputCurrentElement(reader, writer, new OutputChildren()); + } + } + } + + }, false); + } + else if (childName.equals("properties") == true) + { + ImportFileUpdater.this.outputCurrentElement(reader, writer, + new Work() + { + public void doWork(XmlPullParser reader, XMLWriter writer) throws Exception + { + int eventType = reader.getEventType(); + while (eventType != XmlPullParser.END_TAG) + { + eventType = reader.next(); + if (eventType == XmlPullParser.START_TAG) + { + String propName = reader.getName(); + if (propName.equals("actionDescription") == true) + { + writer.startElement( + ContentModel.PROP_DESCRIPTION.getNamespaceURI(), + ContentModel.PROP_DESCRIPTION.getLocalName(), + NamespaceService.CONTENT_MODEL_PREFIX + ":" + ContentModel.PROP_DESCRIPTION.getLocalName(), + new AttributesImpl()); + + // Output the value within + new OutputChildren().doWork(reader, writer); + + writer.endElement( + ContentModel.PROP_DESCRIPTION.getNamespaceURI(), + ContentModel.PROP_DESCRIPTION.getLocalName(), + NamespaceService.CONTENT_MODEL_PREFIX + ":" + ContentModel.PROP_DESCRIPTION.getLocalName()); + eventType = reader.next(); + + } + else if (propName.equals("actionTitle") == true) + { + writer.startElement( + ContentModel.PROP_TITLE.getNamespaceURI(), + ContentModel.PROP_TITLE.getLocalName(), + NamespaceService.CONTENT_MODEL_PREFIX + ":" + ContentModel.PROP_TITLE.getLocalName(), + new AttributesImpl()); + + // Output the value within + new OutputChildren().doWork(reader, writer); + + writer.endElement( + ContentModel.PROP_TITLE.getNamespaceURI(), + ContentModel.PROP_TITLE.getLocalName(), + NamespaceService.CONTENT_MODEL_PREFIX + ":" + ContentModel.PROP_TITLE.getLocalName()); + eventType = reader.next(); + } + else if (propName.equals("executeAsynchronously") == true) + { + writer.startElement( + RuleModel.PROP_EXECUTE_ASYNC.getNamespaceURI(), + RuleModel.PROP_EXECUTE_ASYNC.getLocalName(), + RuleModel.RULE_MODEL_PREFIX + ":" + RuleModel.PROP_EXECUTE_ASYNC.getLocalName(), + new AttributesImpl()); + + // Output the value within + new OutputChildren().doWork(reader, writer); + + writer.endElement( + RuleModel.PROP_EXECUTE_ASYNC.getNamespaceURI(), + RuleModel.PROP_EXECUTE_ASYNC.getLocalName(), + RuleModel.RULE_MODEL_PREFIX + ":" + RuleModel.PROP_EXECUTE_ASYNC.getLocalName()); + eventType = reader.next(); + } + else if (propName.equals("ruleType") == true) + { + ImportFileUpdater.this.outputCurrentElement(reader, writer, + new Work() + { + public void doWork(XmlPullParser reader, XMLWriter writer) throws Exception + { + // Output the elements that contain a multi values property + writer.startElement(NamespaceService.REPOSITORY_VIEW_1_0_URI, "values", "view:values", new AttributesImpl()); + writer.startElement(NamespaceService.REPOSITORY_VIEW_1_0_URI, "value", "view:value", new AttributesImpl()); + + // Output the value within + new OutputChildren().doWork(reader, writer); + + // End the multi values elements + writer.endElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "value", "view:value"); + writer.endElement(NamespaceService.REPOSITORY_VIEW_PREFIX, "values", "view:values"); + } + }, false); + } + else if (propName.equals("definitionName") == true) + { + // Skip past next end + while (eventType != XmlPullParser.END_TAG) + { + eventType = reader.next(); + } + eventType = reader.next(); + } + else + { + ImportFileUpdater.this.outputCurrentElement(reader, writer, new OutputChildren()); + } + } + } + + // Output value for the disabled property + writer.startElement( + RuleModel.PROP_DISABLED.getNamespaceURI(), + RuleModel.PROP_DISABLED.getLocalName(), + RuleModel.RULE_MODEL_PREFIX + ":" + RuleModel.PROP_DISABLED.getLocalName(), + new AttributesImpl()); + writer.write("false"); + writer.endElement( + RuleModel.PROP_DISABLED.getNamespaceURI(), + RuleModel.PROP_DISABLED.getLocalName(), + RuleModel.RULE_MODEL_PREFIX + ":" + RuleModel.PROP_DISABLED.getLocalName()); + } + }, false); + } + else if (childName.equals("associations") == true) + { + ImportFileUpdater.this.outputCurrentElement(reader, writer, + new Work() + { + public void doWork(XmlPullParser reader, XMLWriter writer) throws Exception + { + // + writer.startElement( + RuleModel.ASSOC_ACTION.getNamespaceURI(), + RuleModel.ASSOC_ACTION.getLocalName(), + RuleModel.RULE_MODEL_PREFIX + ":" + RuleModel.ASSOC_ACTION.getLocalName(), + new AttributesImpl()); + + // + AttributesImpl attributes = new AttributesImpl(); + attributes.addAttribute(NamespaceService.REPOSITORY_VIEW_1_0_URI, "childName", "view:childName", null, "rule:action"); + writer.startElement( + ActionModel.TYPE_COMPOSITE_ACTION.getNamespaceURI(), + ActionModel.TYPE_COMPOSITE_ACTION.getLocalName(), + ActionModel.ACTION_MODEL_PREFIX+ ":" + ActionModel.TYPE_COMPOSITE_ACTION.getLocalName(), + attributes); + + // + writer.startElement( + NamespaceService.REPOSITORY_VIEW_1_0_URI, + "properties", + "view:properties", + new AttributesImpl()); + + // composite-action + writer.startElement( + ActionModel.PROP_DEFINITION_NAME.getNamespaceURI(), + ActionModel.PROP_DEFINITION_NAME.getLocalName(), + ActionModel.ACTION_MODEL_PREFIX + ":" + ActionModel.PROP_DEFINITION_NAME.getLocalName(), + new AttributesImpl()); + writer.write("composite-action"); + writer.endElement( + ActionModel.PROP_DEFINITION_NAME.getNamespaceURI(), + ActionModel.PROP_DEFINITION_NAME.getLocalName(), + ActionModel.ACTION_MODEL_PREFIX + ":" + ActionModel.PROP_DEFINITION_NAME.getLocalName()); + + // + writer.endElement( + NamespaceService.REPOSITORY_VIEW_1_0_URI, + "properties", + "view:properties"); + + // + writer.startElement( + NamespaceService.REPOSITORY_VIEW_1_0_URI, + "associations", + "view:associations", + new AttributesImpl()); + + // Output the association details + new OutputChildren().doWork(reader, writer); + + // + writer.endElement( + NamespaceService.REPOSITORY_VIEW_1_0_URI, + "associations", + "view:associations"); + + // + writer.endElement( + ActionModel.TYPE_COMPOSITE_ACTION.getNamespaceURI(), + ActionModel.TYPE_COMPOSITE_ACTION.getLocalName(), + ActionModel.ACTION_MODEL_PREFIX+ ":" + ActionModel.TYPE_COMPOSITE_ACTION.getLocalName()); + + // + writer.endElement( + RuleModel.ASSOC_ACTION.getNamespaceURI(), + RuleModel.ASSOC_ACTION.getLocalName(), + RuleModel.RULE_MODEL_PREFIX + ":" + RuleModel.ASSOC_ACTION.getLocalName()); + } + }, false); + } + else + { + // Output anything else that might be hanging araound + ImportFileUpdater.this.outputCurrentElement(reader, writer, new OutputChildren()); + } + } + } + + // End the rules element + writer.endElement(namespace, name, prefix+":"+name); + } + } + + public static void main(String[] args) + { + if (args.length == 2) + { + ImportFileUpdater util = new ImportFileUpdater(); + util.updateImportFile(args[0], args[1]); + } + else + { + System.out.println(" ImportFileUpdater "); + System.out.println(" source - 1.3 import file name to be updated"); + System.out.println(" destination - name of the generated 1.4 import file"); + } + } + +} diff --git a/source/java/org/alfresco/repo/content/RoutingContentService.java b/source/java/org/alfresco/repo/content/RoutingContentService.java index 3821025eca..4137a3a7ea 100644 --- a/source/java/org/alfresco/repo/content/RoutingContentService.java +++ b/source/java/org/alfresco/repo/content/RoutingContentService.java @@ -1,506 +1,506 @@ -/* - * 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; - -import java.io.Serializable; -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.model.ContentModel; -import org.alfresco.repo.avm.AVMNodeConverter; -import org.alfresco.repo.content.ContentServicePolicies.OnContentReadPolicy; -import org.alfresco.repo.content.ContentServicePolicies.OnContentUpdatePolicy; -import org.alfresco.repo.content.filestore.FileContentStore; -import org.alfresco.repo.content.transform.ContentTransformer; -import org.alfresco.repo.content.transform.ContentTransformerRegistry; -import org.alfresco.repo.content.transform.magick.ImageMagickContentTransformer; -import org.alfresco.repo.policy.ClassPolicyDelegate; -import org.alfresco.repo.policy.JavaBehaviour; -import org.alfresco.repo.policy.PolicyComponent; -import org.alfresco.service.cmr.avm.AVMService; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -import org.alfresco.service.cmr.dictionary.DictionaryService; -import org.alfresco.service.cmr.dictionary.InvalidTypeException; -import org.alfresco.service.cmr.dictionary.PropertyDefinition; -import org.alfresco.service.cmr.repository.ContentData; -import org.alfresco.service.cmr.repository.ContentIOException; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.cmr.repository.ContentService; -import org.alfresco.service.cmr.repository.ContentStreamListener; -import org.alfresco.service.cmr.repository.ContentWriter; -import org.alfresco.service.cmr.repository.NoTransformerException; -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.EqualsHelper; -import org.alfresco.util.Pair; -import org.alfresco.util.TempFileProvider; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - * A content service that determines at runtime the store that the - * content associated with a node should be routed to. - * - * @author Derek Hulley - */ -public class RoutingContentService implements ContentService -{ - private static Log logger = LogFactory.getLog(RoutingContentService.class); - - private TransactionService transactionService; - private DictionaryService dictionaryService; - private NodeService nodeService; - private AVMService avmService; - - /** a registry of all available content transformers */ - private ContentTransformerRegistry transformerRegistry; - /** TEMPORARY until we have a map to choose from at runtime */ - private ContentStore store; - /** the store for all temporarily created content */ - private ContentStore tempStore; - private ImageMagickContentTransformer imageMagickContentTransformer; - - /** - * The policy component - */ - private PolicyComponent policyComponent; - - /** - * Policies delegate - */ - ClassPolicyDelegate onContentUpdateDelegate; - ClassPolicyDelegate onContentReadDelegate; - - /** - * Default constructor sets up a temporary store - */ - public RoutingContentService() - { - this.tempStore = new FileContentStore(TempFileProvider.getTempDir().getAbsolutePath()); - } - - public void setTransactionService(TransactionService transactionService) - { - this.transactionService = transactionService; - } - - public void setDictionaryService(DictionaryService dictionaryService) - { - this.dictionaryService = dictionaryService; - } - - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - public void setTransformerRegistry(ContentTransformerRegistry transformerRegistry) - { - this.transformerRegistry = transformerRegistry; - } - - public void setStore(ContentStore store) - { - this.store = store; - } - - public void setPolicyComponent(PolicyComponent policyComponent) - { - this.policyComponent = policyComponent; - } - - public void setAvmService(AVMService service) - { - this.avmService = service; - } - - public void setImageMagickContentTransformer(ImageMagickContentTransformer imageMagickContentTransformer) - { - this.imageMagickContentTransformer = imageMagickContentTransformer; - } - - /** - * Service initialise - */ - public void init() - { - // Bind on update properties behaviour - this.policyComponent.bindClassBehaviour( - QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"), - this, - new JavaBehaviour(this, "onUpdateProperties")); - - // Register on content update policy - this.onContentUpdateDelegate = this.policyComponent.registerClassPolicy(OnContentUpdatePolicy.class); - this.onContentReadDelegate = this.policyComponent.registerClassPolicy(OnContentReadPolicy.class); - } - - /** - * Update properties policy behaviour - * - * @param nodeRef the node reference - * @param before the before values of the properties - * @param after the after values of the properties - */ - public void onUpdateProperties( - NodeRef nodeRef, - Map before, - Map after) - { - boolean fire = false; - boolean newContent = false; - // check if any of the content properties have changed - for (QName propertyQName : after.keySet()) - { - // is this a content property? - PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); - if (propertyDef == null) - { - // the property is not recognised - continue; - } - if (!propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT)) - { - // not a content type - continue; - } - - try - { - ContentData beforeValue = (ContentData) before.get(propertyQName); - ContentData afterValue = (ContentData) after.get(propertyQName); - if (afterValue != null && afterValue.getContentUrl() == null) - { - // no URL - ignore - } - else if (!EqualsHelper.nullSafeEquals(beforeValue, afterValue)) - { - // So debug ... - if (logger.isDebugEnabled() == true) - { - String beforeString = ""; - if (beforeValue != null) - { - beforeString = beforeValue.toString(); - } - String afterString = ""; - if (afterValue != null) - { - afterString = afterValue.toString(); - } - logger.debug("onContentUpate: before = " + beforeString + "; after = " + afterString); - } - - // Figure out if the content is new or not - String beforeContentUrl = null; - if (beforeValue != null) - { - beforeContentUrl = beforeValue.getContentUrl(); - } - String afterContentUrl = null; - if (afterValue != null) - { - afterContentUrl = afterValue.getContentUrl(); - } - if (beforeContentUrl == null && afterContentUrl != null) - { - newContent = true; - } - - // the content changed - // at the moment, we are only interested in this one change - fire = true; - break; - } - } - catch (ClassCastException e) - { - // properties don't conform to model - continue; - } - } - // fire? - if (fire) - { - // Fire the content update policy - Set types = new HashSet(this.nodeService.getAspects(nodeRef)); - types.add(this.nodeService.getType(nodeRef)); - OnContentUpdatePolicy policy = this.onContentUpdateDelegate.get(nodeRef, types); - policy.onContentUpdate(nodeRef, newContent); - } - } - - public ContentReader getReader(NodeRef nodeRef, QName propertyQName) - { - return getReader(nodeRef, propertyQName, true); - } - - private ContentReader getReader(NodeRef nodeRef, QName propertyQName, boolean fireContentReadPolicy) - { - ContentData contentData = null; - Serializable propValue = nodeService.getProperty(nodeRef, propertyQName); - if (propValue instanceof Collection) - { - Collection colPropValue = (Collection)propValue; - if (colPropValue.size() > 0) - { - propValue = (Serializable)colPropValue.iterator().next(); - } - } - - if (propValue instanceof ContentData) - { - contentData = (ContentData)propValue; - } - - if (contentData == null) - { - // if no value or a value other content, and a property definition has been provided, ensure that it's CONTENT or ANY - PropertyDefinition contentPropDef = dictionaryService.getProperty(propertyQName); - if (contentPropDef != null && - (!(contentPropDef.getDataType().getName().equals(DataTypeDefinition.CONTENT) || - contentPropDef.getDataType().getName().equals(DataTypeDefinition.ANY)))) - { - throw new InvalidTypeException("The node property must be of type content: \n" + - " node: " + nodeRef + "\n" + - " property name: " + propertyQName + "\n" + - " property type: " + ((contentPropDef == null) ? "unknown" : contentPropDef.getDataType()), - propertyQName); - } - } - - // check that the URL is available - if (contentData == null || contentData.getContentUrl() == null) - { - // there is no URL - the interface specifies that this is not an error condition - return null; - } - String contentUrl = contentData.getContentUrl(); - - // TODO: Choose the store to read from at runtime - ContentReader reader = store.getReader(contentUrl); - - // set extra data on the reader - reader.setMimetype(contentData.getMimetype()); - reader.setEncoding(contentData.getEncoding()); - - // Fire the content read policy - if (reader != null && fireContentReadPolicy == true) - { - // Fire the content update policy - Set types = new HashSet(this.nodeService.getAspects(nodeRef)); - types.add(this.nodeService.getType(nodeRef)); - OnContentReadPolicy policy = this.onContentReadDelegate.get(nodeRef, types); - policy.onContentRead(nodeRef); - } - - // we don't listen for anything - // result may be null - but interface contract says we may return null - return reader; - } - - 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); - - // TODO: Choose the store to write to at runtime - - // get the content using the (potentially) existing content - the new content - // can be wherever the store decides. - ContentWriter writer = store.getWriter(existingContentReader, null); - - // Special case for AVM repository. - Serializable contentValue = null; - if (nodeRef.getStoreRef().getProtocol().equals(StoreRef.PROTOCOL_AVM)) - { - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - contentValue = avmService.getContentDataForWrite(avmVersionPath.getSecond()); - } - else - { - contentValue = nodeService.getProperty(nodeRef, propertyQName); - } - - // set extra data on the reader if the property is pre-existing - if (contentValue != null && contentValue instanceof ContentData) - { - ContentData contentData = (ContentData)contentValue; - writer.setMimetype(contentData.getMimetype()); - writer.setEncoding(contentData.getEncoding()); - } - - // attach a listener if required - if (update) - { - // need a listener to update the node when the stream closes - WriteStreamListener listener = new WriteStreamListener(nodeService, nodeRef, propertyQName, writer); - writer.addListener(listener); - writer.setTransactionService(transactionService); - } - - // give back to the client - return writer; - } - - /** - * @return Returns a writer to an anonymous location - */ - public ContentWriter getTempWriter() - { - // there is no existing content and we don't specify the location of the new content - return tempStore.getWriter(null, null); - } - - /** - * @see org.alfresco.repo.content.transform.ContentTransformerRegistry - * @see org.alfresco.repo.content.transform.ContentTransformer - */ - public void transform(ContentReader reader, ContentWriter writer) - throws NoTransformerException, ContentIOException - { - // check that source and target mimetypes are available - String sourceMimetype = reader.getMimetype(); - if (sourceMimetype == null) - { - throw new AlfrescoRuntimeException("The content reader mimetype must be set: " + reader); - } - String targetMimetype = writer.getMimetype(); - if (targetMimetype == null) - { - throw new AlfrescoRuntimeException("The content writer mimetype must be set: " + writer); - } - // look for a transformer - ContentTransformer transformer = transformerRegistry.getTransformer(sourceMimetype, targetMimetype); - if (transformer == null) - { - throw new NoTransformerException(sourceMimetype, targetMimetype); - } - // we have a transformer, so do it - transformer.transform(reader, writer); - // done - } - - /** - * @see org.alfresco.repo.content.transform.ContentTransformerRegistry - * @see org.alfresco.repo.content.transform.ContentTransformer - */ - public ContentTransformer getTransformer(String sourceMimetype, String targetMimetype) - { - // look for a transformer - ContentTransformer transformer = transformerRegistry.getTransformer(sourceMimetype, targetMimetype); - // done - return transformer; - } - - /** - * @see org.alfresco.service.cmr.repository.ContentService#getImageTransformer() - */ - public ContentTransformer getImageTransformer() - { - return imageMagickContentTransformer; - } - - /** - * @see org.alfresco.repo.content.transform.ContentTransformerRegistry - * @see org.alfresco.repo.content.transform.ContentTransformer - */ - public boolean isTransformable(ContentReader reader, ContentWriter writer) - { - // check that source and target mimetypes are available - String sourceMimetype = reader.getMimetype(); - if (sourceMimetype == null) - { - throw new AlfrescoRuntimeException("The content reader mimetype must be set: " + reader); - } - String targetMimetype = writer.getMimetype(); - if (targetMimetype == null) - { - throw new AlfrescoRuntimeException("The content writer mimetype must be set: " + writer); - } - - // look for a transformer - ContentTransformer transformer = transformerRegistry.getTransformer(sourceMimetype, targetMimetype); - return (transformer != null); - } - - /** - * Ensures that, upon closure of the output stream, the node is updated with - * the latest URL of the content to which it refers. - *

- * The listener close operation does not need a transaction as the - * ContentWriter takes care of that. - * - * @author Derek Hulley - */ - private static class WriteStreamListener implements ContentStreamListener - { - private NodeService nodeService; - private NodeRef nodeRef; - private QName propertyQName; - private ContentWriter writer; - - public WriteStreamListener( - NodeService nodeService, - NodeRef nodeRef, - QName propertyQName, - ContentWriter writer) - { - this.nodeService = nodeService; - this.nodeRef = nodeRef; - this.propertyQName = propertyQName; - this.writer = writer; - } - - public void contentStreamClosed() throws ContentIOException - { - try - { - // set the full content property - ContentData contentData = writer.getContentData(); - nodeService.setProperty( - nodeRef, - propertyQName, - contentData); - // done - if (logger.isDebugEnabled()) - { - logger.debug("Stream listener updated node: \n" + - " node: " + nodeRef + "\n" + - " property: " + propertyQName + "\n" + - " value: " + contentData); - } - } - catch (Throwable e) - { - throw new ContentIOException("Failed to set content property on stream closure: \n" + - " node: " + nodeRef + "\n" + - " property: " + propertyQName + "\n" + - " writer: " + writer, - e); - } - } - } -} +/* + * 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; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.avm.AVMNodeConverter; +import org.alfresco.repo.content.ContentServicePolicies.OnContentReadPolicy; +import org.alfresco.repo.content.ContentServicePolicies.OnContentUpdatePolicy; +import org.alfresco.repo.content.filestore.FileContentStore; +import org.alfresco.repo.content.transform.ContentTransformer; +import org.alfresco.repo.content.transform.ContentTransformerRegistry; +import org.alfresco.repo.content.transform.magick.ImageMagickContentTransformer; +import org.alfresco.repo.policy.ClassPolicyDelegate; +import org.alfresco.repo.policy.JavaBehaviour; +import org.alfresco.repo.policy.PolicyComponent; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.InvalidTypeException; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.ContentIOException; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.ContentStreamListener; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.NoTransformerException; +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.EqualsHelper; +import org.alfresco.util.Pair; +import org.alfresco.util.TempFileProvider; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * A content service that determines at runtime the store that the + * content associated with a node should be routed to. + * + * @author Derek Hulley + */ +public class RoutingContentService implements ContentService +{ + private static Log logger = LogFactory.getLog(RoutingContentService.class); + + private TransactionService transactionService; + private DictionaryService dictionaryService; + private NodeService nodeService; + private AVMService avmService; + + /** a registry of all available content transformers */ + private ContentTransformerRegistry transformerRegistry; + /** TEMPORARY until we have a map to choose from at runtime */ + private ContentStore store; + /** the store for all temporarily created content */ + private ContentStore tempStore; + private ImageMagickContentTransformer imageMagickContentTransformer; + + /** + * The policy component + */ + private PolicyComponent policyComponent; + + /** + * Policies delegate + */ + ClassPolicyDelegate onContentUpdateDelegate; + ClassPolicyDelegate onContentReadDelegate; + + /** + * Default constructor sets up a temporary store + */ + public RoutingContentService() + { + this.tempStore = new FileContentStore(TempFileProvider.getTempDir().getAbsolutePath()); + } + + public void setTransactionService(TransactionService transactionService) + { + this.transactionService = transactionService; + } + + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + public void setTransformerRegistry(ContentTransformerRegistry transformerRegistry) + { + this.transformerRegistry = transformerRegistry; + } + + public void setStore(ContentStore store) + { + this.store = store; + } + + public void setPolicyComponent(PolicyComponent policyComponent) + { + this.policyComponent = policyComponent; + } + + public void setAvmService(AVMService service) + { + this.avmService = service; + } + + public void setImageMagickContentTransformer(ImageMagickContentTransformer imageMagickContentTransformer) + { + this.imageMagickContentTransformer = imageMagickContentTransformer; + } + + /** + * Service initialise + */ + public void init() + { + // Bind on update properties behaviour + this.policyComponent.bindClassBehaviour( + QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"), + this, + new JavaBehaviour(this, "onUpdateProperties")); + + // Register on content update policy + this.onContentUpdateDelegate = this.policyComponent.registerClassPolicy(OnContentUpdatePolicy.class); + this.onContentReadDelegate = this.policyComponent.registerClassPolicy(OnContentReadPolicy.class); + } + + /** + * Update properties policy behaviour + * + * @param nodeRef the node reference + * @param before the before values of the properties + * @param after the after values of the properties + */ + public void onUpdateProperties( + NodeRef nodeRef, + Map before, + Map after) + { + boolean fire = false; + boolean newContent = false; + // check if any of the content properties have changed + for (QName propertyQName : after.keySet()) + { + // is this a content property? + PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); + if (propertyDef == null) + { + // the property is not recognised + continue; + } + if (!propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT)) + { + // not a content type + continue; + } + + try + { + ContentData beforeValue = (ContentData) before.get(propertyQName); + ContentData afterValue = (ContentData) after.get(propertyQName); + if (afterValue != null && afterValue.getContentUrl() == null) + { + // no URL - ignore + } + else if (!EqualsHelper.nullSafeEquals(beforeValue, afterValue)) + { + // So debug ... + if (logger.isDebugEnabled() == true) + { + String beforeString = ""; + if (beforeValue != null) + { + beforeString = beforeValue.toString(); + } + String afterString = ""; + if (afterValue != null) + { + afterString = afterValue.toString(); + } + logger.debug("onContentUpate: before = " + beforeString + "; after = " + afterString); + } + + // Figure out if the content is new or not + String beforeContentUrl = null; + if (beforeValue != null) + { + beforeContentUrl = beforeValue.getContentUrl(); + } + String afterContentUrl = null; + if (afterValue != null) + { + afterContentUrl = afterValue.getContentUrl(); + } + if (beforeContentUrl == null && afterContentUrl != null) + { + newContent = true; + } + + // the content changed + // at the moment, we are only interested in this one change + fire = true; + break; + } + } + catch (ClassCastException e) + { + // properties don't conform to model + continue; + } + } + // fire? + if (fire) + { + // Fire the content update policy + Set types = new HashSet(this.nodeService.getAspects(nodeRef)); + types.add(this.nodeService.getType(nodeRef)); + OnContentUpdatePolicy policy = this.onContentUpdateDelegate.get(nodeRef, types); + policy.onContentUpdate(nodeRef, newContent); + } + } + + public ContentReader getReader(NodeRef nodeRef, QName propertyQName) + { + return getReader(nodeRef, propertyQName, true); + } + + private ContentReader getReader(NodeRef nodeRef, QName propertyQName, boolean fireContentReadPolicy) + { + ContentData contentData = null; + Serializable propValue = nodeService.getProperty(nodeRef, propertyQName); + if (propValue instanceof Collection) + { + Collection colPropValue = (Collection)propValue; + if (colPropValue.size() > 0) + { + propValue = (Serializable)colPropValue.iterator().next(); + } + } + + if (propValue instanceof ContentData) + { + contentData = (ContentData)propValue; + } + + if (contentData == null) + { + // if no value or a value other content, and a property definition has been provided, ensure that it's CONTENT or ANY + PropertyDefinition contentPropDef = dictionaryService.getProperty(propertyQName); + if (contentPropDef != null && + (!(contentPropDef.getDataType().getName().equals(DataTypeDefinition.CONTENT) || + contentPropDef.getDataType().getName().equals(DataTypeDefinition.ANY)))) + { + throw new InvalidTypeException("The node property must be of type content: \n" + + " node: " + nodeRef + "\n" + + " property name: " + propertyQName + "\n" + + " property type: " + ((contentPropDef == null) ? "unknown" : contentPropDef.getDataType()), + propertyQName); + } + } + + // check that the URL is available + if (contentData == null || contentData.getContentUrl() == null) + { + // there is no URL - the interface specifies that this is not an error condition + return null; + } + String contentUrl = contentData.getContentUrl(); + + // TODO: Choose the store to read from at runtime + ContentReader reader = store.getReader(contentUrl); + + // set extra data on the reader + reader.setMimetype(contentData.getMimetype()); + reader.setEncoding(contentData.getEncoding()); + + // Fire the content read policy + if (reader != null && fireContentReadPolicy == true) + { + // Fire the content update policy + Set types = new HashSet(this.nodeService.getAspects(nodeRef)); + types.add(this.nodeService.getType(nodeRef)); + OnContentReadPolicy policy = this.onContentReadDelegate.get(nodeRef, types); + policy.onContentRead(nodeRef); + } + + // we don't listen for anything + // result may be null - but interface contract says we may return null + return reader; + } + + 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); + + // TODO: Choose the store to write to at runtime + + // get the content using the (potentially) existing content - the new content + // can be wherever the store decides. + ContentWriter writer = store.getWriter(existingContentReader, null); + + // Special case for AVM repository. + Serializable contentValue = null; + if (nodeRef.getStoreRef().getProtocol().equals(StoreRef.PROTOCOL_AVM)) + { + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + contentValue = avmService.getContentDataForWrite(avmVersionPath.getSecond()); + } + else + { + contentValue = nodeService.getProperty(nodeRef, propertyQName); + } + + // set extra data on the reader if the property is pre-existing + if (contentValue != null && contentValue instanceof ContentData) + { + ContentData contentData = (ContentData)contentValue; + writer.setMimetype(contentData.getMimetype()); + writer.setEncoding(contentData.getEncoding()); + } + + // attach a listener if required + if (update) + { + // need a listener to update the node when the stream closes + WriteStreamListener listener = new WriteStreamListener(nodeService, nodeRef, propertyQName, writer); + writer.addListener(listener); + writer.setTransactionService(transactionService); + } + + // give back to the client + return writer; + } + + /** + * @return Returns a writer to an anonymous location + */ + public ContentWriter getTempWriter() + { + // there is no existing content and we don't specify the location of the new content + return tempStore.getWriter(null, null); + } + + /** + * @see org.alfresco.repo.content.transform.ContentTransformerRegistry + * @see org.alfresco.repo.content.transform.ContentTransformer + */ + public void transform(ContentReader reader, ContentWriter writer) + throws NoTransformerException, ContentIOException + { + // check that source and target mimetypes are available + String sourceMimetype = reader.getMimetype(); + if (sourceMimetype == null) + { + throw new AlfrescoRuntimeException("The content reader mimetype must be set: " + reader); + } + String targetMimetype = writer.getMimetype(); + if (targetMimetype == null) + { + throw new AlfrescoRuntimeException("The content writer mimetype must be set: " + writer); + } + // look for a transformer + ContentTransformer transformer = transformerRegistry.getTransformer(sourceMimetype, targetMimetype); + if (transformer == null) + { + throw new NoTransformerException(sourceMimetype, targetMimetype); + } + // we have a transformer, so do it + transformer.transform(reader, writer); + // done + } + + /** + * @see org.alfresco.repo.content.transform.ContentTransformerRegistry + * @see org.alfresco.repo.content.transform.ContentTransformer + */ + public ContentTransformer getTransformer(String sourceMimetype, String targetMimetype) + { + // look for a transformer + ContentTransformer transformer = transformerRegistry.getTransformer(sourceMimetype, targetMimetype); + // done + return transformer; + } + + /** + * @see org.alfresco.service.cmr.repository.ContentService#getImageTransformer() + */ + public ContentTransformer getImageTransformer() + { + return imageMagickContentTransformer; + } + + /** + * @see org.alfresco.repo.content.transform.ContentTransformerRegistry + * @see org.alfresco.repo.content.transform.ContentTransformer + */ + public boolean isTransformable(ContentReader reader, ContentWriter writer) + { + // check that source and target mimetypes are available + String sourceMimetype = reader.getMimetype(); + if (sourceMimetype == null) + { + throw new AlfrescoRuntimeException("The content reader mimetype must be set: " + reader); + } + String targetMimetype = writer.getMimetype(); + if (targetMimetype == null) + { + throw new AlfrescoRuntimeException("The content writer mimetype must be set: " + writer); + } + + // look for a transformer + ContentTransformer transformer = transformerRegistry.getTransformer(sourceMimetype, targetMimetype); + return (transformer != null); + } + + /** + * Ensures that, upon closure of the output stream, the node is updated with + * the latest URL of the content to which it refers. + *

+ * The listener close operation does not need a transaction as the + * ContentWriter takes care of that. + * + * @author Derek Hulley + */ + private static class WriteStreamListener implements ContentStreamListener + { + private NodeService nodeService; + private NodeRef nodeRef; + private QName propertyQName; + private ContentWriter writer; + + public WriteStreamListener( + NodeService nodeService, + NodeRef nodeRef, + QName propertyQName, + ContentWriter writer) + { + this.nodeService = nodeService; + this.nodeRef = nodeRef; + this.propertyQName = propertyQName; + this.writer = writer; + } + + public void contentStreamClosed() throws ContentIOException + { + try + { + // set the full content property + ContentData contentData = writer.getContentData(); + nodeService.setProperty( + nodeRef, + propertyQName, + contentData); + // done + if (logger.isDebugEnabled()) + { + logger.debug("Stream listener updated node: \n" + + " node: " + nodeRef + "\n" + + " property: " + propertyQName + "\n" + + " value: " + contentData); + } + } + catch (Throwable e) + { + throw new ContentIOException("Failed to set content property on stream closure: \n" + + " node: " + nodeRef + "\n" + + " property: " + propertyQName + "\n" + + " writer: " + writer, + e); + } + } + } +} diff --git a/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java b/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java index 33ebf84479..221ac2b0d9 100644 --- a/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java +++ b/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java @@ -1,249 +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.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); - } - } - } -} +/* + * 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/copy/CopyServiceImpl.java b/source/java/org/alfresco/repo/copy/CopyServiceImpl.java index d9a0f7e59e..34e5436456 100644 --- a/source/java/org/alfresco/repo/copy/CopyServiceImpl.java +++ b/source/java/org/alfresco/repo/copy/CopyServiceImpl.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.i18n.I18NUtil; import org.alfresco.model.ContentModel; import org.alfresco.repo.policy.ClassPolicyDelegate; import org.alfresco.repo.policy.JavaBehaviour; @@ -43,6 +44,7 @@ import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.CopyService; import org.alfresco.service.cmr.repository.CopyServiceException; +import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; @@ -65,8 +67,12 @@ import org.alfresco.util.ParameterCheck; */ public class CopyServiceImpl implements CopyService { + /** I18N labels */ + private String COPY_OF_LABEL = "copy_service.copy_of_label"; + /** The node service */ private NodeService nodeService; + private NodeService internalNodeService; /** The dictionary service*/ private DictionaryService dictionaryService; @@ -99,6 +105,16 @@ public class CopyServiceImpl implements CopyService { this.nodeService = nodeService; } + + /** + * Sets the internal node service + * + * @param internalNodeService the internal node service + */ + public void setInternalNodeService(NodeService internalNodeService) + { + this.internalNodeService = internalNodeService; + } /** * Sets the dictionary service @@ -233,7 +249,32 @@ public class CopyServiceImpl implements CopyService return copy; } - + + public NodeRef copyAndRename(NodeRef sourceNodeRef, NodeRef destinationParent, QName destinationAssocTypeQName, QName destinationQName, boolean copyChildren) + { + // Make a note of the source name and do the copy + String sourceName = (String)this.internalNodeService.getProperty(sourceNodeRef, ContentModel.PROP_NAME); + NodeRef copy = copy(sourceNodeRef, destinationParent, destinationAssocTypeQName, destinationQName, copyChildren); + + // Do the rename, iterating until a non-duplicate name is found + boolean bDone = false; + while (bDone == false) + { + try + { + this.internalNodeService.setProperty(copy, ContentModel.PROP_NAME, sourceName); + bDone = true; + } + catch(DuplicateChildNodeNameException exception) + { + sourceName = I18NUtil.getMessage(COPY_OF_LABEL, sourceName); + } + } + + // Return the copy + return copy; + } + /** * Invokes the copy complete policy for the node reference provided * diff --git a/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java b/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java index 973ff0c827..426d157706 100644 --- a/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java +++ b/source/java/org/alfresco/repo/copy/CopyServiceImplTest.java @@ -104,6 +104,7 @@ public class CopyServiceImplTest extends BaseSpringTest private static final QName TEST_MANDATORY_ASPECT_QNAME = QName.createQName(TEST_TYPE_NAMESPACE, "testMandatoryAspect"); private static final QName PROP5_QNAME_MANDATORY = QName.createQName(TEST_TYPE_NAMESPACE, "prop5Mandatory"); + private static final String TEST_NAME = "testName"; private static final String TEST_VALUE_1 = "testValue1"; private static final String TEST_VALUE_2 = "testValue2"; private static final String TEST_VALUE_3 = "testValue3"; @@ -239,6 +240,7 @@ public class CopyServiceImplTest extends BaseSpringTest private Map createTypePropertyBag() { Map result = new HashMap(); + result.put(ContentModel.PROP_NAME, TEST_NAME); result.put(PROP1_QNAME_MANDATORY, TEST_VALUE_1); result.put(PROP2_QNAME_OPTIONAL, TEST_VALUE_2); result.put(PROP5_QNAME_MANDATORY, TEST_VALUE_3); @@ -624,6 +626,31 @@ public class CopyServiceImplTest extends BaseSpringTest assertNotNull(value); assertEquals(nodeTwoCopy, value); } + + public void testCopyAndRename() + { + // Check a normal copy with no dup restrictions + NodeRef copy = this.copyService.copyAndRename( + this.sourceNodeRef, + this.rootNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQName("{test}copyAssoc"), + false); + checkCopiedNode(this.sourceNodeRef, copy, true, true, false); + assertTrue(TEST_NAME.equals(this.nodeService.getProperty(copy, ContentModel.PROP_NAME))); + + // Create a folder and content node + Map propsFolder = new HashMap(1); + propsFolder.put(ContentModel.PROP_NAME, "tempFolder"); + NodeRef folderNode = this.nodeService.createNode(this.rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{test}tempFolder"), ContentModel.TYPE_FOLDER, propsFolder).getChildRef(); + Map props = new HashMap(1); + props.put(ContentModel.PROP_NAME, TEST_NAME); + NodeRef contentNode = this.nodeService.createNode(folderNode, ContentModel.ASSOC_CONTAINS, QName.createQName("{test}renametest"), ContentModel.TYPE_CONTENT, props).getChildRef(); + + // Now copy the content node with the duplicate name restriction + NodeRef contentCopy = this.copyService.copy(contentNode, folderNode, ContentModel.ASSOC_CONTAINS, QName.createQName("{test}bobbins"), false); + assertFalse(TEST_NAME.equals(this.nodeService.getProperty(contentCopy, ContentModel.PROP_NAME))); + } /** * Check that the copied node contains the state we are expecting diff --git a/source/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java b/source/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java index 158b3fae5b..fc813f1bc4 100644 --- a/source/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java +++ b/source/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java @@ -41,16 +41,12 @@ import org.alfresco.service.license.LicenseService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.AbstractLifecycleBean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.io.Resource; @@ -59,12 +55,10 @@ import org.springframework.core.io.Resource; * * @author David Caruana */ -public class DescriptorServiceImpl implements DescriptorService, ApplicationListener, InitializingBean, ApplicationContextAware, DisposableBean +public class DescriptorServiceImpl extends AbstractLifecycleBean implements DescriptorService, InitializingBean { private static Log logger = LogFactory.getLog(DescriptorServiceImpl.class); - private ApplicationContext applicationContext; - private Properties serverProperties; private ImporterBootstrap systemBootstrap; @@ -78,14 +72,6 @@ public class DescriptorServiceImpl implements DescriptorService, ApplicationList private Descriptor installedRepoDescriptor; - /* (non-Javadoc) - * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) - */ - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException - { - this.applicationContext = applicationContext; - } - /** * Sets the server descriptor from a resource file * @@ -163,36 +149,36 @@ public class DescriptorServiceImpl implements DescriptorService, ApplicationList return (licenseService == null) ? null : licenseService.getLicense(); } - /** - * @param event - */ - public void onApplicationEvent(ApplicationEvent event) + @Override + protected void onBootstrap(ApplicationEvent event) { - if (event instanceof ContextRefreshedEvent) + // initialise the repository descriptor + // note: this requires that the repository schema has already been initialised + TransactionWork createDescriptorWork = new TransactionUtil.TransactionWork() { - // initialise the repository descriptor - // note: this requires that the repository schema has already been initialised - TransactionWork createDescriptorWork = new TransactionUtil.TransactionWork() + public Descriptor doWork() { - public Descriptor doWork() - { - // initialise license service (if installed) - initialiseLicenseService(); - - // verify license, but only if license component is installed - licenseService.verifyLicense(); - - // persist the server descriptor values - updateCurrentRepositoryDescriptor(serverDescriptor); + // initialise license service (if installed) + initialiseLicenseService(); + + // verify license, but only if license component is installed + licenseService.verifyLicense(); + + // persist the server descriptor values + updateCurrentRepositoryDescriptor(serverDescriptor); - // return the repository installed descriptor - return createInstalledRepositoryDescriptor(); - } - }; - installedRepoDescriptor = TransactionUtil.executeInUserTransaction(transactionService, createDescriptorWork); - } + // return the repository installed descriptor + return createInstalledRepositoryDescriptor(); + } + }; + installedRepoDescriptor = TransactionUtil.executeInUserTransaction(transactionService, createDescriptorWork); } + @Override + protected void onShutdown(ApplicationEvent event) + { + } + /** * Initialise Descriptors */ @@ -202,13 +188,6 @@ public class DescriptorServiceImpl implements DescriptorService, ApplicationList serverDescriptor = createServerDescriptor(); } - /** - * Destruction hook - */ - public void destroy() throws Exception - { - } - /** * Create server descriptor * @@ -358,7 +337,7 @@ public class DescriptorServiceImpl implements DescriptorService, ApplicationList // be declaratively taken out in an installed environment. Class licenseComponentClass = Class.forName("org.alfresco.license.LicenseComponent"); Constructor constructor = licenseComponentClass.getConstructor(new Class[] { ApplicationContext.class} ); - licenseService = (LicenseService)constructor.newInstance(new Object[] { applicationContext }); + licenseService = (LicenseService)constructor.newInstance(new Object[] { getApplicationContext() }); } catch (ClassNotFoundException e) { @@ -766,4 +745,5 @@ public class DescriptorServiceImpl implements DescriptorService, ApplicationList return serverProperties.getProperty(key, ""); } } + } diff --git a/source/java/org/alfresco/repo/descriptor/DescriptorStartupLog.java b/source/java/org/alfresco/repo/descriptor/DescriptorStartupLog.java index 13d77fff3b..bd802737cc 100644 --- a/source/java/org/alfresco/repo/descriptor/DescriptorStartupLog.java +++ b/source/java/org/alfresco/repo/descriptor/DescriptorStartupLog.java @@ -23,11 +23,10 @@ import java.util.Map; import org.alfresco.service.descriptor.Descriptor; import org.alfresco.service.descriptor.DescriptorService; import org.alfresco.service.license.LicenseDescriptor; +import org.alfresco.util.AbstractLifecycleBean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; /** @@ -35,7 +34,7 @@ import org.springframework.context.event.ContextRefreshedEvent; * * @author davidc */ -public class DescriptorStartupLog implements ApplicationListener +public class DescriptorStartupLog extends AbstractLifecycleBean { // Logger private static final Log logger = LogFactory.getLog(DescriptorService.class); @@ -52,82 +51,6 @@ public class DescriptorStartupLog implements ApplicationListener } - /** - * @param event - */ - public void onApplicationEvent(ApplicationEvent event) - { - if (event instanceof ContextRefreshedEvent) - { - // - // log output of VM stats - // - Map properties = System.getProperties(); - String version = (properties.get("java.runtime.version") == null) ? "unknown" : (String)properties.get("java.runtime.version"); - long maxHeap = Runtime.getRuntime().maxMemory(); - float maxHeapMB = maxHeap / 1024l; - maxHeapMB = maxHeapMB / 1024l; - if (logger.isInfoEnabled()) - { - logger.info(String.format("Alfresco JVM - v%s; maximum heap size %.3fMB", version, maxHeapMB)); - } - if (logger.isWarnEnabled()) - { - if (version.startsWith("1.2") || version.startsWith("1.3") || version.startsWith("1.4")) - { - logger.warn(String.format("Alfresco JVM - WARNING - v1.5 is required; currently using v%s", version)); - } - if (maxHeapMB < 500) - { - logger.warn(String.format("Alfresco JVM - WARNING - maximum heap size %.3fMB is less than recommended 512MB", maxHeapMB)); - } - } - - // Log License Descriptors (if applicable) - LicenseDescriptor license = descriptorService.getLicenseDescriptor(); - if (license != null && logger.isInfoEnabled()) - { - String subject = license.getSubject(); - String msg = "Alfresco license: " + subject; - String holder = getHolderOrganisation(license.getHolder()); - if (holder != null) - { - msg += " granted to " + holder; - } - Date validUntil = license.getValidUntil(); - if (validUntil != null) - { - Integer days = license.getDays(); - Integer remainingDays = license.getRemainingDays(); - - msg += " limited to " + days + " days expiring " + validUntil + " (" + remainingDays + " days remaining)"; - } - else - { - msg += " (does not expire)"; - } - - - logger.info(msg); - } - - // Log Repository Descriptors - if (logger.isInfoEnabled()) - { - Descriptor serverDescriptor = descriptorService.getServerDescriptor(); - Descriptor installedRepoDescriptor = descriptorService.getInstalledRepositoryDescriptor(); - String serverEdition = serverDescriptor.getEdition(); - String serverVersion = serverDescriptor.getVersion(); - int serverSchemaVersion = serverDescriptor.getSchema(); - String installedRepoVersion = installedRepoDescriptor.getVersion(); - int installedSchemaVersion = installedRepoDescriptor.getSchema(); - logger.info(String.format("Alfresco started (%s): Current version %s schema %d - Installed version %s schema %d", - serverEdition, serverVersion, serverSchemaVersion, installedRepoVersion, installedSchemaVersion)); - } - } - } - - /** * Get Organisation from Principal * @@ -156,5 +79,83 @@ public class DescriptorStartupLog implements ApplicationListener return holder; } + + + @Override + protected void onBootstrap(ApplicationEvent event) + { + // + // log output of VM stats + // + Map properties = System.getProperties(); + String version = (properties.get("java.runtime.version") == null) ? "unknown" : (String)properties.get("java.runtime.version"); + long maxHeap = Runtime.getRuntime().maxMemory(); + float maxHeapMB = maxHeap / 1024l; + maxHeapMB = maxHeapMB / 1024l; + if (logger.isInfoEnabled()) + { + logger.info(String.format("Alfresco JVM - v%s; maximum heap size %.3fMB", version, maxHeapMB)); + } + if (logger.isWarnEnabled()) + { + if (version.startsWith("1.2") || version.startsWith("1.3") || version.startsWith("1.4")) + { + logger.warn(String.format("Alfresco JVM - WARNING - v1.5 is required; currently using v%s", version)); + } + if (maxHeapMB < 500) + { + logger.warn(String.format("Alfresco JVM - WARNING - maximum heap size %.3fMB is less than recommended 512MB", maxHeapMB)); + } + } + + // Log License Descriptors (if applicable) + LicenseDescriptor license = descriptorService.getLicenseDescriptor(); + if (license != null && logger.isInfoEnabled()) + { + String subject = license.getSubject(); + String msg = "Alfresco license: " + subject; + String holder = getHolderOrganisation(license.getHolder()); + if (holder != null) + { + msg += " granted to " + holder; + } + Date validUntil = license.getValidUntil(); + if (validUntil != null) + { + Integer days = license.getDays(); + Integer remainingDays = license.getRemainingDays(); + + msg += " limited to " + days + " days expiring " + validUntil + " (" + remainingDays + " days remaining)"; + } + else + { + msg += " (does not expire)"; + } + + + logger.info(msg); + } + + // Log Repository Descriptors + if (logger.isInfoEnabled()) + { + Descriptor serverDescriptor = descriptorService.getServerDescriptor(); + Descriptor installedRepoDescriptor = descriptorService.getInstalledRepositoryDescriptor(); + String serverEdition = serverDescriptor.getEdition(); + String serverVersion = serverDescriptor.getVersion(); + int serverSchemaVersion = serverDescriptor.getSchema(); + String installedRepoVersion = installedRepoDescriptor.getVersion(); + int installedSchemaVersion = installedRepoDescriptor.getSchema(); + logger.info(String.format("Alfresco started (%s): Current version %s schema %d - Installed version %s schema %d", + serverEdition, serverVersion, serverSchemaVersion, installedRepoVersion, installedSchemaVersion)); + } + } + + + @Override + protected void onShutdown(ApplicationEvent event) + { + // NOOP + } } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryDAOTest.java b/source/java/org/alfresco/repo/dictionary/DictionaryDAOTest.java index 4b5430ac50..a1e4d7da6f 100644 --- a/source/java/org/alfresco/repo/dictionary/DictionaryDAOTest.java +++ b/source/java/org/alfresco/repo/dictionary/DictionaryDAOTest.java @@ -16,6 +16,7 @@ */ package org.alfresco.repo.dictionary; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -274,5 +275,26 @@ public class DictionaryDAOTest extends TestCase assertFalse(test5); } - + + public void testPropertyOverride() + { + TypeDefinition type1 = service.getType(QName.createQName(TEST_URL, "overridetype1")); + Map props1 = type1.getProperties(); + PropertyDefinition prop1 = props1.get(QName.createQName(TEST_URL, "propoverride")); + String def1 = prop1.getDefaultValue(); + assertEquals("one", def1); + + TypeDefinition type2 = service.getType(QName.createQName(TEST_URL, "overridetype2")); + Map props2 = type2.getProperties(); + PropertyDefinition prop2 = props2.get(QName.createQName(TEST_URL, "propoverride")); + String def2 = prop2.getDefaultValue(); + assertEquals("two", def2); + + TypeDefinition type3 = service.getType(QName.createQName(TEST_URL, "overridetype3")); + Map props3 = type3.getProperties(); + PropertyDefinition prop3 = props3.get(QName.createQName(TEST_URL, "propoverride")); + String def3 = prop3.getDefaultValue(); + assertEquals("three", def3); + } + } diff --git a/source/java/org/alfresco/repo/dictionary/TestModel.java b/source/java/org/alfresco/repo/dictionary/TestModel.java index d2bcb4be54..240be4ce7b 100644 --- a/source/java/org/alfresco/repo/dictionary/TestModel.java +++ b/source/java/org/alfresco/repo/dictionary/TestModel.java @@ -43,6 +43,8 @@ public class TestModel bootstrapModels.add("alfresco/model/systemModel.xml"); bootstrapModels.add("alfresco/model/contentModel.xml"); bootstrapModels.add("alfresco/model/applicationModel.xml"); + bootstrapModels.add("alfresco/model/bpmModel.xml"); + bootstrapModels.add("alfresco/workflow/workflowModel.xml"); // include models specified on command line for (String arg: args) diff --git a/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml b/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml index ba51937ef7..500c04df53 100644 --- a/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml +++ b/source/java/org/alfresco/repo/dictionary/dictionarydaotest_model.xml @@ -188,6 +188,33 @@ + + + + d:text + one + + + + + + test:overridetype1 + + + two + + + + + + test:overridetype2 + + + three + + + + diff --git a/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java b/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java index 4a830a42f1..679588c6ca 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/ChildAssocImpl.java @@ -25,7 +25,6 @@ import org.alfresco.repo.domain.ChildAssoc; import org.alfresco.repo.domain.Node; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.namespace.QName; -import org.alfresco.util.EqualsHelper; /** * @author Derek Hulley @@ -124,9 +123,12 @@ public class ChildAssocImpl implements ChildAssoc, Serializable { StringBuffer sb = new StringBuffer(32); sb.append("ChildAssoc") - .append("[ parent=").append(parent) - .append(", child=").append(child) + .append("[ id=").append(id) + .append(", parent=").append(parent.getId()) + .append(", child=").append(child.getId()) + .append(", child name=").append(childNodeName) .append(", child name crc=").append(childNodeNameCrc) + .append(", assoc type=").append(getTypeQName()) .append(", assoc name=").append(getQname()) .append(", isPrimary=").append(isPrimary) .append("]"); diff --git a/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml index c79ac4586d..87d9900356 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml @@ -144,4 +144,14 @@ ace.authority.recipient = :authorityRecipient + + select + entry + from + org.alfresco.repo.domain.hibernate.DbAccessControlEntryImpl entry + where + entry.permission.typeQname = :oldTypeQName and + entry.permission.name = :oldName + + \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/hibernate/PermissionsDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/hibernate/PermissionsDaoComponentImpl.java index 3879739aff..7e2bd5e68e 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/PermissionsDaoComponentImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/PermissionsDaoComponentImpl.java @@ -1,600 +1,600 @@ -/* - * 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.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.alfresco.repo.domain.AccessControlListDAO; -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.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.impl.PermissionsDaoComponent; -import org.alfresco.repo.security.permissions.impl.SimpleNodePermissionEntry; -import org.alfresco.repo.security.permissions.impl.SimplePermissionEntry; -import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; -import org.alfresco.repo.transaction.TransactionalDao; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.security.AccessStatus; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.GUID; -import org.hibernate.Query; -import org.hibernate.Session; -import org.springframework.orm.hibernate3.HibernateCallback; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; - -/** - * Support for accessing persisted permission information. - * - * This class maps between persisted objects and the external API defined in the - * PermissionsDAO interface. - * - * @author andyh - */ -public class PermissionsDaoComponentImpl extends HibernateDaoSupport implements PermissionsDaoComponent, TransactionalDao -{ - private static final boolean INHERIT_PERMISSIONS_DEFAULT = true; - public static final String QUERY_GET_PERMISSION = "permission.GetPermission"; - public static final String QUERY_GET_AC_ENTRIES_FOR_AUTHORITY = "permission.GetAccessControlEntriesForAuthority"; - public static final String QUERY_GET_AC_ENTRIES_FOR_PERMISSION = "permission.GetAccessControlEntriesForPermission"; - - private Map fProtocolToACLDAO; - - private AccessControlListDAO fDefaultACLDAO; - - /** a uuid identifying this unique instance */ - private String uuid; - - /** - * - */ - public PermissionsDaoComponentImpl() - { - this.uuid = GUID.generate(); - } - - /** - * Checks equality by type and uuid - */ - public boolean equals(Object obj) - { - if (obj == null) - { - return false; - } - else if (!(obj instanceof PermissionsDaoComponentImpl)) - { - return false; - } - PermissionsDaoComponentImpl that = (PermissionsDaoComponentImpl) obj; - return this.uuid.equals(that.uuid); - } - - /** - * @see #uuid - */ - public int hashCode() - { - return uuid.hashCode(); - } - - /** - * Does this Session contain any changes which must be - * synchronized with the store? - * - * @return true => changes are pending - */ - public boolean isDirty() - { - // create a callback for the task - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - return session.isDirty(); - } - }; - // execute the callback - return ((Boolean)getHibernateTemplate().execute(callback)).booleanValue(); - } - - /** - * Just flushes the session - */ - public void flush() - { - getSession().flush(); - } - - public void setProtocolToACLDAO(Map map) - { - fProtocolToACLDAO = map; - } - - public void setDefaultACLDAO(AccessControlListDAO defaultACLDAO) - { - fDefaultACLDAO = defaultACLDAO; - } - - public NodePermissionEntry getPermissions(NodeRef nodeRef) - { - // Create the object if it is not found. - // Null objects are not cached in hibernate - // If the object does not exist it will repeatedly query to check its - // non existence. - NodePermissionEntry npe = null; - DbAccessControlList acl = null; - try - { - acl = getAccessControlList(nodeRef, false); - } - catch (InvalidNodeRefException e) - { - // Do nothing. - } - if (acl == null) - { - // there isn't an access control list for the node - spoof a null one - SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry( - nodeRef, - true, - Collections. emptySet()); - npe = snpe; - } - else - { - npe = createSimpleNodePermissionEntry(nodeRef); - } - // done - if (logger.isDebugEnabled()) - { - logger.debug( - "Created access control list for node: \n" + - " node: " + nodeRef + "\n" + - " acl: " + npe); - } - return npe; - } - - /** - * Get the persisted access control list or create it if required. - * - * @param nodeRef - the node for which to create the list - * @param create - create the object if it is missing - * @return Returns the current access control list or null if not found - */ - private DbAccessControlList getAccessControlList(NodeRef nodeRef, boolean create) - { - DbAccessControlList acl = - getACLDAO(nodeRef).getAccessControlList(nodeRef); - if (acl == null && create) - { - acl = createAccessControlList(nodeRef); - } - // done - if (logger.isDebugEnabled()) - { - logger.debug("Retrieved access control list: \n" + - " node: " + nodeRef + "\n" + - " list: " + acl); - } - return acl; - } - - /** - * Creates an access control list for the node and removes the entry from - * the nullPermsionCache. - */ - private DbAccessControlList createAccessControlList(NodeRef nodeRef) - { - DbAccessControlList acl = new DbAccessControlListImpl(); - acl.setInherits(INHERIT_PERMISSIONS_DEFAULT); - getHibernateTemplate().save(acl); - - // maintain inverse - getACLDAO(nodeRef).setAccessControlList(nodeRef, acl); - - // done - if (logger.isDebugEnabled()) - { - logger.debug("Created Access Control List: \n" + - " node: " + nodeRef + "\n" + - " list: " + acl); - } - return acl; - } - - public void deletePermissions(NodeRef nodeRef) - { - DbAccessControlList acl = null; - try - { - acl = getAccessControlList(nodeRef, false); - } - catch (InvalidNodeRefException e) - { - return; - } - if (acl != null) - { - // maintain referencial integrity - getACLDAO(nodeRef).setAccessControlList(nodeRef, null); - // delete the access control list - it will cascade to the entries - getHibernateTemplate().delete(acl); - } - } - - @SuppressWarnings("unchecked") - public void deletePermissions(final String authority) - { - // get the authority - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(QUERY_GET_AC_ENTRIES_FOR_AUTHORITY) - .setString("authorityRecipient", authority); - return (Integer) HibernateHelper.deleteDbAccessControlEntries(session, query); - } - }; - Integer deletedCount = (Integer) getHibernateTemplate().execute(callback); - // done - if (logger.isDebugEnabled()) - { - logger.debug("Deleted " + deletedCount + " entries for authority " + authority); - } - } - - public void deletePermissions(final NodeRef nodeRef, final String authority) - { - DbAccessControlList acl = null; - try - { - acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); - } - catch (InvalidNodeRefException e) - { - return; - } - int deletedCount = 0; - if (acl != null) - { - deletedCount = acl.deleteEntriesForAuthority(authority); - } - // done - if (logger.isDebugEnabled()) - { - logger.debug("Deleted " + deletedCount + "entries for criteria: \n" + - " node: " + nodeRef + "\n" + - " authority: " + authority); - } - } - - /** - * Deletes all permission entries (access control list entries) that match - * the given criteria. Note that the access control list for the node is - * not deleted. - */ - public void deletePermission(NodeRef nodeRef, String authority, PermissionReference permission) - { - DbAccessControlList acl = null; - try - { - acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); - } - catch (InvalidNodeRefException e) - { - return; - } - int deletedCount = 0; - if (acl != null) - { - DbPermissionKey permissionKey = new DbPermissionKey(permission.getQName(), permission.getName()); - deletedCount = acl.deleteEntry(authority, permissionKey); - } - // done - if (logger.isDebugEnabled()) - { - logger.debug("Deleted " + deletedCount + "entries for criteria: \n" + - " node: " + nodeRef + "\n" + - " permission: " + permission + "\n" + - " authority: " + authority); - } - } - - public void setPermission(NodeRef nodeRef, String authority, PermissionReference permission, boolean allow) - { - // get the entry - DbAccessControlEntry entry = getAccessControlEntry(nodeRef, authority, permission); - if (entry == null) - { - // need to create it - DbAccessControlList dbAccessControlList = getAccessControlList(nodeRef, true); - DbPermission dbPermission = getPermission(permission, true); - DbAuthority dbAuthority = getAuthority(authority, true); - // set persistent objects - entry = dbAccessControlList.newEntry(dbPermission, dbAuthority, allow); - // done - if (logger.isDebugEnabled()) - { - logger.debug("Created new access control entry: " + entry); - } - } - else - { - entry.setAllowed(allow); - // done - if (logger.isDebugEnabled()) - { - logger.debug("Updated access control entry: " + entry); - } - } - } - - /** - * @param nodeRef the node against which to join - * @param authority the authority against which to join - * @param perm the permission against which to join - * @return Returns all access control entries that match the criteria - */ - private DbAccessControlEntry getAccessControlEntry( - NodeRef nodeRef, - String authority, - PermissionReference permission) - { - DbAccessControlList acl = getAccessControlList(nodeRef, false); - DbAccessControlEntry entry = null; - if (acl != null) - { - DbPermissionKey permissionKey = new DbPermissionKey(permission.getQName(), permission.getName()); - entry = acl.getEntry(authority, permissionKey); - } - // done - if (logger.isDebugEnabled()) - { - logger.debug("" + (entry == null ? "Did not find" : "Found") + " entry for criteria: \n" + - " node: " + nodeRef + "\n" + - " authority: " + authority + "\n" + - " permission: " + permission); - } - return entry; - } - - /** - * Utility method to find or create a persisted authority - */ - private DbAuthority getAuthority(String authority, boolean create) - { - DbAuthority entity = (DbAuthority) getHibernateTemplate().get(DbAuthorityImpl.class, authority); - if ((entity == null) && create) - { - entity = new DbAuthorityImpl(); - entity.setRecipient(authority); - getHibernateTemplate().save(entity); - return entity; - } - else - { - return entity; - } - } - - /** - * Utility method to find and optionally create a persisted permission. - */ - private DbPermission getPermission(PermissionReference permissionRef, final boolean create) - { - final QName qname = permissionRef.getQName(); - final String name = permissionRef.getName(); - Session session = getSession(); - - DbPermission dbPermission = DbPermissionImpl.find(session, qname, name); - - // create if necessary - if ((dbPermission == null) && create) - { - dbPermission = new DbPermissionImpl(); - dbPermission.setTypeQname(qname); - dbPermission.setName(name); - getHibernateTemplate().save(dbPermission); - } - return dbPermission; - } - - public void setPermission(PermissionEntry permissionEntry) - { - setPermission( - permissionEntry.getNodeRef(), - permissionEntry.getAuthority(), - permissionEntry.getPermissionReference(), - permissionEntry.isAllowed()); - } - - public void setPermission(NodePermissionEntry nodePermissionEntry) - { - NodeRef nodeRef = nodePermissionEntry.getNodeRef(); - - // Get the access control list - // Note the logic here requires to know whether it was created or not - DbAccessControlList acl = getAccessControlList(nodeRef, false); - if (acl != null) - { - // maintain referencial integrity - getACLDAO(nodeRef).setAccessControlList(nodeRef, null); - // drop the list - getHibernateTemplate().delete(acl); - } - // create the access control list - acl = createAccessControlList(nodeRef); - - // set attributes - acl.setInherits(nodePermissionEntry.inheritPermissions()); - - // add all entries - for (PermissionEntry pe : nodePermissionEntry.getPermissionEntries()) - { - PermissionReference permission = pe.getPermissionReference(); - String authority = pe.getAuthority(); - boolean isAllowed = pe.isAllowed(); - - DbPermission permissionEntity = getPermission(permission, true); - DbAuthority authorityEntity = getAuthority(authority, true); - - @SuppressWarnings("unused") - DbAccessControlEntryImpl entry = acl.newEntry(permissionEntity, authorityEntity, isAllowed); - } - } - - public void setInheritParentPermissions(NodeRef nodeRef, boolean inheritParentPermissions) - { - DbAccessControlList acl = null; - if (!inheritParentPermissions) - { - // Inheritance == true is the default, so only force a create of the ACL if the value false - acl = getAccessControlList(nodeRef, true); - acl.setInherits(false); - } - else - { - acl = getAccessControlList(nodeRef, false); - if (acl != null) - { - acl.setInherits(true); - } - } - } - - public boolean getInheritParentPermissions(NodeRef nodeRef) - { - DbAccessControlList acl = null; - try - { - acl = getAccessControlList(nodeRef, false); - } - catch (InvalidNodeRefException e) - { - return INHERIT_PERMISSIONS_DEFAULT; - } - if (acl == null) - { - return true; - } - else - { - return acl.getInherits(); - } - } - - // Utility methods to create simple detached objects for the outside world - // We do not pass out the hibernate objects - - private SimpleNodePermissionEntry createSimpleNodePermissionEntry(NodeRef nodeRef) - { - DbAccessControlList acl = - getACLDAO(nodeRef).getAccessControlList(nodeRef); - if (acl == null) - { - // there isn't an access control list for the node - spoof a null one - SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry( - nodeRef, - true, - Collections. emptySet()); - return snpe; - } - else - { - Set entries = acl.getEntries(); - SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry( - nodeRef, - acl.getInherits(), - createSimplePermissionEntries(nodeRef, entries)); - return snpe; - } - } - - /** - * @param entries access control entries - * @return Returns a unique set of entries that can be given back to the outside world - */ - private Set createSimplePermissionEntries(NodeRef nodeRef, - Collection entries) - { - if (entries == null) - { - return null; - } - HashSet spes = new HashSet(entries.size(), 1.0f); - if (entries.size() != 0) - { - for (DbAccessControlEntry entry : entries) - { - spes.add(createSimplePermissionEntry(nodeRef, entry)); - } - } - return spes; - } - - private static SimplePermissionEntry createSimplePermissionEntry(NodeRef nodeRef, - DbAccessControlEntry ace) - { - if (ace == null) - { - return null; - } - return new SimplePermissionEntry( - nodeRef, - createSimplePermissionReference(ace.getPermission()), - ace.getAuthority().getRecipient(), - ace.isAllowed() ? AccessStatus.ALLOWED : AccessStatus.DENIED); - } - - private static SimplePermissionReference createSimplePermissionReference(DbPermission perm) - { - if (perm == null) - { - return null; - } - return new SimplePermissionReference( - perm.getTypeQname(), - perm.getName()); - } - - /** - * Helper to choose appropriate NodeService for the given NodeRef - * @param nodeRef The NodeRef to dispatch from. - * @return The appropriate NodeService. - */ - private AccessControlListDAO getACLDAO(NodeRef nodeRef) - { - AccessControlListDAO ret = fProtocolToACLDAO.get(nodeRef.getStoreRef().getProtocol()); - if (ret == null) - { - return fDefaultACLDAO; - } - return ret; - } -} +/* + * 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.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.domain.AccessControlListDAO; +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.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.impl.PermissionsDaoComponent; +import org.alfresco.repo.security.permissions.impl.SimpleNodePermissionEntry; +import org.alfresco.repo.security.permissions.impl.SimplePermissionEntry; +import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; +import org.alfresco.repo.transaction.TransactionalDao; +import org.alfresco.service.cmr.repository.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.GUID; +import org.hibernate.Query; +import org.hibernate.Session; +import org.springframework.orm.hibernate3.HibernateCallback; +import org.springframework.orm.hibernate3.support.HibernateDaoSupport; + +/** + * Support for accessing persisted permission information. + * + * This class maps between persisted objects and the external API defined in the + * PermissionsDAO interface. + * + * @author andyh + */ +public class PermissionsDaoComponentImpl extends HibernateDaoSupport implements PermissionsDaoComponent, TransactionalDao +{ + private static final boolean INHERIT_PERMISSIONS_DEFAULT = true; + public static final String QUERY_GET_PERMISSION = "permission.GetPermission"; + public static final String QUERY_GET_AC_ENTRIES_FOR_AUTHORITY = "permission.GetAccessControlEntriesForAuthority"; + public static final String QUERY_GET_AC_ENTRIES_FOR_PERMISSION = "permission.GetAccessControlEntriesForPermission"; + + private Map fProtocolToACLDAO; + + private AccessControlListDAO fDefaultACLDAO; + + /** a uuid identifying this unique instance */ + private String uuid; + + /** + * + */ + public PermissionsDaoComponentImpl() + { + this.uuid = GUID.generate(); + } + + /** + * Checks equality by type and uuid + */ + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + else if (!(obj instanceof PermissionsDaoComponentImpl)) + { + return false; + } + PermissionsDaoComponentImpl that = (PermissionsDaoComponentImpl) obj; + return this.uuid.equals(that.uuid); + } + + /** + * @see #uuid + */ + public int hashCode() + { + return uuid.hashCode(); + } + + /** + * Does this Session contain any changes which must be + * synchronized with the store? + * + * @return true => changes are pending + */ + public boolean isDirty() + { + // create a callback for the task + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + return session.isDirty(); + } + }; + // execute the callback + return ((Boolean)getHibernateTemplate().execute(callback)).booleanValue(); + } + + /** + * Just flushes the session + */ + public void flush() + { + getSession().flush(); + } + + public void setProtocolToACLDAO(Map map) + { + fProtocolToACLDAO = map; + } + + public void setDefaultACLDAO(AccessControlListDAO defaultACLDAO) + { + fDefaultACLDAO = defaultACLDAO; + } + + public NodePermissionEntry getPermissions(NodeRef nodeRef) + { + // Create the object if it is not found. + // Null objects are not cached in hibernate + // If the object does not exist it will repeatedly query to check its + // non existence. + NodePermissionEntry npe = null; + DbAccessControlList acl = null; + try + { + acl = getAccessControlList(nodeRef, false); + } + catch (InvalidNodeRefException e) + { + // Do nothing. + } + if (acl == null) + { + // there isn't an access control list for the node - spoof a null one + SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry( + nodeRef, + true, + Collections. emptySet()); + npe = snpe; + } + else + { + npe = createSimpleNodePermissionEntry(nodeRef); + } + // done + if (logger.isDebugEnabled()) + { + logger.debug( + "Created access control list for node: \n" + + " node: " + nodeRef + "\n" + + " acl: " + npe); + } + return npe; + } + + /** + * Get the persisted access control list or create it if required. + * + * @param nodeRef - the node for which to create the list + * @param create - create the object if it is missing + * @return Returns the current access control list or null if not found + */ + private DbAccessControlList getAccessControlList(NodeRef nodeRef, boolean create) + { + DbAccessControlList acl = + getACLDAO(nodeRef).getAccessControlList(nodeRef); + if (acl == null && create) + { + acl = createAccessControlList(nodeRef); + } + // done + if (logger.isDebugEnabled()) + { + logger.debug("Retrieved access control list: \n" + + " node: " + nodeRef + "\n" + + " list: " + acl); + } + return acl; + } + + /** + * Creates an access control list for the node and removes the entry from + * the nullPermsionCache. + */ + private DbAccessControlList createAccessControlList(NodeRef nodeRef) + { + DbAccessControlList acl = new DbAccessControlListImpl(); + acl.setInherits(INHERIT_PERMISSIONS_DEFAULT); + getHibernateTemplate().save(acl); + + // maintain inverse + getACLDAO(nodeRef).setAccessControlList(nodeRef, acl); + + // done + if (logger.isDebugEnabled()) + { + logger.debug("Created Access Control List: \n" + + " node: " + nodeRef + "\n" + + " list: " + acl); + } + return acl; + } + + public void deletePermissions(NodeRef nodeRef) + { + DbAccessControlList acl = null; + try + { + acl = getAccessControlList(nodeRef, false); + } + catch (InvalidNodeRefException e) + { + return; + } + if (acl != null) + { + // maintain referencial integrity + getACLDAO(nodeRef).setAccessControlList(nodeRef, null); + // delete the access control list - it will cascade to the entries + getHibernateTemplate().delete(acl); + } + } + + @SuppressWarnings("unchecked") + public void deletePermissions(final String authority) + { + // get the authority + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session + .getNamedQuery(QUERY_GET_AC_ENTRIES_FOR_AUTHORITY) + .setString("authorityRecipient", authority); + return (Integer) HibernateHelper.deleteDbAccessControlEntries(session, query); + } + }; + Integer deletedCount = (Integer) getHibernateTemplate().execute(callback); + // done + if (logger.isDebugEnabled()) + { + logger.debug("Deleted " + deletedCount + " entries for authority " + authority); + } + } + + public void deletePermissions(final NodeRef nodeRef, final String authority) + { + DbAccessControlList acl = null; + try + { + acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); + } + catch (InvalidNodeRefException e) + { + return; + } + int deletedCount = 0; + if (acl != null) + { + deletedCount = acl.deleteEntriesForAuthority(authority); + } + // done + if (logger.isDebugEnabled()) + { + logger.debug("Deleted " + deletedCount + "entries for criteria: \n" + + " node: " + nodeRef + "\n" + + " authority: " + authority); + } + } + + /** + * Deletes all permission entries (access control list entries) that match + * the given criteria. Note that the access control list for the node is + * not deleted. + */ + public void deletePermission(NodeRef nodeRef, String authority, PermissionReference permission) + { + DbAccessControlList acl = null; + try + { + acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); + } + catch (InvalidNodeRefException e) + { + return; + } + int deletedCount = 0; + if (acl != null) + { + DbPermissionKey permissionKey = new DbPermissionKey(permission.getQName(), permission.getName()); + deletedCount = acl.deleteEntry(authority, permissionKey); + } + // done + if (logger.isDebugEnabled()) + { + logger.debug("Deleted " + deletedCount + "entries for criteria: \n" + + " node: " + nodeRef + "\n" + + " permission: " + permission + "\n" + + " authority: " + authority); + } + } + + public void setPermission(NodeRef nodeRef, String authority, PermissionReference permission, boolean allow) + { + // get the entry + DbAccessControlEntry entry = getAccessControlEntry(nodeRef, authority, permission); + if (entry == null) + { + // need to create it + DbAccessControlList dbAccessControlList = getAccessControlList(nodeRef, true); + DbPermission dbPermission = getPermission(permission, true); + DbAuthority dbAuthority = getAuthority(authority, true); + // set persistent objects + entry = dbAccessControlList.newEntry(dbPermission, dbAuthority, allow); + // done + if (logger.isDebugEnabled()) + { + logger.debug("Created new access control entry: " + entry); + } + } + else + { + entry.setAllowed(allow); + // done + if (logger.isDebugEnabled()) + { + logger.debug("Updated access control entry: " + entry); + } + } + } + + /** + * @param nodeRef the node against which to join + * @param authority the authority against which to join + * @param perm the permission against which to join + * @return Returns all access control entries that match the criteria + */ + private DbAccessControlEntry getAccessControlEntry( + NodeRef nodeRef, + String authority, + PermissionReference permission) + { + DbAccessControlList acl = getAccessControlList(nodeRef, false); + DbAccessControlEntry entry = null; + if (acl != null) + { + DbPermissionKey permissionKey = new DbPermissionKey(permission.getQName(), permission.getName()); + entry = acl.getEntry(authority, permissionKey); + } + // done + if (logger.isDebugEnabled()) + { + logger.debug("" + (entry == null ? "Did not find" : "Found") + " entry for criteria: \n" + + " node: " + nodeRef + "\n" + + " authority: " + authority + "\n" + + " permission: " + permission); + } + return entry; + } + + /** + * Utility method to find or create a persisted authority + */ + private DbAuthority getAuthority(String authority, boolean create) + { + DbAuthority entity = (DbAuthority) getHibernateTemplate().get(DbAuthorityImpl.class, authority); + if ((entity == null) && create) + { + entity = new DbAuthorityImpl(); + entity.setRecipient(authority); + getHibernateTemplate().save(entity); + return entity; + } + else + { + return entity; + } + } + + /** + * Utility method to find and optionally create a persisted permission. + */ + private DbPermission getPermission(PermissionReference permissionRef, final boolean create) + { + final QName qname = permissionRef.getQName(); + final String name = permissionRef.getName(); + Session session = getSession(); + + DbPermission dbPermission = DbPermissionImpl.find(session, qname, name); + + // create if necessary + if ((dbPermission == null) && create) + { + dbPermission = new DbPermissionImpl(); + dbPermission.setTypeQname(qname); + dbPermission.setName(name); + getHibernateTemplate().save(dbPermission); + } + return dbPermission; + } + + public void setPermission(PermissionEntry permissionEntry) + { + setPermission( + permissionEntry.getNodeRef(), + permissionEntry.getAuthority(), + permissionEntry.getPermissionReference(), + permissionEntry.isAllowed()); + } + + public void setPermission(NodePermissionEntry nodePermissionEntry) + { + NodeRef nodeRef = nodePermissionEntry.getNodeRef(); + + // Get the access control list + // Note the logic here requires to know whether it was created or not + DbAccessControlList acl = getAccessControlList(nodeRef, false); + if (acl != null) + { + // maintain referencial integrity + getACLDAO(nodeRef).setAccessControlList(nodeRef, null); + // drop the list + getHibernateTemplate().delete(acl); + } + // create the access control list + acl = createAccessControlList(nodeRef); + + // set attributes + acl.setInherits(nodePermissionEntry.inheritPermissions()); + + // add all entries + for (PermissionEntry pe : nodePermissionEntry.getPermissionEntries()) + { + PermissionReference permission = pe.getPermissionReference(); + String authority = pe.getAuthority(); + boolean isAllowed = pe.isAllowed(); + + DbPermission permissionEntity = getPermission(permission, true); + DbAuthority authorityEntity = getAuthority(authority, true); + + @SuppressWarnings("unused") + DbAccessControlEntryImpl entry = acl.newEntry(permissionEntity, authorityEntity, isAllowed); + } + } + + public void setInheritParentPermissions(NodeRef nodeRef, boolean inheritParentPermissions) + { + DbAccessControlList acl = null; + if (!inheritParentPermissions) + { + // Inheritance == true is the default, so only force a create of the ACL if the value false + acl = getAccessControlList(nodeRef, true); + acl.setInherits(false); + } + else + { + acl = getAccessControlList(nodeRef, false); + if (acl != null) + { + acl.setInherits(true); + } + } + } + + public boolean getInheritParentPermissions(NodeRef nodeRef) + { + DbAccessControlList acl = null; + try + { + acl = getAccessControlList(nodeRef, false); + } + catch (InvalidNodeRefException e) + { + return INHERIT_PERMISSIONS_DEFAULT; + } + if (acl == null) + { + return true; + } + else + { + return acl.getInherits(); + } + } + + // Utility methods to create simple detached objects for the outside world + // We do not pass out the hibernate objects + + private SimpleNodePermissionEntry createSimpleNodePermissionEntry(NodeRef nodeRef) + { + DbAccessControlList acl = + getACLDAO(nodeRef).getAccessControlList(nodeRef); + if (acl == null) + { + // there isn't an access control list for the node - spoof a null one + SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry( + nodeRef, + true, + Collections. emptySet()); + return snpe; + } + else + { + Set entries = acl.getEntries(); + SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry( + nodeRef, + acl.getInherits(), + createSimplePermissionEntries(nodeRef, entries)); + return snpe; + } + } + + /** + * @param entries access control entries + * @return Returns a unique set of entries that can be given back to the outside world + */ + private Set createSimplePermissionEntries(NodeRef nodeRef, + Collection entries) + { + if (entries == null) + { + return null; + } + HashSet spes = new HashSet(entries.size(), 1.0f); + if (entries.size() != 0) + { + for (DbAccessControlEntry entry : entries) + { + spes.add(createSimplePermissionEntry(nodeRef, entry)); + } + } + return spes; + } + + private static SimplePermissionEntry createSimplePermissionEntry(NodeRef nodeRef, + DbAccessControlEntry ace) + { + if (ace == null) + { + return null; + } + return new SimplePermissionEntry( + nodeRef, + createSimplePermissionReference(ace.getPermission()), + ace.getAuthority().getRecipient(), + ace.isAllowed() ? AccessStatus.ALLOWED : AccessStatus.DENIED); + } + + private static SimplePermissionReference createSimplePermissionReference(DbPermission perm) + { + if (perm == null) + { + return null; + } + return new SimplePermissionReference( + perm.getTypeQname(), + perm.getName()); + } + + /** + * Helper to choose appropriate NodeService for the given NodeRef + * @param nodeRef The NodeRef to dispatch from. + * @return The appropriate NodeService. + */ + private AccessControlListDAO getACLDAO(NodeRef nodeRef) + { + AccessControlListDAO ret = fProtocolToACLDAO.get(nodeRef.getStoreRef().getProtocol()); + if (ret == null) + { + return fDefaultACLDAO; + } + return ret; + } +} 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 61d3314746..a3c9bad0c9 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/Transaction.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/Transaction.hbm.xml @@ -29,7 +29,7 @@ unique="false" not-null="false" cascade="none" /> - + + + select + max(txn.id) + from + org.alfresco.repo.domain.hibernate.NodeStatusImpl as status + join status.transaction as txn + + select count(txn.id) @@ -90,6 +98,21 @@ ]]> + + :lastTxnId and + server.ipAddress != :serverIpAddress + order by + txn.id + ]]> + + select count(status.key.guid) @@ -98,9 +121,7 @@ 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 + status.node is not null @@ -111,9 +132,7 @@ join status.transaction as txn where txn.id = :txnId and - status.node is null and - status.key.protocol = :protocol and - status.key.identifier = :identifier + status.node is null diff --git a/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java b/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java index 6ab41fa9ff..88ea3cf2ad 100644 --- a/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java +++ b/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java @@ -1,539 +1,627 @@ -/* - * 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) {} - } - } -} +/* + * 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.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +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.repo.content.filestore.FileContentWriter; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.util.AbstractLifecycleBean; +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.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 extends AbstractLifecycleBean +{ + /** 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 MSG_OPTIONAL_STATEMENT_FAILED = "schema.update.msg.optional_statement_failed"; + private static final String ERR_STATEMENT_FAILED = "schema.update.err.statement_failed"; + 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; + } + + 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(); + } + + private static class NoSchemaException extends Exception + { + private static final long serialVersionUID = 5574280159910824660L; + } + + /** + * @return Returns the number of applied patches + */ + private int countAppliedPatches(Connection connection) throws Exception + { + DatabaseMetaData dbMetadata = connection.getMetaData(); + + ResultSet tableRs = dbMetadata.getTables(null, null, "%", null); + boolean newPatchTable = false; + boolean oldPatchTable = false; + try + { + while (tableRs.next()) + { + String tableName = tableRs.getString("TABLE_NAME"); + if (tableName.equalsIgnoreCase("applied_patch")) + { + oldPatchTable = true; + break; + } + else if (tableName.equalsIgnoreCase("alf_applied_patch")) + { + newPatchTable = true; + break; + } + } + } + finally + { + try { tableRs.close(); } catch (Throwable e) {e.printStackTrace(); } + } + + if (newPatchTable) + { + 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; + } + finally + { + try { stmt.close(); } catch (Throwable e) {} + } + } + else if (oldPatchTable) + { + // found the old style table name + Statement 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) {} + } + } + else + { + // The applied patches table is not present + throw new NoSchemaException(); + } + } + + /** + * @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 (NoSchemaException e) + { + create = true; + } + // Get the dialect + final Dialect dialect = Dialect.getDialect(cfg.getProperties()); + String dialectStr = dialect.getClass().getName(); + + 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-" + dialectStr + "-", ".sql"); + dumpSchemaCreate(cfg, tempFile); + executeScriptFile(cfg, connection, tempFile, 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 + { + DatabaseMetadata metadata = new DatabaseMetadata(connection, dialect); + String[] sqls = cfg.generateSchemaUpdateScript(dialect, metadata); + if (sqls.length > 0) + { + tempFile = TempFileProvider.createTempFile("AlfrescoSchemaUpdate-" + dialectStr + "-", ".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) + { + executeScriptFile(cfg, connection, tempFile, 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()); + String dialectStr = dialect.getClass().getName(); + InputStream scriptInputStream = getScriptInputStream(dialect.getClass(), scriptUrl); + // check that it exists + if (scriptInputStream == null) + { + throw AlfrescoRuntimeException.create(ERR_SCRIPT_NOT_FOUND, scriptUrl); + } + // write the script to a temp location for future and failure reference + File tempFile = null; + try + { + tempFile = TempFileProvider.createTempFile("AlfrescoSchemaUpdate-" + dialectStr + "-", ".sql"); + ContentWriter writer = new FileContentWriter(tempFile); + writer.putContent(scriptInputStream); + } + finally + { + try { scriptInputStream.close(); } catch (Throwable e) {} // usually a duplicate close + } + // now execute it + executeScriptFile(cfg, connection, tempFile, 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, + File scriptFile, + String scriptUrl) throws Exception + { + logger.info(I18NUtil.getMessage(MSG_EXECUTING_SCRIPT, scriptUrl)); + + InputStream scriptInputStream = new FileInputStream(scriptFile); + 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; + boolean optional = false; + if (sql.endsWith(";")) + { + sql = sql.substring(0, sql.length() - 1); + execute = true; + optional = false; + } + else if (sql.endsWith(";(optional)")) + { + sql = sql.substring(0, sql.length() - 11); + execute = true; + optional = true; + } + // append to the statement being built up + sb.append(" ").append(sql); + // execute, if required + if (execute) + { + sql = sb.toString(); + executeStatement(connection, sql, optional, line, scriptFile); + sb = new StringBuilder(1024); + } + } + } + finally + { + try { reader.close(); } catch (Throwable e) {} + try { scriptInputStream.close(); } catch (Throwable e) {} + } + } + + /** + * Execute the given SQL statement, absorbing exceptions that we expect during + * schema creation or upgrade. + */ + private void executeStatement(Connection connection, String sql, boolean optional, int line, File file) throws Exception + { + Statement stmt = connection.createStatement(); + try + { + if (logger.isDebugEnabled()) + { + logger.debug("Executing statment: " + sql); + } + stmt.execute(sql); + } + catch (SQLException e) + { + if (optional) + { + // it was marked as optional, so we just ignore it + String msg = I18NUtil.getMessage(MSG_OPTIONAL_STATEMENT_FAILED, sql, e.getMessage(), file.getAbsolutePath(), line); + logger.warn(msg); + } + else + { + String err = I18NUtil.getMessage(ERR_STATEMENT_FAILED, sql, e.getMessage(), file.getAbsolutePath(), line); + logger.error(err); + throw e; + } + } + finally + { + try { stmt.close(); } catch (Throwable e) {} + } + } + + @Override + protected void onBootstrap(ApplicationEvent event) + { + // 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); + } + } + } + + @Override + protected void onShutdown(ApplicationEvent event) + { + // NOOP + } +} diff --git a/source/java/org/alfresco/repo/importer/ImporterBootstrap.java b/source/java/org/alfresco/repo/importer/ImporterBootstrap.java index 12556807e0..60f8e1fcba 100644 --- a/source/java/org/alfresco/repo/importer/ImporterBootstrap.java +++ b/source/java/org/alfresco/repo/importer/ImporterBootstrap.java @@ -25,6 +25,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.UnsupportedEncodingException; +import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Properties; @@ -46,6 +47,7 @@ import org.alfresco.service.cmr.view.Location; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.AbstractLifecycleBean; import org.alfresco.util.TempFileProvider; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -53,8 +55,6 @@ import org.apache.commons.logging.impl.Log4JLogger; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.util.FileCopyUtils; /** @@ -62,7 +62,7 @@ import org.springframework.util.FileCopyUtils; * * @author David Caruana */ -public class ImporterBootstrap implements ApplicationListener +public class ImporterBootstrap extends AbstractLifecycleBean { // View Properties (used in setBootstrapViews) public static final String VIEW_PATH_PROPERTY = "path"; @@ -83,6 +83,7 @@ public class ImporterBootstrap implements ApplicationListener private NodeService nodeService; private ImporterService importerService; private List bootstrapViews; + private List extensionBootstrapViews; private StoreRef storeRef = null; private List mustNotExistStoreUrls = null; private Properties configuration = null; @@ -176,6 +177,20 @@ public class ImporterBootstrap implements ApplicationListener this.bootstrapViews = bootstrapViews; } + /** + * Sets the bootstrap views + * + * @param bootstrapViews + */ + public void addBootstrapViews(List bootstrapViews) + { + if (this.extensionBootstrapViews == null) + { + this.extensionBootstrapViews = new ArrayList(); + } + this.extensionBootstrapViews.addAll(bootstrapViews); + } + /** * Sets the Store Ref to bootstrap into * @@ -348,6 +363,12 @@ public class ImporterBootstrap implements ApplicationListener // bootstrap the store contents if (bootstrapViews != null) { + // add-in any extended views + if (extensionBootstrapViews != null) + { + bootstrapViews.addAll(extensionBootstrapViews); + } + for (Properties bootstrapView : bootstrapViews) { String view = bootstrapView.getProperty(VIEW_LOCATION_VIEW); @@ -643,16 +664,16 @@ public class ImporterBootstrap implements ApplicationListener return true; } - /* - * (non-Javadoc) - * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) - */ - public void onApplicationEvent(ApplicationEvent event) + @Override + protected void onBootstrap(ApplicationEvent event) { - if (event instanceof ContextRefreshedEvent) - { - bootstrap(); - } + bootstrap(); + } + + @Override + protected void onShutdown(ApplicationEvent event) + { + // NOOP } } diff --git a/source/java/org/alfresco/repo/importer/ImporterBootstrapViews.java b/source/java/org/alfresco/repo/importer/ImporterBootstrapViews.java new file mode 100644 index 0000000000..a15f11da30 --- /dev/null +++ b/source/java/org/alfresco/repo/importer/ImporterBootstrapViews.java @@ -0,0 +1,62 @@ +/* + * 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.importer; + +import java.util.List; +import java.util.Properties; + +import org.springframework.beans.factory.InitializingBean; + +/** + * Collection of views to import + * + * @author David Caruana + */ +public class ImporterBootstrapViews implements InitializingBean +{ + // Dependencies + private ImporterBootstrap importer; + private List bootstrapViews; + + + /** + * Sets the importer + * + * @param importer + */ + public void setImporter(ImporterBootstrap importer) + { + this.importer = importer; + } + + /** + * Sets the bootstrap views + * + * @param bootstrapViews + */ + public void setBootstrapViews(List bootstrapViews) + { + this.bootstrapViews = bootstrapViews; + } + + + public void afterPropertiesSet() throws Exception + { + importer.addBootstrapViews(bootstrapViews); + } + +} diff --git a/source/java/org/alfresco/repo/importer/system/SystemExporterImporter.java b/source/java/org/alfresco/repo/importer/system/SystemExporterImporter.java index 20a3271d59..adbc5320ba 100644 --- a/source/java/org/alfresco/repo/importer/system/SystemExporterImporter.java +++ b/source/java/org/alfresco/repo/importer/system/SystemExporterImporter.java @@ -22,7 +22,7 @@ import java.util.List; import org.alfresco.repo.admin.patch.PatchDaoService; import org.alfresco.repo.domain.AppliedPatch; -import org.alfresco.repo.domain.hibernate.VersionCounterDaoComponentImpl; +import org.alfresco.repo.version.common.counter.VersionCounterService; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; @@ -37,7 +37,7 @@ public class SystemExporterImporter // dependencies private NodeService nodeService; private PatchDaoService patchDao; - private VersionCounterDaoComponentImpl versionCounterDao; + private VersionCounterService versionCounterService; public void setNodeService(NodeService nodeService) @@ -50,9 +50,9 @@ public class SystemExporterImporter this.patchDao = patchDaoService; } - public void setVersionDao(VersionCounterDaoComponentImpl versionCounterDao) + public void setVersionCounterService(VersionCounterService versionCounterService) { - this.versionCounterDao = versionCounterDao; + this.versionCounterService = versionCounterService; } @@ -89,7 +89,7 @@ public class SystemExporterImporter for (StoreRef storeRef : storeRefs) { VersionCounterInfo versionCounterInfo = new VersionCounterInfo(); - int versionCount = versionCounterDao.currentVersionNumber(storeRef); + int versionCount = versionCounterService.currentVersionNumber(storeRef); versionCounterInfo.storeRef = storeRef.toString(); versionCounterInfo.count = versionCount; systemInfo.versionCounters.add(versionCounterInfo); @@ -128,7 +128,7 @@ public class SystemExporterImporter for (VersionCounterInfo versionCounterInfo : systemInfo.versionCounters) { StoreRef storeRef = new StoreRef(versionCounterInfo.storeRef); - versionCounterDao.setVersionNumber(storeRef, versionCounterInfo.count); + versionCounterService.setVersionNumber(storeRef, versionCounterInfo.count); } } diff --git a/source/java/org/alfresco/repo/importer/system/SystemInfoBootstrap.java b/source/java/org/alfresco/repo/importer/system/SystemInfoBootstrap.java index e764c2e751..5983a32379 100644 --- a/source/java/org/alfresco/repo/importer/system/SystemInfoBootstrap.java +++ b/source/java/org/alfresco/repo/importer/system/SystemInfoBootstrap.java @@ -26,9 +26,8 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.view.ImporterException; import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.AbstractLifecycleBean; import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; /** @@ -36,7 +35,7 @@ import org.springframework.context.event.ContextRefreshedEvent; * * @author davidc */ -public class SystemInfoBootstrap implements ApplicationListener +public class SystemInfoBootstrap extends AbstractLifecycleBean { // dependencies private TransactionService transactionService; @@ -177,16 +176,16 @@ public class SystemInfoBootstrap implements ApplicationListener return true; } - /* - * (non-Javadoc) - * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) - */ - public void onApplicationEvent(ApplicationEvent event) + @Override + protected void onBootstrap(ApplicationEvent event) { - if (event instanceof ContextRefreshedEvent) - { - bootstrap(); - } + bootstrap(); + } + + @Override + protected void onShutdown(ApplicationEvent event) + { + // NOOP } } diff --git a/source/java/org/alfresco/repo/jscript/Actions.java b/source/java/org/alfresco/repo/jscript/Actions.java index b371b1b5aa..a0f4734e97 100644 --- a/source/java/org/alfresco/repo/jscript/Actions.java +++ b/source/java/org/alfresco/repo/jscript/Actions.java @@ -28,32 +28,31 @@ import org.alfresco.service.cmr.action.ParameterDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.namespace.QName; import org.mozilla.javascript.Scriptable; - +import org.mozilla.javascript.Wrapper; /** * Scripted Action service for describing and executing actions against Nodes. - * + * * @author davidc */ -public final class Actions implements Scopeable +public final class Actions extends BaseScriptImplementation implements Scopeable { /** Repository Service Registry */ private ServiceRegistry services; - + /** Root scope for this object */ private Scriptable scope; - /** - * Constructor + * Set the service registry * - * @param services repository service registry + * @param serviceRegistry the service registry */ - public Actions(ServiceRegistry services) + public void setServiceRegistry(ServiceRegistry serviceRegistry) { - this.services = services; + this.services = serviceRegistry; } - + /** * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) */ @@ -65,7 +64,7 @@ public final class Actions implements Scopeable /** * Gets the list of registered action names * - * @return the registered action names + * @return the registered action names */ public String[] getRegistered() { @@ -79,17 +78,18 @@ public final class Actions implements Scopeable } return registered; } - + public String[] jsGet_registered() { return getRegistered(); } - + /** * Create an Action * - * @param actionName the action name - * @return the action + * @param actionName + * the action name + * @return the action */ public ScriptAction create(String actionName) { @@ -104,8 +104,7 @@ public final class Actions implements Scopeable } return scriptAction; } - - + /** * Scriptable Action * @@ -114,23 +113,25 @@ public final class Actions implements Scopeable public final class ScriptAction implements Serializable, Scopeable { private static final long serialVersionUID = 5794161358406531996L; - + /** Root scope for this object */ - private Scriptable scope; + private Scriptable scope; /** Converter with knowledge of action parameter values */ private ActionValueConverter converter; - + /** Action state */ private Action action; + private ActionDefinition actionDef; + private ScriptableParameterMap parameters = null; - - + /** * Construct * - * @param action Alfresco action + * @param action + * Alfresco action */ public ScriptAction(Action action, ActionDefinition actionDef) { @@ -138,7 +139,7 @@ public final class Actions implements Scopeable this.actionDef = actionDef; this.converter = new ActionValueConverter(); } - + /** * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) */ @@ -146,28 +147,25 @@ public final class Actions implements Scopeable { this.scope = scope; } - + /** * Returns the action name * - * @return action name + * @return action name */ public String getName() { return this.actionDef.getName(); } - + public String jsGet_name() { return getName(); } - + /** - * Return all the properties known about this node. - * - * The Map returned implements the Scriptable interface to allow access to the properties via - * JavaScript associative array access. This means properties of a node can be access thus: - * node.properties["name"] + * Return all the properties known about this node. The Map returned implements the Scriptable interface to allow access to the properties via JavaScript associative array + * access. This means properties of a node can be access thus: node.properties["name"] * * @return Map of properties for this Node. */ @@ -187,17 +185,18 @@ public final class Actions implements Scopeable this.parameters.setModified(false); } return this.parameters; - } - + } + public Map jsGet_parameters() { return getParameters(); } - + /** * Execute action * - * @param node the node to execute action upon + * @param node + * the node to execute action upon */ @SuppressWarnings("synthetic-access") public void execute(Node node) @@ -206,7 +205,7 @@ public final class Actions implements Scopeable { Map actionParams = action.getParameterValues(); actionParams.clear(); - + for (Map.Entry entry : this.parameters.entrySet()) { // perform the conversion from script wrapper object to repo serializable values @@ -216,8 +215,11 @@ public final class Actions implements Scopeable } } services.getActionService().executeAction(action, node.getNodeRef()); + + // Reset the actioned upon node + node.reset(); } - + /** * Value converter with specific knowledge of action parameters * @@ -227,10 +229,12 @@ public final class Actions implements Scopeable { /** * Convert Action Parameter for Script usage - * - * @param paramName parameter name - * @param value value to convert - * @return converted value + * + * @param paramName + * parameter name + * @param value + * value to convert + * @return converted value */ @SuppressWarnings("synthetic-access") public Serializable convertActionParamForScript(String paramName, Serializable value) @@ -238,7 +242,7 @@ public final class Actions implements Scopeable ParameterDefinition paramDef = actionDef.getParameterDefintion(paramName); if (paramDef != null && paramDef.getType().equals(DataTypeDefinition.QNAME)) { - return ((QName)value).toPrefixString(services.getNamespaceService()); + return ((QName) value).toPrefixString(services.getNamespaceService()); } else { @@ -249,17 +253,45 @@ public final class Actions implements Scopeable /** * Convert Action Parameter for Java usage * - * @param paramName parameter name - * @param value value to convert - * @return converted value + * @param paramName + * parameter name + * @param value + * value to convert + * @return converted value */ @SuppressWarnings("synthetic-access") public Serializable convertActionParamForRepo(String paramName, Serializable value) { ParameterDefinition paramDef = actionDef.getParameterDefintion(paramName); + if (paramDef != null && paramDef.getType().equals(DataTypeDefinition.QNAME)) { - return QName.createQName((String)value, services.getNamespaceService()); + if (value instanceof Wrapper) + { + // unwrap a Java object from a JavaScript wrapper + // recursively call this method to convert the unwrapped value + return convertActionParamForRepo(paramName, (Serializable) ((Wrapper) value).unwrap()); + } + else + { + if (value instanceof String) + { + String stringQName = (String) value; + if (stringQName.startsWith("{")) + { + return QName.createQName(stringQName); + + } + else + { + return QName.createQName(stringQName, services.getNamespaceService()); + } + } + else + { + return value; + } + } } else { @@ -269,39 +301,41 @@ public final class Actions implements Scopeable } } - /** * Scripted Parameter map with modified flag. - * + * * @author davidc */ - public static final class ScriptableParameterMap extends ScriptableHashMap + public static final class ScriptableParameterMap extends ScriptableHashMap { private static final long serialVersionUID = 574661815973241554L; - private boolean modified = false; + private boolean modified = false; /** * Is this a modified parameter map? * - * @return true => modified + * @return true => modified */ - /*package*/ boolean isModified() + /* package */boolean isModified() { return modified; } - + /** * Set explicitly whether this map is modified * - * @param modified true => modified, false => not modified + * @param modified + * true => modified, false => not modified */ - /*package*/ void setModified(boolean modified) + /* package */void setModified(boolean modified) { this.modified = modified; } - - /* (non-Javadoc) + + /* + * (non-Javadoc) + * * @see org.mozilla.javascript.Scriptable#getClassName() */ @Override @@ -310,7 +344,9 @@ public final class Actions implements Scopeable return "ScriptableParameterMap"; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.mozilla.javascript.Scriptable#delete(java.lang.String) */ @Override @@ -320,7 +356,9 @@ public final class Actions implements Scopeable setModified(true); } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.mozilla.javascript.Scriptable#put(java.lang.String, org.mozilla.javascript.Scriptable, java.lang.Object) */ @Override @@ -330,5 +368,5 @@ public final class Actions implements Scopeable setModified(true); } } - + } diff --git a/source/java/org/alfresco/repo/jscript/BaseScriptImplementation.java b/source/java/org/alfresco/repo/jscript/BaseScriptImplementation.java new file mode 100644 index 0000000000..3183d2f16d --- /dev/null +++ b/source/java/org/alfresco/repo/jscript/BaseScriptImplementation.java @@ -0,0 +1,57 @@ +/** + * + */ +package org.alfresco.repo.jscript; + +import org.alfresco.service.cmr.repository.ScriptImplementation; +import org.alfresco.service.cmr.repository.ScriptService; + +/** + * Abstract base class for a script implementation + * + * @author Roy Wetherall + */ +public abstract class BaseScriptImplementation implements ScriptImplementation +{ + /** The script service */ + private ScriptService scriptService; + + /** The name of the script */ + private String scriptName; + + /** + * Sets the script service + * + * @param scriptService the script service + */ + public void setScriptService(ScriptService scriptService) + { + this.scriptService = scriptService; + } + + /** + * Registers this script with the script service + */ + public void register() + { + this.scriptService.registerScript(this); + } + + /** + * Sets the script name + * + * @param scriptName the script name + */ + public void setScriptName(String scriptName) + { + this.scriptName = scriptName; + } + + /** + * @see org.alfresco.service.cmr.repository.ScriptImplementation#getScriptName() + */ + public String getScriptName() + { + return this.scriptName; + } +} diff --git a/source/java/org/alfresco/repo/jscript/CategoryNode.java b/source/java/org/alfresco/repo/jscript/CategoryNode.java new file mode 100644 index 0000000000..a22183ba61 --- /dev/null +++ b/source/java/org/alfresco/repo/jscript/CategoryNode.java @@ -0,0 +1,206 @@ +/* + * 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.jscript; + +import java.util.Collection; + +import org.alfresco.model.ContentModel; +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.TemplateImageResolver; +import org.alfresco.service.cmr.search.CategoryService; +import org.alfresco.service.namespace.QName; +import org.mozilla.javascript.Scriptable; + +/** + * Category Nodes from the classification helper have special support. + * + * @author Andy Hind + */ +public class CategoryNode extends Node +{ + /** + * Constructor + * + * @param nodeRef + * @param services + * @param resolver + */ + public CategoryNode(NodeRef nodeRef, ServiceRegistry services, TemplateImageResolver resolver) + { + super(nodeRef, services, resolver); + } + + /** + * Constructor + * + * @param nodeRef + * @param services + * @param resolver + * @param scope + */ + public CategoryNode(NodeRef nodeRef, ServiceRegistry services, TemplateImageResolver resolver, Scriptable scope) + { + super(nodeRef, services, resolver, scope); + } + + /** + * @return all the members of a category + */ + public Node[] getCategoryMembers() + { + return buildNodes(services.getCategoryService().getChildren(getNodeRef(), CategoryService.Mode.MEMBERS, CategoryService.Depth.ANY)); + } + + public Node[] jsGet_categoryMembers() + { + return getCategoryMembers(); + } + + /** + * @return all the subcategories of a category + */ + public CategoryNode[] getSubCategories() + { + return buildCategoryNodes(services.getCategoryService().getChildren(getNodeRef(), CategoryService.Mode.SUB_CATEGORIES, CategoryService.Depth.ANY)); + } + + public CategoryNode[] jsGet_subCategories() + { + return getSubCategories(); + } + + /** + * @return members and subcategories of a category + */ + public Node[] getMembersAndSubCategories() + { + return buildMixedNodes(services.getCategoryService().getChildren(getNodeRef(), CategoryService.Mode.ALL, CategoryService.Depth.ANY)); + } + + public Node[] jsGet_membersAndSubCategories() + { + return getMembersAndSubCategories(); + } + + /** + * @return all the immediate member of a category + */ + public Node[] getImmediateCategoryMembers() + { + return buildNodes(services.getCategoryService().getChildren(getNodeRef(), CategoryService.Mode.MEMBERS, CategoryService.Depth.IMMEDIATE)); + } + + public Node[] jsGet_immediateCategoryMembers() + { + return getImmediateCategoryMembers(); + } + + /** + * @return all the immediate subcategories of a category + */ + public CategoryNode[] getImmediateSubCategories() + { + return buildCategoryNodes(services.getCategoryService().getChildren(getNodeRef(), CategoryService.Mode.SUB_CATEGORIES, CategoryService.Depth.IMMEDIATE)); + } + + public CategoryNode[] jsGet_immediateSubCategories() + { + return getImmediateSubCategories(); + } + + /** + * @return immediate members and subcategories of a category + */ + public Node[] getImmediateMembersAndSubCategories() + { + return buildMixedNodes(services.getCategoryService().getChildren(getNodeRef(), CategoryService.Mode.ALL, CategoryService.Depth.IMMEDIATE)); + } + + public Node[] jsGet_immediateMembersAndSubCategories() + { + return getImmediateMembersAndSubCategories(); + } + + /** + * Create a new subcategory + * + * @param name Of the category to create + * + * @return CategoryNode + */ + public CategoryNode createSubCategory(String name) + { + return new CategoryNode(services.getCategoryService().createCategory(getNodeRef(), name), this.services, this.imageResolver, this.scope); + } + + /** + * Remove this category + */ + public void removeCategory() + { + services.getCategoryService().deleteCategory(getNodeRef()); + } + + @Override + public boolean getIsCategory() + { + return true; + } + + private CategoryNode[] buildCategoryNodes(Collection cars) + { + CategoryNode[] categoryNodes = new CategoryNode[cars.size()]; + int i = 0; + for (ChildAssociationRef car : cars) + { + categoryNodes[i++] = new CategoryNode(car.getChildRef(), this.services, this.imageResolver, this.scope); + } + return categoryNodes; + } + + private Node[] buildNodes(Collection cars) + { + Node[] nodes = new Node[cars.size()]; + int i = 0; + for (ChildAssociationRef car : cars) + { + nodes[i++] = new Node(car.getChildRef(), this.services, this.imageResolver, this.scope); + } + return nodes; + } + + private Node[] buildMixedNodes(Collection cars) + { + Node[] nodes = new Node[cars.size()]; + int i = 0; + for (ChildAssociationRef car : cars) + { + QName type = services.getNodeService().getType(car.getChildRef()); + if (services.getDictionaryService().isSubClass(type, ContentModel.TYPE_CATEGORY)) + { + nodes[i++] = new CategoryNode(car.getChildRef(), this.services, this.imageResolver, this.scope); + } + else + { + nodes[i++] = new Node(car.getChildRef(), this.services, this.imageResolver, this.scope); + } + } + return nodes; + } +} diff --git a/source/java/org/alfresco/repo/jscript/CategoryTemplateNode.java b/source/java/org/alfresco/repo/jscript/CategoryTemplateNode.java new file mode 100644 index 0000000000..2db629bcc2 --- /dev/null +++ b/source/java/org/alfresco/repo/jscript/CategoryTemplateNode.java @@ -0,0 +1,202 @@ +/* + * 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.jscript; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.alfresco.model.ContentModel; +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.TemplateImageResolver; +import org.alfresco.service.cmr.repository.TemplateNode; +import org.alfresco.service.cmr.search.CategoryService; +import org.alfresco.service.namespace.QName; + +/** + * Category Nodes from the classification helper have special support. + */ +public class CategoryTemplateNode extends TemplateNode +{ + /** + * Constructor + * + * @param nodeRef + * @param services + * @param resolver + */ + public CategoryTemplateNode(NodeRef nodeRef, ServiceRegistry services, TemplateImageResolver resolver) + { + super(nodeRef, services, resolver); + } + + @Override + public boolean getIsCategory() + { + return true; + } + + /** + * @return all the member of a category + */ + public List getCategoryMembers() + { + if (getIsCategory()) + { + return buildTemplateNodeList(services.getCategoryService().getChildren(getNodeRef(), + CategoryService.Mode.MEMBERS, CategoryService.Depth.ANY)); + } + else + { + return Collections.emptyList(); + } + } + + /** + * @return all the subcategories of a category + */ + public List getSubCategories() + { + if (getIsCategory()) + { + return buildCategoryNodeList(services.getCategoryService().getChildren(getNodeRef(), + CategoryService.Mode.SUB_CATEGORIES, CategoryService.Depth.ANY)); + } + else + { + return Collections.emptyList(); + } + } + + /** + * @return members and subcategories of a category + */ + public List getMembersAndSubCategories() + { + if (getIsCategory()) + { + + return buildMixedNodeList(services.getCategoryService().getChildren(getNodeRef(), CategoryService.Mode.ALL, + CategoryService.Depth.ANY)); + } + else + { + return Collections.emptyList(); + } + } + + /** + * @return all the immediate member of a category + */ + public List getImmediateCategoryMembers() + { + if (getIsCategory()) + { + return buildTemplateNodeList(services.getCategoryService().getChildren(getNodeRef(), + CategoryService.Mode.MEMBERS, CategoryService.Depth.IMMEDIATE)); + } + else + { + return Collections.emptyList(); + } + } + + /** + * @return all the immediate subcategories of a category + */ + public List getImmediateSubCategories() + { + if (getIsCategory()) + { + return buildCategoryNodeList(services.getCategoryService().getChildren(getNodeRef(), + CategoryService.Mode.SUB_CATEGORIES, CategoryService.Depth.IMMEDIATE)); + } + else + { + return Collections.emptyList(); + } + } + + /** + * @return immediate members and subcategories of a category + */ + public List getImmediateMembersAndSubCategories() + { + if (getIsCategory()) + { + return buildMixedNodeList(services.getCategoryService().getChildren(getNodeRef(), + CategoryService.Mode.ALL, CategoryService.Depth.IMMEDIATE)); + } + else + { + return Collections.emptyList(); + } + } + + /** + * Support to build node lists from category service API calls. + * + * @param childRefs + * + * @return List of TemplateNode + */ + private List buildTemplateNodeList(Collection childRefs) + { + List answer = new ArrayList(childRefs.size()); + for (ChildAssociationRef ref : childRefs) + { + // create our Node representation from the NodeRef + TemplateNode child = new TemplateNode(ref.getChildRef(), this.services, this.imageResolver); + answer.add(child); + } + return answer; + } + + private List buildCategoryNodeList(Collection childRefs) + { + List answer = new ArrayList(childRefs.size()); + for (ChildAssociationRef ref : childRefs) + { + // create our Node representation from the NodeRef + CategoryTemplateNode child = new CategoryTemplateNode(ref.getChildRef(), this.services, this.imageResolver); + answer.add(child); + } + return answer; + } + + private List buildMixedNodeList(Collection cars) + { + List nodes = new ArrayList(cars.size()); + int i = 0; + for (ChildAssociationRef car : cars) + { + QName type = services.getNodeService().getType(car.getChildRef()); + if (services.getDictionaryService().isSubClass(type, ContentModel.TYPE_CATEGORY)) + { + nodes.add(new CategoryTemplateNode(car.getChildRef(), this.services, this.imageResolver)); + } + else + { + nodes.add(new TemplateNode(car.getChildRef(), this.services, this.imageResolver)); + } + } + return nodes; + } +} diff --git a/source/java/org/alfresco/repo/jscript/Classification.java b/source/java/org/alfresco/repo/jscript/Classification.java new file mode 100644 index 0000000000..c093bf630d --- /dev/null +++ b/source/java/org/alfresco/repo/jscript/Classification.java @@ -0,0 +1,144 @@ +/* + * 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.jscript; + +import java.util.Collection; + +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.TemplateImageResolver; +import org.alfresco.service.cmr.search.CategoryService; +import org.alfresco.service.namespace.QName; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.mozilla.javascript.Scriptable; + +/** + * Support class for finding categories, finding root nodes for categories and creating root categories. + * + * @author Andy Hind + */ +public final class Classification implements Scopeable +{ + @SuppressWarnings("unused") + private Scriptable scope; + + private ServiceRegistry services; + + @SuppressWarnings("unused") + private TemplateImageResolver imageResolver; + + private StoreRef storeRef; + + public Classification(ServiceRegistry services, StoreRef storeRef, TemplateImageResolver imageResolver) + { + this.services = services; + this.imageResolver = imageResolver; + this.storeRef = storeRef; + } + + /** + * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) + */ + public void setScope(Scriptable scope) + { + this.scope = scope; + } + + /** + * Find all the category nodes in a given classification. + * + * @param aspect + * @return + */ + public CategoryNode[] getAllCategoryNodes(String aspect) + { + return buildCategoryNodes(services.getCategoryService().getCategories(storeRef, createQName(aspect), + CategoryService.Depth.ANY)); + } + + /** + * Get all the aspects that define a classification. + * + * @return + */ + public String[] getAllClassificationAspects() + { + Collection aspects = services.getCategoryService().getClassificationAspects(); + String[] answer = new String[aspects.size()]; + int i = 0; + for (QName qname : aspects) + { + answer[i++] = qname.toPrefixString(this.services.getNamespaceService()); + } + return answer; + } + + public String[] jsGet_allClassificationAspects() + { + return getAllClassificationAspects(); + } + + /** + * Create a root category in a classification. + * + * @param aspect + * @param name + */ + public void createRootCategory(String aspect, String name) + { + services.getCategoryService().createRootCategory(storeRef, createQName(aspect), name); + } + + /** + * Get the root categories in a classification. + * + * @param aspect + * @return + */ + public CategoryNode[] getRootCategories(String aspect) + { + return buildCategoryNodes(services.getCategoryService().getRootCategories(storeRef, createQName(aspect))); + } + + private CategoryNode[] buildCategoryNodes(Collection cars) + { + CategoryNode[] categoryNodes = new CategoryNode[cars.size()]; + int i = 0; + for (ChildAssociationRef car : cars) + { + categoryNodes[i++] = new CategoryNode(car.getChildRef(), this.services, this.imageResolver, this.scope); + } + return categoryNodes; + } + + private QName createQName(String s) + { + QName qname; + if (s.indexOf(QName.NAMESPACE_BEGIN) != -1) + { + qname = QName.createQName(s); + } + else + { + qname = QName.createQName(s, this.services.getNamespaceService()); + } + return qname; + } + +} diff --git a/source/java/org/alfresco/repo/jscript/Node.java b/source/java/org/alfresco/repo/jscript/Node.java index daeb82ed3f..5d5195833c 100644 --- a/source/java/org/alfresco/repo/jscript/Node.java +++ b/source/java/org/alfresco/repo/jscript/Node.java @@ -92,7 +92,7 @@ public class Node implements Serializable, Scopeable private final static String FOLDER_BROWSE_URL = "/navigate/browse/{0}/{1}/{2}"; /** Root scope for this object */ - private Scriptable scope; + protected Scriptable scope; /** Node Value Converter */ private NodeValueConverter converter = null; @@ -110,18 +110,17 @@ public class Node implements Serializable, Scopeable private Node[] children = null; /** The properties of this node */ private ScriptableQNameMap properties = null; - private ServiceRegistry services = null; + protected ServiceRegistry services = null; private NodeService nodeService = null; private Boolean isDocument = null; private Boolean isContainer = null; private String displayPath = null; - private TemplateImageResolver imageResolver = null; + protected TemplateImageResolver imageResolver = null; private Node parent = null; private ChildAssociationRef primaryParentAssoc = null; // NOTE: see the reset() method when adding new cached members! - // ------------------------------------------------------------------------------ // Construction @@ -428,7 +427,7 @@ public class Node implements Serializable, Scopeable /** * @return true if this Node is a container (i.e. a folder) */ - public boolean isContainer() + public boolean getIsContainer() { if (isContainer == null) { @@ -442,13 +441,13 @@ public class Node implements Serializable, Scopeable public boolean jsGet_isContainer() { - return isContainer(); + return getIsContainer(); } /** * @return true if this Node is a Document (i.e. with content) */ - public boolean isDocument() + public boolean getIsDocument() { if (isDocument == null) { @@ -461,7 +460,21 @@ public class Node implements Serializable, Scopeable public boolean jsGet_isDocument() { - return isDocument(); + return getIsDocument(); + } + + /** + * @return true if the Node is a Category + */ + public boolean getIsCategory() + { + // this valid is overriden by the CategoryNode sub-class + return false; + } + + public boolean jsGet_isCategory() + { + return getIsCategory(); } /** @@ -554,7 +567,7 @@ public class Node implements Serializable, Scopeable { if (this.imageResolver != null) { - if (isDocument()) + if (getIsDocument()) { return this.imageResolver.resolveImagePathForName(getName(), true); } @@ -581,7 +594,7 @@ public class Node implements Serializable, Scopeable { if (this.imageResolver != null) { - if (isDocument()) + if (getIsDocument()) { return this.imageResolver.resolveImagePathForName(getName(), false); } @@ -727,7 +740,7 @@ public class Node implements Serializable, Scopeable */ public String getUrl() { - if (isDocument() == true) + if (getIsDocument() == true) { try { @@ -890,7 +903,8 @@ public class Node implements Serializable, Scopeable this.services.getPermissionService().deletePermission(this.nodeRef, authority, permission); } - // ------------- + + // ------------------------------------------------------------------------------ // Ownership API /** @@ -1145,7 +1159,7 @@ public class Node implements Serializable, Scopeable { if (destination != null) { - NodeRef copyRef = this.services.getCopyService().copy( + NodeRef copyRef = this.services.getCopyService().copyAndRename( this.nodeRef, destination.getNodeRef(), ContentModel.ASSOC_CONTAINS, @@ -1632,7 +1646,7 @@ public class Node implements Serializable, Scopeable this.imageResolver); // add the current node as either the document/space as appropriate - if (this.isDocument()) + if (this.getIsDocument()) { model.put("document", new TemplateNode(this.nodeRef, this.services, this.imageResolver)); model.put("space", new TemplateNode(getPrimaryParentAssoc().getParentRef(), this.services, this.imageResolver)); @@ -1724,7 +1738,7 @@ public class Node implements Serializable, Scopeable /** * Reset the Node cached state */ - private void reset() + public void reset() { this.name = null; this.type = null; diff --git a/source/java/org/alfresco/repo/jscript/RhinoScriptService.java b/source/java/org/alfresco/repo/jscript/RhinoScriptService.java index 9e501435c3..e92b887c91 100644 --- a/source/java/org/alfresco/repo/jscript/RhinoScriptService.java +++ b/source/java/org/alfresco/repo/jscript/RhinoScriptService.java @@ -21,7 +21,9 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; @@ -30,6 +32,7 @@ import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.ScriptException; +import org.alfresco.service.cmr.repository.ScriptImplementation; import org.alfresco.service.cmr.repository.ScriptService; import org.alfresco.service.cmr.repository.TemplateImageResolver; import org.alfresco.service.namespace.QName; @@ -51,6 +54,8 @@ public class RhinoScriptService implements ScriptService /** Repository Service Registry */ private ServiceRegistry services; + /** List of global scripts */ + private List globalScripts = new ArrayList(5); /** * Set the Service Registry @@ -62,6 +67,14 @@ public class RhinoScriptService implements ScriptService this.services = services; } + /** + * @see org.alfresco.service.cmr.repository.ScriptService#registerScript(java.lang.Object) + */ + public void registerScript(ScriptImplementation script) + { + this.globalScripts.add(script); + } + /** * @see org.alfresco.service.cmr.repository.ScriptService#executeScript(java.lang.String, java.util.Map) */ @@ -217,28 +230,28 @@ public class RhinoScriptService implements ScriptService model = new HashMap(); } - // add useful util objects - model.put("actions", new Actions(services)); - model.put("logger", new ScriptLogger()); + // add the global scripts + for (ScriptImplementation script : this.globalScripts) + { + model.put(script.getScriptName(), script); + } // insert supplied object model into root of the default scope + for (String key : model.keySet()) { - for (String key : model.keySet()) + // set the root scope on appropriate objects + // this is used to allow native JS object creation etc. + Object obj = model.get(key); + if (obj instanceof Scopeable) { - // set the root scope on appropriate objects - // this is used to allow native JS object creation etc. - Object obj = model.get(key); - if (obj instanceof Scopeable) - { - ((Scopeable)obj).setScope(scope); - } - - // convert/wrap each object to JavaScript compatible - Object jsObject = Context.javaToJS(obj, scope); - - // insert into the root scope ready for access by the script - ScriptableObject.putProperty(scope, key, jsObject); + ((Scopeable)obj).setScope(scope); } + + // convert/wrap each object to JavaScript compatible + Object jsObject = Context.javaToJS(obj, scope); + + // insert into the root scope ready for access by the script + ScriptableObject.putProperty(scope, key, jsObject); } // execute the script @@ -343,6 +356,10 @@ public class RhinoScriptService implements ScriptService model.put("search", new Search(services, companyHome.getStoreRef(), resolver)); + model.put("session", new Session(services, resolver)); + + model.put("classification", new Classification(services, companyHome.getStoreRef(), resolver)); + return model; } } diff --git a/source/java/org/alfresco/repo/jscript/ScriptLogger.java b/source/java/org/alfresco/repo/jscript/ScriptLogger.java index 2f885ff474..29c21d1dfc 100644 --- a/source/java/org/alfresco/repo/jscript/ScriptLogger.java +++ b/source/java/org/alfresco/repo/jscript/ScriptLogger.java @@ -21,7 +21,7 @@ import org.apache.log4j.Logger; /** * @author Kevin Roast */ -public final class ScriptLogger +public final class ScriptLogger extends BaseScriptImplementation { private static final Logger logger = Logger.getLogger(ScriptLogger.class); diff --git a/source/java/org/alfresco/repo/jscript/ScriptUtils.java b/source/java/org/alfresco/repo/jscript/ScriptUtils.java new file mode 100644 index 0000000000..a96d3288e7 --- /dev/null +++ b/source/java/org/alfresco/repo/jscript/ScriptUtils.java @@ -0,0 +1,56 @@ +/* + * 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.jscript; + +import org.mozilla.javascript.Scriptable; + +/** + * Place for general and miscellenous utility functions not already found in generic JavaScript. + * + * @author Kevin Roast + */ +public final class ScriptUtils extends BaseScriptImplementation implements Scopeable +{ + /** Root scope for this object */ + private Scriptable scope; + + /** + * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) + */ + public void setScope(Scriptable scope) + { + this.scope = scope; + } + + /** + * Function to pad a string with zero '0' characters to the required length + * + * @param s String to pad with leading zero '0' characters + * @param len Length to pad to + * + * @return padded string or the original if already at >=len characters + */ + public String pad(String s, int len) + { + String result = s; + for (int i=0; i<(len - s.length()); i++) + { + result = "0" + result; + } + return result; + } +} diff --git a/source/java/org/alfresco/repo/jscript/Session.java b/source/java/org/alfresco/repo/jscript/Session.java new file mode 100644 index 0000000000..de54dfab33 --- /dev/null +++ b/source/java/org/alfresco/repo/jscript/Session.java @@ -0,0 +1,79 @@ +/* + * 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.jscript; + +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.TemplateImageResolver; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.mozilla.javascript.Scriptable; + +/** + * Support object for session level properties etc. + *

+ * Provides access to the user's authentication ticket. + * + * @author Andy Hind + */ +public class Session implements Scopeable +{ + + @SuppressWarnings("unused") + private static Log logger = LogFactory.getLog(Session.class); + + @SuppressWarnings("unused") + private Scriptable scope; + + private ServiceRegistry services; + + @SuppressWarnings("unused") + private TemplateImageResolver imageResolver; + + public Session(ServiceRegistry services, TemplateImageResolver imageResolver) + { + this.services = services; + this.imageResolver = imageResolver; + } + + /** + * @see org.alfresco.repo.jscript.Scopeable#setScope(org.mozilla.javascript.Scriptable) + */ + public void setScope(Scriptable scope) + { + this.scope = scope; + } + + /** + * Get the user's authentication ticket. + * + * @return + */ + public String getTicket() + { + return services.getAuthenticationService().getCurrentTicket(); + } + + /** + * Expose the user's authentication ticket as JavaScipt property. + * + * @return + */ + public String jsGet_ticket() + { + return getTicket(); + } +} diff --git a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java index 6d5eff338d..950571e8c6 100644 --- a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java +++ b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java @@ -503,7 +503,7 @@ public class FileFolderServiceImpl implements FileFolderService */ public FileInfo rename(NodeRef sourceNodeRef, String newName) throws FileExistsException, FileNotFoundException { - return move(sourceNodeRef, null, newName); + return moveOrCopy(sourceNodeRef, null, newName, true); } /** @@ -815,12 +815,25 @@ public class FileFolderServiceImpl implements FileFolderService for (int i = 0; i < folderCount; i++) { String pathElement = pathElements.get(i); - FileInfo pathElementInfo = getPathElementInfo(currentPath, rootNodeRef, parentNodeRef, pathElement, true); - parentNodeRef = pathElementInfo.getNodeRef(); + NodeRef folderNodeRef = searchSimple(parentNodeRef, pathElement); + if (folderNodeRef == null) + { + StringBuilder sb = new StringBuilder(128); + sb.append("Folder not found: " + currentPath); + throw new FileNotFoundException(sb.toString()); + } + parentNodeRef = folderNodeRef; } // we have resolved the folder path - resolve the last component String pathElement = pathElements.get(pathElements.size() - 1); - FileInfo result = getPathElementInfo(currentPath, rootNodeRef, parentNodeRef, pathElement, false); + NodeRef fileNodeRef = searchSimple(parentNodeRef, pathElement); + if (fileNodeRef == null) + { + StringBuilder sb = new StringBuilder(128); + sb.append("File not found: " + currentPath); + throw new FileNotFoundException(sb.toString()); + } + FileInfo result = getFileInfo(fileNodeRef); // found it if (logger.isDebugEnabled()) { @@ -831,42 +844,6 @@ public class FileFolderServiceImpl implements FileFolderService } return result; } - - /** - * Helper method to dig down a level for a node based on name - */ - private FileInfo getPathElementInfo( - StringBuilder currentPath, - NodeRef rootNodeRef, - NodeRef parentNodeRef, - String pathElement, - boolean folderOnly) throws FileNotFoundException - { - currentPath.append("/").append(pathElement); - - boolean includeFiles = (folderOnly ? false : true); - List pathElementInfos = search(parentNodeRef, pathElement, includeFiles, true, false); - // check - if (pathElementInfos.size() == 0) - { - StringBuilder sb = new StringBuilder(128); - sb.append(folderOnly ? "Folder" : "File or folder").append(" not found: \n") - .append(" root: ").append(rootNodeRef).append("\n") - .append(" path: ").append(currentPath); - throw new FileNotFoundException(sb.toString()); - } - else if (pathElementInfos.size() > 1) - { - // we have detected a duplicate name - warn, but allow - StringBuilder sb = new StringBuilder(128); - sb.append("Duplicate file or folder found: \n") - .append(" root: ").append(rootNodeRef).append("\n") - .append(" path: ").append(currentPath); - logger.warn(sb); - } - FileInfo pathElementInfo = pathElementInfos.get(0); - return pathElementInfo; - } public FileInfo getFileInfo(NodeRef nodeRef) { diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index b92cc1f17e..f71b5c1de2 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -1,1820 +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.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); - } - } -} +/* + * 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/NodeDaoService.java b/source/java/org/alfresco/repo/node/db/NodeDaoService.java index c44fb7fca7..2e102f7aa0 100644 --- a/source/java/org/alfresco/repo/node/db/NodeDaoService.java +++ b/source/java/org/alfresco/repo/node/db/NodeDaoService.java @@ -236,11 +236,14 @@ public interface NodeDaoService */ 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 Transaction getTxnById(long txnId); + public Transaction getLastTxn(); + public Transaction getLastTxnForStore(final StoreRef storeRef); + public int getTxnUpdateCount(final long txnId); + public int getTxnDeleteCount(final long txnId); public int getTransactionCount(); - public List getNextTxns(final Transaction lastTxn, final int count); + public List getNextTxns(final long lastTxnId, final int count); + public List getNextRemoteTxns(final long lastTxnId, 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 8881eea7d6..cc702dc894 100644 --- a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java @@ -1,1165 +1,1216 @@ -/* - * 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.hibernate; - -import java.io.Serializable; -import java.net.InetAddress; -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.zip.CRC32; - -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.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.domain.hibernate.ChildAssocImpl; -import org.alfresco.repo.domain.hibernate.NodeAssocImpl; -import org.alfresco.repo.domain.hibernate.NodeImpl; -import org.alfresco.repo.domain.hibernate.NodeStatusImpl; -import org.alfresco.repo.domain.hibernate.ServerImpl; -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; -import org.springframework.orm.hibernate3.HibernateCallback; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; - -/** - * Hibernate-specific implementation of the persistence-independent node DAO interface - * - * @author Derek Hulley - */ -public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements NodeDaoService, TransactionalDao -{ - private static final String QUERY_GET_ALL_STORES = "store.GetAllStores"; - private static final String UPDATE_SET_CHILD_ASSOC_NAME = "node.updateChildAssocName"; - private static final String QUERY_GET_CHILD_ASSOCS = "node.GetChildAssocs"; - private static final String QUERY_GET_CHILD_ASSOC_BY_TYPE_AND_NAME = "node.GetChildAssocByTypeAndName"; - private static final String QUERY_GET_CHILD_ASSOC_REFS = "node.GetChildAssocRefs"; - private static final String QUERY_GET_NODE_ASSOC = "node.GetNodeAssoc"; - 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_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); - - /** a uuid identifying this unique instance */ - private final String uuid; - - private static TransactionAwareSingleton serverIdSingleton = new TransactionAwareSingleton(); - - /** - * - */ - public HibernateNodeDaoServiceImpl() - { - this.uuid = GUID.generate(); - } - - /** - * Checks equality by type and uuid - */ - public boolean equals(Object obj) - { - if (obj == null) - { - return false; - } - else if (!(obj instanceof HibernateNodeDaoServiceImpl)) - { - return false; - } - HibernateNodeDaoServiceImpl that = (HibernateNodeDaoServiceImpl) obj; - return this.uuid.equals(that.uuid); - } - - /** - * @see #uuid - */ - public int hashCode() - { - return uuid.hashCode(); - } - - /** - * Gets/creates the server instance to use for the life of this instance - */ - private Server getServer() - { - Long serverId = serverIdSingleton.get(); - Server server = null; - if (serverId != null) - { - server = (Server) getSession().get(ServerImpl.class, serverId); - if (server != null) - { - return server; - } - } - try - { - final String ipAddress = InetAddress.getLocalHost().getHostAddress(); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_SERVER_BY_IPADDRESS) - .setString("ipAddress", ipAddress); - return query.uniqueResult(); - } - }; - server = (Server) getHibernateTemplate().execute(callback); - // create it if it doesn't exist - if (server == null) - { - server = new ServerImpl(); - server.setIpAddress(ipAddress); - try - { - getSession().save(server); - } - catch (DataIntegrityViolationException e) - { - // get it again - server = (Server) getHibernateTemplate().execute(callback); - if (server == null) - { - throw new AlfrescoRuntimeException("Unable to create server instance: " + ipAddress); - } - } - } - // push the value into the singleton - serverIdSingleton.put(server.getId()); - - return server; - } - catch (Exception e) - { - throw new AlfrescoRuntimeException("Failed to create server instance", e); - } - } - - private static final String RESOURCE_KEY_TRANSACTION_ID = "hibernate.transaction.id"; - private Transaction getCurrentTransaction() - { - Transaction transaction = null; - Serializable txnId = (Serializable) AlfrescoTransactionSupport.getResource(RESOURCE_KEY_TRANSACTION_ID); - if (txnId == null) - { - // no transaction instance has been bound to the transaction - transaction = new TransactionImpl(); - transaction.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); - transaction.setServer(getServer()); - txnId = getHibernateTemplate().save(transaction); - // bind the id - AlfrescoTransactionSupport.bindResource(RESOURCE_KEY_TRANSACTION_ID, txnId); - } - else - { - transaction = (Transaction) getHibernateTemplate().get(TransactionImpl.class, txnId); - } - return transaction; - } - - /** - * Does this Session contain any changes which must be - * synchronized with the store? - * - * @return true => changes are pending - */ - public boolean isDirty() - { - // create a callback for the task - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - return session.isDirty(); - } - }; - // execute the callback - return ((Boolean)getHibernateTemplate().execute(callback)).booleanValue(); - } - - /** - * Just flushes the session - */ - public void flush() - { - getSession().flush(); - } - - /** - * @see #QUERY_GET_ALL_STORES - */ - @SuppressWarnings("unchecked") - public List getStores() - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_ALL_STORES); - return query.list(); - } - }; - List queryResults = (List) getHibernateTemplate().execute(callback); - // done - return queryResults; - } - - /** - * Ensures that the store protocol/identifier combination is unique - */ - public Store createStore(String protocol, String identifier) - { - // ensure that the name isn't in use - Store store = getStore(protocol, identifier); - if (store != null) - { - throw new RuntimeException("A store already exists: \n" + - " protocol: " + protocol + "\n" + - " identifier: " + identifier + "\n" + - " store: " + store); - } - - store = new StoreImpl(); - // set key - store.setKey(new StoreKey(protocol, identifier)); - // persist so that it is present in the hibernate cache - getHibernateTemplate().save(store); - // create and assign a root node - Node rootNode = newNode( - store, - GUID.generate(), - ContentModel.TYPE_STOREROOT); - store.setRootNode(rootNode); - // done - return store; - } - - public Store getStore(String protocol, String identifier) - { - StoreKey storeKey = new StoreKey(protocol, identifier); - Store store = (Store) getHibernateTemplate().get(StoreImpl.class, storeKey); - // done - return store; - } - - /** - * Fetch the node status, if it exists - */ - public NodeStatus getNodeStatus(NodeRef nodeRef, boolean update) - { - NodeKey nodeKey = new NodeKey(nodeRef); - NodeStatus status = null; - try - { - status = (NodeStatus) getHibernateTemplate().get(NodeStatusImpl.class, nodeKey); - } - catch (DataAccessException e) - { - if (e.contains(ObjectDeletedException.class)) - { - // the object no longer exists - return null; - } - throw e; - } - // create if necessary - 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; - } - - public void recordChangeId(NodeRef nodeRef) - { - NodeKey key = new NodeKey(nodeRef); - - NodeStatus status = (NodeStatus) getHibernateTemplate().get(NodeStatusImpl.class, key); - if (status == null) - { - // the node never existed or the status was deleted - return; - } - else - { - status.getTransaction().setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); - } - } - - public Node newNode(Store store, String uuid, QName nodeTypeQName) throws InvalidTypeException - { - NodeKey key = new NodeKey(store.getKey(), uuid); - - // create (or reuse) the mandatory node status - NodeStatus status = (NodeStatus) getHibernateTemplate().get(NodeStatusImpl.class, key); - if (status == null) - { - status = new NodeStatusImpl(); - status.setKey(key); - } - else - { - // The node existed at some point. - // Although unlikely, it is possible that the node was deleted in this transaction. - // If that is the case, then the session has to be flushed so that the database - // constraints aren't violated as the node creation will write to the database to - // get an ID - if (status.getTransaction().getChangeTxnId().equals(AlfrescoTransactionSupport.getTransactionId())) - { - // flush - getHibernateTemplate().flush(); - } - } - - // build a concrete node based on a bootstrap type - Node node = new NodeImpl(); - // set other required properties - node.setStore(store); - node.setUuid(uuid); - node.setTypeQName(nodeTypeQName); - // persist the node - getHibernateTemplate().save(node); - - // set required status properties - status.setNode(node); - // assign a transaction - if (status.getTransaction() == null) - { - status.setTransaction(getCurrentTransaction()); - } - // persist the nodestatus - getHibernateTemplate().save(status); - - // done - return node; - } - - public Node getNode(NodeRef nodeRef) - { - // get it via the node status - NodeStatus status = getNodeStatus(nodeRef, false); - if (status == null) - { - // no status implies no node - return null; - } - else - { - // a status may have a node - Node node = status.getNode(); - return node; - } - } - - /** - * Manually ensures that all cascading of associations is taken care of - */ - public void deleteNode(Node node, boolean cascade) - { - Set deletedChildAssocIds = new HashSet(10); - deleteNodeInternal(node, cascade, deletedChildAssocIds); - } - - /** - * - * @param node - * @param cascade true to cascade delete - * @param deletedChildAssocIds previously deleted child associations - */ - private void deleteNodeInternal(Node node, boolean cascade, Set deletedChildAssocIds) - { - // delete all parent assocs - if (logger.isDebugEnabled()) - { - logger.debug("Deleting parent assocs of node " + node.getId()); - } - - Collection parentAssocs = node.getParentAssocs(); - parentAssocs = new ArrayList(parentAssocs); - for (ChildAssoc assoc : parentAssocs) - { - deleteChildAssocInternal(assoc, false, deletedChildAssocIds); // we don't cascade upwards - } - // delete all child assocs - if (logger.isDebugEnabled()) - { - logger.debug("Deleting child assocs of node " + node.getId()); - } - Collection childAssocs = getChildAssocs(node); - childAssocs = new ArrayList(childAssocs); - for (ChildAssoc assoc : childAssocs) - { - deleteChildAssocInternal(assoc, cascade, deletedChildAssocIds); // potentially cascade downwards - } - // delete all node associations to and from - if (logger.isDebugEnabled()) - { - logger.debug("Deleting source and target assocs of node " + node.getId()); - } - List nodeAssocs = getNodeAssocsToAndFrom(node); - for (NodeAssoc assoc : nodeAssocs) - { - getHibernateTemplate().delete(assoc); - } - // update the node status - NodeRef nodeRef = node.getNodeRef(); - NodeStatus nodeStatus = getNodeStatus(nodeRef, true); - nodeStatus.setNode(null); - nodeStatus.getTransaction().setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); - // finally delete the node - getHibernateTemplate().delete(node); - // flush to ensure constraints can't be violated - getSession().flush(); - // done - } - - private long getCrc(String str) - { - CRC32 crc = new CRC32(); - crc.update(str.getBytes()); - return crc.getValue(); - } - - private static final String TRUNCATED_NAME_INDICATOR = "~~~"; - private String getShortName(String str) - { - int length = str.length(); - if (length <= 50) - { - return str; - } - else - { - StringBuilder ret = new StringBuilder(50); - ret.append(str.substring(0, 47)).append(TRUNCATED_NAME_INDICATOR); - return ret.toString(); - } - } - - public ChildAssoc newChildAssoc( - Node parentNode, - Node childNode, - boolean isPrimary, - QName assocTypeQName, - QName qname) - { - /* - * This initial child association creation will fail IFF there is already - * an association of the given type and name between the two nodes. For new association - * creation, this can only occur if two transactions attempt to create a secondary - * child association between the same two nodes. As this is unlikely, it is - * appropriate to just throw a runtime exception and let the second transaction - * fail. - * - * We don't need to flush the session beforehand as there won't be any deletions - * of the assocation pending. The association deletes, on the other hand, have - * to flush early in order to ensure that the database unique index isn't violated - * if the association is recreated subsequently. - */ - - // assign a random name to the node - String randomName = GUID.generate(); - - ChildAssoc assoc = new ChildAssocImpl(); - assoc.setTypeQName(assocTypeQName); - assoc.setChildNodeName(randomName); - assoc.setChildNodeNameCrc(-1L); // random names compete only with each other - assoc.setQname(qname); - assoc.setIsPrimary(isPrimary); - // maintain inverse sets - assoc.buildAssociation(parentNode, childNode); - // persist it - getHibernateTemplate().save(assoc); - // done - return assoc; - } - - public void setChildNameUnique(final ChildAssoc childAssoc, String childName) - { - /* - * As the Hibernate session is rendered useless when an exception is - * bubbled up, we go direct to the database to update the child association. - * This preserves the session and client code can catch the resulting - * exception and react to it whilst in the same transaction. - * - * We ensure that case-insensitivity is maintained by persisting - * the lowercase version of the child node name. - */ - - String childNameNew = null; - long crc = -1; - if (childName == null) - { - // random names compete only with each other, i.e. not at all - childNameNew = GUID.generate(); - crc = -1; - } - else - { - // assigned names compete exactly - childNameNew = childName.toLowerCase(); - crc = getCrc(childNameNew); - } - - final String childNameNewShort = getShortName(childNameNew); - final long childNameNewCrc = crc; - - // check if the name has changed - if (childAssoc.getChildNodeNameCrc() == childNameNewCrc) - { - if (childAssoc.getChildNodeName().equals(childNameNewShort)) - { - // nothing changed - return; - } - } - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - session.flush(); - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.UPDATE_SET_CHILD_ASSOC_NAME) - .setString("newName", childNameNewShort) - .setLong("newNameCrc", childNameNewCrc) - .setLong("childAssocId", childAssoc.getId()); - return (Integer) query.executeUpdate(); - } - }; - try - { - Integer count = (Integer) getHibernateTemplate().execute(callback); - // refresh the entity directly - if (count.intValue() == 0) - { - if (logger.isDebugEnabled()) - { - logger.debug("ChildAssoc not updated: " + childAssoc.getId()); - } - } - else - { - getHibernateTemplate().refresh(childAssoc); - } - } - catch (DataIntegrityViolationException e) - { - NodeRef parentNodeRef = childAssoc.getParent().getNodeRef(); - QName assocTypeQName = childAssoc.getTypeQName(); - throw new DuplicateChildNodeNameException(parentNodeRef, assocTypeQName, childName); - } - } - - @SuppressWarnings("unchecked") - public Collection getChildAssocs(final Node parentNode) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOCS) - .setLong("parentId", parentNode.getId()); - return query.list(); - } - }; - List queryResults = (List) getHibernateTemplate().execute(callback); - return queryResults; - } - - @SuppressWarnings("unchecked") - public Collection getChildAssocRefs(final Node parentNode) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_REFS) - .setLong("parentId", parentNode.getId()); - return query.list(); - } - }; - List queryResults = (List) getHibernateTemplate().execute(callback); - Collection refs = new ArrayList(queryResults.size()); - NodeRef parentNodeRef = parentNode.getNodeRef(); - for (Object[] row : queryResults) - { - String childProtocol = (String) row[5]; - String childIdentifier = (String) row[6]; - String childUuid = (String) row[7]; - NodeRef childNodeRef = new NodeRef(new StoreRef(childProtocol, childIdentifier), childUuid); - QName assocTypeQName = (QName) row[0]; - QName assocQName = (QName) row[1]; - Boolean assocIsPrimary = (Boolean) row[2]; - Integer assocIndex = (Integer) row[3]; - ChildAssociationRef assocRef = new ChildAssociationRef( - assocTypeQName, - parentNodeRef, - assocQName, - childNodeRef, - assocIsPrimary.booleanValue(), - assocIndex.intValue()); - refs.add(assocRef); - } - return refs; - } - - public ChildAssoc getChildAssoc( - Node parentNode, - Node childNode, - QName assocTypeQName, - QName qname) - { - ChildAssociationRef childAssocRef = new ChildAssociationRef( - assocTypeQName, - parentNode.getNodeRef(), - qname, - childNode.getNodeRef()); - // get all the parent's child associations - Collection assocs = getChildAssocs(parentNode); - // hunt down the desired assoc - for (ChildAssoc assoc : assocs) - { - // is it a match? - if (!assoc.getChildAssocRef().equals(childAssocRef)) // not a match - { - continue; - } - else - { - return assoc; - } - } - // not found - return null; - } - - public ChildAssoc getChildAssoc(final Node parentNode, final QName assocTypeQName, final String childName) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - String childNameLower = childName.toLowerCase(); - String childNameShort = getShortName(childNameLower); - long childNameLowerCrc = getCrc(childNameLower); - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_BY_TYPE_AND_NAME) - .setLong("parentId", parentNode.getId()) - .setParameter("typeQName", assocTypeQName) - .setParameter("childNodeName", childNameShort) - .setLong("childNodeNameCrc", childNameLowerCrc); - return query.uniqueResult(); - } - }; - ChildAssoc childAssoc = (ChildAssoc) getHibernateTemplate().execute(callback); - return childAssoc; - } - - /** - * Public level entry-point. - */ - public void deleteChildAssoc(ChildAssoc assoc, boolean cascade) - { - Set deletedChildAssocIds = new HashSet(10); - deleteChildAssocInternal(assoc, cascade, deletedChildAssocIds); - } - - /** - * Cascade deletion of child associations, recording the IDs of deleted assocs. - * - * @param assoc the association to delete - * @param cascade true to cascade to the child node of the association - * @param deletedChildAssocIds already-deleted associations - */ - private void deleteChildAssocInternal(ChildAssoc assoc, boolean cascade, Set deletedChildAssocIds) - { - Long childAssocId = assoc.getId(); - if (deletedChildAssocIds.contains(childAssocId)) - { - if (logger.isDebugEnabled()) - { - logger.debug("Ignoring parent-child association " + assoc.getId()); - } - return; - } - - if (logger.isDebugEnabled()) - { - logger.debug( - "Deleting parent-child association " + assoc.getId() + - (cascade ? " with" : " without") + " cascade:" + - assoc.getParent().getId() + " -> " + assoc.getChild().getId()); - } - - Node childNode = assoc.getChild(); - - // maintain inverse association sets - assoc.removeAssociation(); - // remove instance - getHibernateTemplate().delete(assoc); - deletedChildAssocIds.add(childAssocId); // ensure that we don't attempt to delete it twice - - if (cascade && assoc.getIsPrimary()) // the assoc is primary - { - // delete the child node - deleteNodeInternal(childNode, cascade, deletedChildAssocIds); - /* - * The child node deletion will cascade delete all assocs to - * and from it, but we have safely removed this one, so no - * duplicate call will be received to do this - */ - } - - // To ensure the validity of the constraint enforcement by the database, - // we have to flush here - getSession().flush(); - } - - public ChildAssoc getPrimaryParentAssoc(Node node) - { - // get the assocs pointing to the node - Collection parentAssocs = node.getParentAssocs(); - ChildAssoc primaryAssoc = null; - for (ChildAssoc assoc : parentAssocs) - { - // ignore non-primary assocs - if (!assoc.getIsPrimary()) - { - continue; - } - else if (primaryAssoc != null) - { - // we have more than one somehow - throw new DataIntegrityViolationException( - "Multiple primary associations: \n" + - " child: " + node + "\n" + - " first primary assoc: " + primaryAssoc + "\n" + - " second primary assoc: " + assoc); - } - primaryAssoc = assoc; - // we keep looping to hunt out data integrity issues - } - // did we find a primary assoc? - if (primaryAssoc == null) - { - // the only condition where this is allowed is if the given node is a root node - Store store = node.getStore(); - Node rootNode = store.getRootNode(); - if (rootNode == null) - { - // a store without a root node - the entire store is hosed - throw new DataIntegrityViolationException("Store has no root node: \n" + - " store: " + store); - } - if (!rootNode.equals(node)) - { - // it wasn't the root node - throw new DataIntegrityViolationException("Non-root node has no primary parent: \n" + - " child: " + node); - } - } - // done - return primaryAssoc; - } - - public NodeAssoc newNodeAssoc(Node sourceNode, Node targetNode, QName assocTypeQName) - { - NodeAssoc assoc = new NodeAssocImpl(); - assoc.setTypeQName(assocTypeQName); - assoc.buildAssociation(sourceNode, targetNode); - // persist - try - { - getHibernateTemplate().save(assoc); - } - catch (DataIntegrityViolationException e) - { - throw new AssociationExistsException( - sourceNode.getNodeRef(), - targetNode.getNodeRef(), - assocTypeQName, - e); - } - // done - return assoc; - } - - @SuppressWarnings("unchecked") - public List getNodeAssocsToAndFrom(final Node node) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODE_ASSOCS_TO_AND_FROM) - .setLong("nodeId", node.getId()); - return query.list(); - } - }; - List results = (List) getHibernateTemplate().execute(callback); - return results; - } - - public NodeAssoc getNodeAssoc( - final Node sourceNode, - final Node targetNode, - final QName assocTypeQName) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODE_ASSOC) - .setLong("sourceId", sourceNode.getId()) - .setLong("targetId", targetNode.getId()) - .setParameter("assocTypeQName", assocTypeQName); - return query.uniqueResult(); - } - }; - NodeAssoc result = (NodeAssoc) getHibernateTemplate().execute(callback); - return result; - } - - @SuppressWarnings("unchecked") - public List getTargetNodeAssocs(final Node sourceNode) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_TARGET_ASSOCS) - .setLong("sourceId", sourceNode.getId()); - return query.list(); - } - }; - List queryResults = (List) getHibernateTemplate().execute(callback); - return queryResults; - } - - @SuppressWarnings("unchecked") - public List getSourceNodeAssocs(final Node targetNode) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_SOURCE_ASSOCS) - .setLong("targetId", targetNode.getId()); - return query.list(); - } - }; - List queryResults = (List) getHibernateTemplate().execute(callback); - return queryResults; - } - - public void deleteNodeAssoc(NodeAssoc assoc) - { - // Remove instance - getHibernateTemplate().delete(assoc); - // Flush to ensure that the database constraints aren't violated if the assoc - // is recreated in the transaction - 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 Transaction getLastTxn(final StoreRef storeRef) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - 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 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; - } -} +/* + * 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.hibernate; + +import java.io.Serializable; +import java.net.InetAddress; +import java.net.UnknownHostException; +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.zip.CRC32; + +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.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.domain.hibernate.ChildAssocImpl; +import org.alfresco.repo.domain.hibernate.NodeAssocImpl; +import org.alfresco.repo.domain.hibernate.NodeImpl; +import org.alfresco.repo.domain.hibernate.NodeStatusImpl; +import org.alfresco.repo.domain.hibernate.ServerImpl; +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; +import org.springframework.orm.hibernate3.HibernateCallback; +import org.springframework.orm.hibernate3.support.HibernateDaoSupport; + +/** + * Hibernate-specific implementation of the persistence-independent node DAO interface + * + * @author Derek Hulley + */ +public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements NodeDaoService, TransactionalDao +{ + private static final String QUERY_GET_ALL_STORES = "store.GetAllStores"; + private static final String UPDATE_SET_CHILD_ASSOC_NAME = "node.updateChildAssocName"; + private static final String QUERY_GET_CHILD_ASSOCS = "node.GetChildAssocs"; + private static final String QUERY_GET_CHILD_ASSOC_BY_TYPE_AND_NAME = "node.GetChildAssocByTypeAndName"; + private static final String QUERY_GET_CHILD_ASSOC_REFS = "node.GetChildAssocRefs"; + private static final String QUERY_GET_NODE_ASSOC = "node.GetNodeAssoc"; + 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_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); + + /** a uuid identifying this unique instance */ + private final String uuid; + + private static TransactionAwareSingleton serverIdSingleton = new TransactionAwareSingleton(); + private final String ipAddress; + + /** + * + */ + public HibernateNodeDaoServiceImpl() + { + this.uuid = GUID.generate(); + try + { + ipAddress = InetAddress.getLocalHost().getHostAddress(); + } + catch (UnknownHostException e) + { + throw new AlfrescoRuntimeException("Failed to get server IP address", e); + } + } + + /** + * Checks equality by type and uuid + */ + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + else if (!(obj instanceof HibernateNodeDaoServiceImpl)) + { + return false; + } + HibernateNodeDaoServiceImpl that = (HibernateNodeDaoServiceImpl) obj; + return this.uuid.equals(that.uuid); + } + + /** + * @see #uuid + */ + public int hashCode() + { + return uuid.hashCode(); + } + + /** + * Gets/creates the server instance to use for the life of this instance + */ + private Server getServer() + { + Long serverId = serverIdSingleton.get(); + Server server = null; + if (serverId != null) + { + server = (Server) getSession().get(ServerImpl.class, serverId); + if (server != null) + { + return server; + } + } + try + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session + .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_SERVER_BY_IPADDRESS) + .setString("ipAddress", ipAddress); + return query.uniqueResult(); + } + }; + server = (Server) getHibernateTemplate().execute(callback); + // create it if it doesn't exist + if (server == null) + { + server = new ServerImpl(); + server.setIpAddress(ipAddress); + try + { + getSession().save(server); + } + catch (DataIntegrityViolationException e) + { + // get it again + server = (Server) getHibernateTemplate().execute(callback); + if (server == null) + { + throw new AlfrescoRuntimeException("Unable to create server instance: " + ipAddress); + } + } + } + // push the value into the singleton + serverIdSingleton.put(server.getId()); + + return server; + } + catch (Exception e) + { + throw new AlfrescoRuntimeException("Failed to create server instance", e); + } + } + + private static final String RESOURCE_KEY_TRANSACTION_ID = "hibernate.transaction.id"; + private Transaction getCurrentTransaction() + { + Transaction transaction = null; + Serializable txnId = (Serializable) AlfrescoTransactionSupport.getResource(RESOURCE_KEY_TRANSACTION_ID); + if (txnId == null) + { + // no transaction instance has been bound to the transaction + transaction = new TransactionImpl(); + transaction.setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); + transaction.setServer(getServer()); + txnId = getHibernateTemplate().save(transaction); + // bind the id + AlfrescoTransactionSupport.bindResource(RESOURCE_KEY_TRANSACTION_ID, txnId); + } + else + { + transaction = (Transaction) getHibernateTemplate().get(TransactionImpl.class, txnId); + } + return transaction; + } + + /** + * Does this Session contain any changes which must be + * synchronized with the store? + * + * @return true => changes are pending + */ + public boolean isDirty() + { + // create a callback for the task + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + return session.isDirty(); + } + }; + // execute the callback + return ((Boolean)getHibernateTemplate().execute(callback)).booleanValue(); + } + + /** + * Just flushes the session + */ + public void flush() + { + getSession().flush(); + } + + /** + * @see #QUERY_GET_ALL_STORES + */ + @SuppressWarnings("unchecked") + public List getStores() + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_ALL_STORES); + return query.list(); + } + }; + List queryResults = (List) getHibernateTemplate().execute(callback); + // done + return queryResults; + } + + /** + * Ensures that the store protocol/identifier combination is unique + */ + public Store createStore(String protocol, String identifier) + { + // ensure that the name isn't in use + Store store = getStore(protocol, identifier); + if (store != null) + { + throw new RuntimeException("A store already exists: \n" + + " protocol: " + protocol + "\n" + + " identifier: " + identifier + "\n" + + " store: " + store); + } + + store = new StoreImpl(); + // set key + store.setKey(new StoreKey(protocol, identifier)); + // persist so that it is present in the hibernate cache + getHibernateTemplate().save(store); + // create and assign a root node + Node rootNode = newNode( + store, + GUID.generate(), + ContentModel.TYPE_STOREROOT); + store.setRootNode(rootNode); + // done + return store; + } + + public Store getStore(String protocol, String identifier) + { + StoreKey storeKey = new StoreKey(protocol, identifier); + Store store = (Store) getHibernateTemplate().get(StoreImpl.class, storeKey); + // done + return store; + } + + /** + * Fetch the node status, if it exists + */ + public NodeStatus getNodeStatus(NodeRef nodeRef, boolean update) + { + NodeKey nodeKey = new NodeKey(nodeRef); + NodeStatus status = null; + try + { + status = (NodeStatus) getHibernateTemplate().get(NodeStatusImpl.class, nodeKey); + } + catch (DataAccessException e) + { + if (e.contains(ObjectDeletedException.class)) + { + // the object no longer exists + return null; + } + throw e; + } + // create if necessary + 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; + } + + public void recordChangeId(NodeRef nodeRef) + { + NodeKey key = new NodeKey(nodeRef); + + NodeStatus status = (NodeStatus) getHibernateTemplate().get(NodeStatusImpl.class, key); + if (status == null) + { + // the node never existed or the status was deleted + return; + } + else + { + status.getTransaction().setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); + } + } + + public Node newNode(Store store, String uuid, QName nodeTypeQName) throws InvalidTypeException + { + NodeKey key = new NodeKey(store.getKey(), uuid); + + // create (or reuse) the mandatory node status + NodeStatus status = (NodeStatus) getHibernateTemplate().get(NodeStatusImpl.class, key); + if (status == null) + { + status = new NodeStatusImpl(); + status.setKey(key); + } + else + { + // The node existed at some point. + // Although unlikely, it is possible that the node was deleted in this transaction. + // If that is the case, then the session has to be flushed so that the database + // constraints aren't violated as the node creation will write to the database to + // get an ID + if (status.getTransaction().getChangeTxnId().equals(AlfrescoTransactionSupport.getTransactionId())) + { + // flush + getHibernateTemplate().flush(); + } + } + + // build a concrete node based on a bootstrap type + Node node = new NodeImpl(); + // set other required properties + node.setStore(store); + node.setUuid(uuid); + node.setTypeQName(nodeTypeQName); + // persist the node + getHibernateTemplate().save(node); + + // set required status properties + status.setNode(node); + // assign a transaction + if (status.getTransaction() == null) + { + status.setTransaction(getCurrentTransaction()); + } + // persist the nodestatus + getHibernateTemplate().save(status); + + // done + return node; + } + + public Node getNode(NodeRef nodeRef) + { + // get it via the node status + NodeStatus status = getNodeStatus(nodeRef, false); + if (status == null) + { + // no status implies no node + return null; + } + else + { + // a status may have a node + Node node = status.getNode(); + return node; + } + } + + /** + * Manually ensures that all cascading of associations is taken care of + */ + public void deleteNode(Node node, boolean cascade) + { + Set deletedChildAssocIds = new HashSet(10); + deleteNodeInternal(node, cascade, deletedChildAssocIds); + } + + /** + * + * @param node + * @param cascade true to cascade delete + * @param deletedChildAssocIds previously deleted child associations + */ + private void deleteNodeInternal(Node node, boolean cascade, Set deletedChildAssocIds) + { + // delete all parent assocs + if (logger.isDebugEnabled()) + { + logger.debug("Deleting parent assocs of node " + node.getId()); + } + + Collection parentAssocs = node.getParentAssocs(); + parentAssocs = new ArrayList(parentAssocs); + for (ChildAssoc assoc : parentAssocs) + { + deleteChildAssocInternal(assoc, false, deletedChildAssocIds); // we don't cascade upwards + } + // delete all child assocs + if (logger.isDebugEnabled()) + { + logger.debug("Deleting child assocs of node " + node.getId()); + } + Collection childAssocs = getChildAssocs(node); + childAssocs = new ArrayList(childAssocs); + for (ChildAssoc assoc : childAssocs) + { + deleteChildAssocInternal(assoc, cascade, deletedChildAssocIds); // potentially cascade downwards + } + // delete all node associations to and from + if (logger.isDebugEnabled()) + { + logger.debug("Deleting source and target assocs of node " + node.getId()); + } + List nodeAssocs = getNodeAssocsToAndFrom(node); + for (NodeAssoc assoc : nodeAssocs) + { + getHibernateTemplate().delete(assoc); + } + // update the node status + NodeRef nodeRef = node.getNodeRef(); + NodeStatus nodeStatus = getNodeStatus(nodeRef, true); + nodeStatus.setNode(null); + nodeStatus.getTransaction().setChangeTxnId(AlfrescoTransactionSupport.getTransactionId()); + // finally delete the node + getHibernateTemplate().delete(node); + // flush to ensure constraints can't be violated + getSession().flush(); + // done + } + + private long getCrc(String str) + { + CRC32 crc = new CRC32(); + crc.update(str.getBytes()); + return crc.getValue(); + } + + private static final String TRUNCATED_NAME_INDICATOR = "~~~"; + private String getShortName(String str) + { + int length = str.length(); + if (length <= 50) + { + return str; + } + else + { + StringBuilder ret = new StringBuilder(50); + ret.append(str.substring(0, 47)).append(TRUNCATED_NAME_INDICATOR); + return ret.toString(); + } + } + + public ChildAssoc newChildAssoc( + Node parentNode, + Node childNode, + boolean isPrimary, + QName assocTypeQName, + QName qname) + { + /* + * This initial child association creation will fail IFF there is already + * an association of the given type and name between the two nodes. For new association + * creation, this can only occur if two transactions attempt to create a secondary + * child association between the same two nodes. As this is unlikely, it is + * appropriate to just throw a runtime exception and let the second transaction + * fail. + * + * We don't need to flush the session beforehand as there won't be any deletions + * of the assocation pending. The association deletes, on the other hand, have + * to flush early in order to ensure that the database unique index isn't violated + * if the association is recreated subsequently. + */ + + // assign a random name to the node + String randomName = GUID.generate(); + + ChildAssoc assoc = new ChildAssocImpl(); + assoc.setTypeQName(assocTypeQName); + assoc.setChildNodeName(randomName); + assoc.setChildNodeNameCrc(-1L); // random names compete only with each other + assoc.setQname(qname); + assoc.setIsPrimary(isPrimary); + // maintain inverse sets + assoc.buildAssociation(parentNode, childNode); + // persist it + getHibernateTemplate().save(assoc); + // done + return assoc; + } + + public void setChildNameUnique(final ChildAssoc childAssoc, String childName) + { + /* + * As the Hibernate session is rendered useless when an exception is + * bubbled up, we go direct to the database to update the child association. + * This preserves the session and client code can catch the resulting + * exception and react to it whilst in the same transaction. + * + * We ensure that case-insensitivity is maintained by persisting + * the lowercase version of the child node name. + */ + + String childNameNew = null; + long crc = -1; + if (childName == null) + { + // random names compete only with each other, i.e. not at all + childNameNew = GUID.generate(); + crc = -1; + } + else + { + // assigned names compete exactly + childNameNew = childName.toLowerCase(); + crc = getCrc(childNameNew); + } + + final String childNameNewShort = getShortName(childNameNew); + final long childNameNewCrc = crc; + + // check if the name has changed + if (childAssoc.getChildNodeNameCrc() == childNameNewCrc) + { + if (childAssoc.getChildNodeName().equals(childNameNewShort)) + { + // nothing changed + return; + } + } + + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + session.flush(); + Query query = session + .getNamedQuery(HibernateNodeDaoServiceImpl.UPDATE_SET_CHILD_ASSOC_NAME) + .setString("newName", childNameNewShort) + .setLong("newNameCrc", childNameNewCrc) + .setLong("childAssocId", childAssoc.getId()); + return (Integer) query.executeUpdate(); + } + }; + try + { + Integer count = (Integer) getHibernateTemplate().execute(callback); + // refresh the entity directly + if (count.intValue() == 0) + { + if (logger.isDebugEnabled()) + { + logger.debug("ChildAssoc not updated: " + childAssoc.getId()); + } + } + else + { + getHibernateTemplate().refresh(childAssoc); + } + } + catch (DataIntegrityViolationException e) + { + NodeRef parentNodeRef = childAssoc.getParent().getNodeRef(); + QName assocTypeQName = childAssoc.getTypeQName(); + throw new DuplicateChildNodeNameException(parentNodeRef, assocTypeQName, childName); + } + } + + @SuppressWarnings("unchecked") + public Collection getChildAssocs(final Node parentNode) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session + .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOCS) + .setLong("parentId", parentNode.getId()); + return query.list(); + } + }; + List queryResults = (List) getHibernateTemplate().execute(callback); + return queryResults; + } + + @SuppressWarnings("unchecked") + public Collection getChildAssocRefs(final Node parentNode) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session + .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_REFS) + .setLong("parentId", parentNode.getId()); + return query.list(); + } + }; + List queryResults = (List) getHibernateTemplate().execute(callback); + Collection refs = new ArrayList(queryResults.size()); + NodeRef parentNodeRef = parentNode.getNodeRef(); + for (Object[] row : queryResults) + { + String childProtocol = (String) row[5]; + String childIdentifier = (String) row[6]; + String childUuid = (String) row[7]; + NodeRef childNodeRef = new NodeRef(new StoreRef(childProtocol, childIdentifier), childUuid); + QName assocTypeQName = (QName) row[0]; + QName assocQName = (QName) row[1]; + Boolean assocIsPrimary = (Boolean) row[2]; + Integer assocIndex = (Integer) row[3]; + ChildAssociationRef assocRef = new ChildAssociationRef( + assocTypeQName, + parentNodeRef, + assocQName, + childNodeRef, + assocIsPrimary.booleanValue(), + assocIndex.intValue()); + refs.add(assocRef); + } + return refs; + } + + public ChildAssoc getChildAssoc( + Node parentNode, + Node childNode, + QName assocTypeQName, + QName qname) + { + ChildAssociationRef childAssocRef = new ChildAssociationRef( + assocTypeQName, + parentNode.getNodeRef(), + qname, + childNode.getNodeRef()); + // get all the parent's child associations + Collection assocs = getChildAssocs(parentNode); + // hunt down the desired assoc + for (ChildAssoc assoc : assocs) + { + // is it a match? + if (!assoc.getChildAssocRef().equals(childAssocRef)) // not a match + { + continue; + } + else + { + return assoc; + } + } + // not found + return null; + } + + public ChildAssoc getChildAssoc(final Node parentNode, final QName assocTypeQName, final String childName) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + String childNameLower = childName.toLowerCase(); + String childNameShort = getShortName(childNameLower); + long childNameLowerCrc = getCrc(childNameLower); + Query query = session + .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_BY_TYPE_AND_NAME) + .setLong("parentId", parentNode.getId()) + .setParameter("typeQName", assocTypeQName) + .setParameter("childNodeName", childNameShort) + .setLong("childNodeNameCrc", childNameLowerCrc); + return query.uniqueResult(); + } + }; + ChildAssoc childAssoc = (ChildAssoc) getHibernateTemplate().execute(callback); + return childAssoc; + } + + /** + * Public level entry-point. + */ + public void deleteChildAssoc(ChildAssoc assoc, boolean cascade) + { + Set deletedChildAssocIds = new HashSet(10); + deleteChildAssocInternal(assoc, cascade, deletedChildAssocIds); + } + + /** + * Cascade deletion of child associations, recording the IDs of deleted assocs. + * + * @param assoc the association to delete + * @param cascade true to cascade to the child node of the association + * @param deletedChildAssocIds already-deleted associations + */ + private void deleteChildAssocInternal(ChildAssoc assoc, boolean cascade, Set deletedChildAssocIds) + { + Long childAssocId = assoc.getId(); + if (deletedChildAssocIds.contains(childAssocId)) + { + if (logger.isDebugEnabled()) + { + logger.debug("Ignoring parent-child association " + assoc.getId()); + } + return; + } + + if (logger.isDebugEnabled()) + { + logger.debug( + "Deleting parent-child association " + assoc.getId() + + (cascade ? " with" : " without") + " cascade:" + + assoc.getParent().getId() + " -> " + assoc.getChild().getId()); + } + + Node childNode = assoc.getChild(); + + // maintain inverse association sets + assoc.removeAssociation(); + // remove instance + getHibernateTemplate().delete(assoc); + deletedChildAssocIds.add(childAssocId); // ensure that we don't attempt to delete it twice + + if (cascade && assoc.getIsPrimary()) // the assoc is primary + { + // delete the child node + deleteNodeInternal(childNode, cascade, deletedChildAssocIds); + /* + * The child node deletion will cascade delete all assocs to + * and from it, but we have safely removed this one, so no + * duplicate call will be received to do this + */ + } + + // To ensure the validity of the constraint enforcement by the database, + // we have to flush here + getSession().flush(); + } + + public ChildAssoc getPrimaryParentAssoc(Node node) + { + // get the assocs pointing to the node + Collection parentAssocs = node.getParentAssocs(); + ChildAssoc primaryAssoc = null; + for (ChildAssoc assoc : parentAssocs) + { + // ignore non-primary assocs + if (!assoc.getIsPrimary()) + { + continue; + } + else if (primaryAssoc != null) + { + // we have more than one somehow + throw new DataIntegrityViolationException( + "Multiple primary associations: \n" + + " child: " + node + "\n" + + " first primary assoc: " + primaryAssoc + "\n" + + " second primary assoc: " + assoc); + } + primaryAssoc = assoc; + // we keep looping to hunt out data integrity issues + } + // did we find a primary assoc? + if (primaryAssoc == null) + { + // the only condition where this is allowed is if the given node is a root node + Store store = node.getStore(); + Node rootNode = store.getRootNode(); + if (rootNode == null) + { + // a store without a root node - the entire store is hosed + throw new DataIntegrityViolationException("Store has no root node: \n" + + " store: " + store); + } + if (!rootNode.equals(node)) + { + // it wasn't the root node + throw new DataIntegrityViolationException("Non-root node has no primary parent: \n" + + " child: " + node); + } + } + // done + return primaryAssoc; + } + + public NodeAssoc newNodeAssoc(Node sourceNode, Node targetNode, QName assocTypeQName) + { + NodeAssoc assoc = new NodeAssocImpl(); + assoc.setTypeQName(assocTypeQName); + assoc.buildAssociation(sourceNode, targetNode); + // persist + try + { + getHibernateTemplate().save(assoc); + } + catch (DataIntegrityViolationException e) + { + throw new AssociationExistsException( + sourceNode.getNodeRef(), + targetNode.getNodeRef(), + assocTypeQName, + e); + } + // done + return assoc; + } + + @SuppressWarnings("unchecked") + public List getNodeAssocsToAndFrom(final Node node) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session + .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODE_ASSOCS_TO_AND_FROM) + .setLong("nodeId", node.getId()); + return query.list(); + } + }; + List results = (List) getHibernateTemplate().execute(callback); + return results; + } + + public NodeAssoc getNodeAssoc( + final Node sourceNode, + final Node targetNode, + final QName assocTypeQName) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session + .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODE_ASSOC) + .setLong("sourceId", sourceNode.getId()) + .setLong("targetId", targetNode.getId()) + .setParameter("assocTypeQName", assocTypeQName); + return query.uniqueResult(); + } + }; + NodeAssoc result = (NodeAssoc) getHibernateTemplate().execute(callback); + return result; + } + + @SuppressWarnings("unchecked") + public List getTargetNodeAssocs(final Node sourceNode) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session + .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_TARGET_ASSOCS) + .setLong("sourceId", sourceNode.getId()); + return query.list(); + } + }; + List queryResults = (List) getHibernateTemplate().execute(callback); + return queryResults; + } + + @SuppressWarnings("unchecked") + public List getSourceNodeAssocs(final Node targetNode) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session + .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_SOURCE_ASSOCS) + .setLong("targetId", targetNode.getId()); + return query.list(); + } + }; + List queryResults = (List) getHibernateTemplate().execute(callback); + return queryResults; + } + + public void deleteNodeAssoc(NodeAssoc assoc) + { + // Remove instance + getHibernateTemplate().delete(assoc); + // Flush to ensure that the database constraints aren't violated if the assoc + // is recreated in the transaction + 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 = "txn.GetLastTxnId"; + 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_NEXT_REMOTE_TXNS = "txn.GetNextRemoteTxns"; + private static final String QUERY_GET_TXN_CHANGES_FOR_STORE = "txn.GetTxnChangesForStore"; + private static final String QUERY_GET_TXN_CHANGES = "txn.GetTxnChanges"; + + public Transaction getTxnById(long txnId) + { + return (Transaction) getSession().get(TransactionImpl.class, new Long(txnId)); + } + + @SuppressWarnings("unchecked") + public Transaction getLastTxn() + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_LAST_TXN_ID); + query.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 Transaction getLastTxnForStore(final StoreRef storeRef) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + 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 getTxnUpdateCount(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) + .setReadOnly(true); + return query.uniqueResult(); + } + }; + Integer count = (Integer) getHibernateTemplate().execute(callback); + // done + return count; + } + + @SuppressWarnings("unchecked") + public int getTxnDeleteCount(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) + .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 long lastTxnId, final int count) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_NEXT_TXNS); + query.setLong("lastTxnId", lastTxnId) + .setMaxResults(count) + .setReadOnly(true); + return query.list(); + } + }; + List results = (List) getHibernateTemplate().execute(callback); + // done + return results; + } + + @SuppressWarnings("unchecked") + public List getNextRemoteTxns(final long lastTxnId, final int count) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_NEXT_REMOTE_TXNS); + query.setLong("lastTxnId", lastTxnId) + .setString("serverIpAddress", ipAddress) + .setMaxResults(count) + .setReadOnly(true); + return query.list(); + } + }; + 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; + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java b/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java index c715264264..2d4f597540 100644 --- a/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java +++ b/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java @@ -16,20 +16,30 @@ */ package org.alfresco.repo.node.index; +import java.util.List; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import net.sf.acegisecurity.Authentication; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.Transaction; import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.search.Indexer; +import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; 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.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.util.PropertyCheck; import org.alfresco.util.VmShutdownListener; @@ -224,4 +234,229 @@ public abstract class AbstractReindexComponent implements IndexRecovery } } } + + /** + * Gets the last indexed transaction working back from the provided index. + * This method can be used to hunt for a starting point for indexing of + * transactions not yet in the index. + */ + protected long getLastIndexedTxn(long lastTxnId) + { + // get the last transaction + long lastFoundTxnId = lastTxnId + 10L; + boolean found = false; + while (!found && lastFoundTxnId >= 0) + { + // reduce the transaction ID + lastFoundTxnId = lastFoundTxnId - 10L; + // break out as soon as we find a transaction that is in the index + found = isTxnIdPresentInIndex(lastFoundTxnId); + if (found) + { + break; + } + } + // done + if (logger.isDebugEnabled()) + { + logger.debug("Found last index txn before " + lastTxnId + ": " + lastFoundTxnId); + } + return lastFoundTxnId; + } + + protected boolean isTxnIdPresentInIndex(long txnId) + { + if (logger.isDebugEnabled()) + { + logger.debug("Checking for transaction in index: " + txnId); + } + + Transaction txn = nodeDaoService.getTxnById(txnId); + if (txn == null) + { + return true; + } + + // count the changes in the transaction + int updateCount = nodeDaoService.getTxnUpdateCount(txnId); + int deleteCount = nodeDaoService.getTxnDeleteCount(txnId); + if (logger.isDebugEnabled()) + { + logger.debug("Transaction has " + updateCount + " updates and " + deleteCount + " deletes: " + txnId); + } + + // get the stores + boolean found = false; + List storeRefs = nodeService.getStores(); + for (StoreRef storeRef : storeRefs) + { + boolean inStore = isTxnIdPresentInIndex(storeRef, txn, updateCount, deleteCount); + if (inStore) + { + // found in a particular store + found = true; + break; + } + } + // done + if (logger.isDebugEnabled()) + { + logger.debug("Transaction " + txnId + " was " + (found ? "found" : "not found") + " in indexes."); + } + return found; + } + + /** + * @return Returns true if the given transaction is indexed in the in the + */ + private boolean isTxnIdPresentInIndex(StoreRef storeRef, Transaction txn, int updateCount, int deleteCount) + { + long txnId = txn.getId(); + String changeTxnId = txn.getChangeTxnId(); + // do the most update check, which is most common + if (updateCount > 0) + { + 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); + + if (results.length() > 0) + { + if (logger.isDebugEnabled()) + { + logger.debug("Index has results for txn (OK): " + txnId); + } + 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): " + txnId); + } + return false; + } + } + finally + { + if (results != null) { results.close(); } + } + } + // 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 + List nodeRefs = nodeDaoService.getTxnChangesForStore(storeRef, txnId); + for (NodeRef nodeRef : nodeRefs) + { + if (logger.isDebugEnabled()) + { + logger.debug("Searching for node in index: \n" + + " node: " + nodeRef + "\n" + + " txn: " + txnId); + } + // 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()) + { + logger.debug("Index is in synch with transaction: " + txnId); + } + return true; + } + + /** + * Perform a full reindexing of the given transaction in the context of a completely + * new transaction. + * + * @param txnId the transaction identifier + */ + protected void reindexTransaction(final long txnId) + { + if (logger.isDebugEnabled()) + { + logger.debug("Reindexing transaction: " + txnId); + } + + TransactionWork reindexWork = new TransactionWork() + { + public Object doWork() throws Exception + { + // 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; + } + }; + TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, reindexWork, true); + // done + } } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java b/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java index e67c1648bf..f7fc4047f1 100644 --- a/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java +++ b/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java @@ -21,27 +21,25 @@ import java.util.List; import org.alfresco.i18n.I18NUtil; import org.alfresco.model.ContentModel; 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.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.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** - * Component to check and recover the indexes. + * Component to check and recover the indexes. By default, the server is + * put into read-only mode during the reindex process in order to prevent metadata changes. + * This is not critical and can be {@link #setLockServer(boolean) switched off} if the + * server is required immediately. * * @author Derek Hulley */ public class FullIndexRecoveryComponent extends AbstractReindexComponent { - private static final String ERR_STORE_NOT_UP_TO_DATE = "index.recovery.store_not_up_to_date"; + private static final String ERR_INDEX_OUT_OF_DATE = "index.recovery.out_of_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"; @@ -51,17 +49,25 @@ public class FullIndexRecoveryComponent extends AbstractReindexComponent public static enum RecoveryMode { - /** Do nothing - not even a check */ + /** Do nothing - not even a check. */ NONE, - /** Perform a quick check on the state of the indexes only */ + /** + * 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 */ + /** + * Performs a validation and starts a quick recovery, if necessary. + */ AUTO, - /** Performs a full pass-through of all recorded transactions to ensure that the indexes are up to date */ + /** + * Performs a full pass-through of all recorded transactions to ensure that the indexes + * are up to date. + */ FULL; } private RecoveryMode recoveryMode; + private boolean lockServer; public FullIndexRecoveryComponent() { @@ -69,7 +75,8 @@ public class FullIndexRecoveryComponent extends AbstractReindexComponent } /** - * Set the type of recovery to perform. + * Set the type of recovery to perform. Default is {@link RecoveryMode#VALIDATE to validate} + * the indexes only. * * @param recoveryMode one of the {@link RecoveryMode } values */ @@ -77,7 +84,18 @@ public class FullIndexRecoveryComponent extends AbstractReindexComponent { this.recoveryMode = RecoveryMode.valueOf(recoveryMode); } - + + /** + * Set this on to put the server into READ-ONLY mode for the duration of the index recovery. + * The default is true, i.e. the server will be locked against further updates. + * + * @param lockServer true to force the server to be read-only + */ + public void setLockServer(boolean lockServer) + { + this.lockServer = lockServer; + } + @Override protected void reindexImpl() { @@ -99,25 +117,22 @@ public class FullIndexRecoveryComponent extends AbstractReindexComponent } else // validate first { - List storeRefs = nodeService.getStores(); - for (StoreRef storeRef : storeRefs) + Transaction txn = nodeDaoService.getLastTxn(); + if (txn == null) { - // 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); + // no transactions - just bug out + return; + } + long txnId = txn.getId(); + boolean txnInIndex = isTxnIdPresentInIndex(txnId); + if (!txnInIndex) + { + String msg = I18NUtil.getMessage(ERR_INDEX_OUT_OF_DATE); logger.warn(msg); - // the store is out of date - validation failed + // this store isn't up to date if (recoveryMode == RecoveryMode.VALIDATE) { - // next store - continue; + // the store is out of date - validation failed } else if (recoveryMode == RecoveryMode.AUTO) { @@ -130,8 +145,11 @@ public class FullIndexRecoveryComponent extends AbstractReindexComponent boolean allowWrite = !transactionService.isReadOnly(); try { - // set the server into read-only mode - transactionService.setAllowWrite(false); + if (lockServer) + { + // set the server into read-only mode + transactionService.setAllowWrite(false); + } // do we need to perform a full recovery if (fullRecoveryRequired) @@ -160,8 +178,9 @@ public class FullIndexRecoveryComponent extends AbstractReindexComponent Transaction lastTxn = null; while(true) { + long lastTxnId = (lastTxn == null) ? -1L : lastTxn.getId().longValue(); List nextTxns = nodeDaoService.getNextTxns( - lastTxn, + lastTxnId, MAX_TRANSACTIONS_PER_ITERATION); // reindex each transaction @@ -256,125 +275,4 @@ public class FullIndexRecoveryComponent extends AbstractReindexComponent TransactionUtil.executeInNonPropagatingUserTransaction(transactionService, reindexWork, true); // done } - - private boolean isTxnIdPresentInIndex(StoreRef storeRef, Transaction txn) - { - if (logger.isDebugEnabled()) - { - logger.debug("Checking for transaction in index: \n" + - " store: " + storeRef + "\n" + - " txn: " + txn); - } - - 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()) - { - logger.debug("Transaction has " + updateCount + " updates and " + deleteCount + " deletes: " + txn); - } - - // 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) - { - 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); - - if (results.length() > 0) - { - if (logger.isDebugEnabled()) - { - logger.debug("Index has results for txn (OK): " + txn); - } - 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(); } - } - } - // 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) - { - if (logger.isDebugEnabled()) - { - logger.debug("Searching for node in index: \n" + - " node: " + nodeRef + "\n" + - " txn: " + txn); - } - // 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()) - { - 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/IndexRemoteTransactionTracker.java b/source/java/org/alfresco/repo/node/index/IndexRemoteTransactionTracker.java new file mode 100644 index 0000000000..5f0c49e95a --- /dev/null +++ b/source/java/org/alfresco/repo/node/index/IndexRemoteTransactionTracker.java @@ -0,0 +1,119 @@ +/* + * 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.domain.Transaction; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Component to check and recover the indexes. + * + * @author Derek Hulley + */ +public class IndexRemoteTransactionTracker extends AbstractReindexComponent +{ + private static Log logger = LogFactory.getLog(IndexRemoteTransactionTracker.class); + + private boolean remoteOnly; + private long currentTxnId; + + public IndexRemoteTransactionTracker() + { + remoteOnly = true; + currentTxnId = -1L; + } + + /** + * Set whether or not this component should only track remote transactions. + * By default, it is true, but under certain test conditions, it may + * be desirable to track local transactions too; e.g. during testing of clustering + * when running multiple instances on the same machine. + * + * @param remoteOnly true to reindex only those transactions that were + * committed to the database by a remote server. + */ + public void setRemoteOnly(boolean remoteOnly) + { + this.remoteOnly = remoteOnly; + } + + + + @Override + protected void reindexImpl() + { + if (currentTxnId < 0) + { + // initialize the starting point + Transaction lastTxn = nodeDaoService.getLastTxn(); + if (lastTxn == null) + { + // there is nothing to do + return; + } + long lastTxnId = lastTxn.getId(); + currentTxnId = getLastIndexedTxn(lastTxnId); + } + + if (logger.isDebugEnabled()) + { + logger.debug("Performing index tracking from txn " + currentTxnId); + } + + while (true) + { + // get next transactions to index + List txns = getNextTransactions(currentTxnId); + if (txns.size() == 0) + { + // we've caught up + break; + } + // break out if the VM is shutting down + if (isShuttingDown()) + { + break; + } + // reindex all "foreign" or "local" transactions, one at a time + for (Transaction txn : txns) + { + long txnId = txn.getId(); + reindexTransaction(txnId); + currentTxnId = txnId; + } + } + } + + private static final int MAX_TXN_COUNT = 1000; + private List getNextTransactions(long currentTxnId) + { + List txns = null; + if (remoteOnly) + { + txns = nodeDaoService.getNextRemoteTxns(currentTxnId, MAX_TXN_COUNT); + } + else + { + txns = nodeDaoService.getNextTxns(currentTxnId, MAX_TXN_COUNT); + } + // done + return txns; + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/node/index/IndexRemoteTransactionTrackerTest.java b/source/java/org/alfresco/repo/node/index/IndexRemoteTransactionTrackerTest.java new file mode 100644 index 0000000000..a33ff0bf40 --- /dev/null +++ b/source/java/org/alfresco/repo/node/index/IndexRemoteTransactionTrackerTest.java @@ -0,0 +1,125 @@ +/* + * 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.ContentStore; +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.transaction.TransactionComponent; +import org.alfresco.repo.transaction.TransactionUtil; +import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.model.FileFolderService; +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.SearchService; +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; + +/** + * @see org.alfresco.repo.node.index.IndexRemoteTransactionTracker + * + * @author Derek Hulley + */ +@SuppressWarnings("unused") +public class IndexRemoteTransactionTrackerTest 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 Indexer indexer; + private NodeRef rootNodeRef; + + private IndexRemoteTransactionTracker indexTracker; + + public 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) ctx.getBean("indexerComponent"); + NodeDaoService nodeDaoService = (NodeDaoService) ctx.getBean("nodeDaoService"); + TransactionService transactionService = serviceRegistry.getTransactionService(); + indexTracker = new IndexRemoteTransactionTracker(); + indexTracker.setAuthenticationComponent(authenticationComponent); + indexTracker.setFtsIndexer(ftsIndexer); + indexTracker.setIndexer(indexer); + indexTracker.setNodeDaoService(nodeDaoService); + indexTracker.setNodeService(nodeService); + indexTracker.setSearcher(searchService); + indexTracker.setTransactionComponent((TransactionComponent)transactionService); + + // authenticate + authenticationComponent.setSystemUserAsCurrentUser(); + + // disable indexing + TransactionWork createNodeWork = new TransactionWork() + { + public ChildAssociationRef doWork() throws Exception + { + StoreRef storeRef = new StoreRef("test", getName() + "-" + System.currentTimeMillis()); + NodeRef rootNodeRef = null; + if (!nodeService.exists(storeRef)) + { + nodeService.createStore(storeRef.getProtocol(), storeRef.getIdentifier()); + } + rootNodeRef = nodeService.getRootNode(storeRef); + // create another node + ChildAssociationRef childAssocRef = nodeService.createNode( + rootNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQName(NamespaceService.ALFRESCO_URI, "xyz"), + ContentModel.TYPE_FOLDER); + // remove the node from the index + indexer.deleteNode(childAssocRef); + return childAssocRef; + } + }; + ChildAssociationRef childAssocRef = TransactionUtil.executeInUserTransaction(transactionService, createNodeWork); + } + + public void testSetup() throws Exception + { + + } + + public synchronized void testStartup() throws Exception + { + indexTracker.reindex(); + indexTracker.reindex(); + } +} diff --git a/source/java/org/alfresco/repo/rule/BaseRuleTest.java b/source/java/org/alfresco/repo/rule/BaseRuleTest.java index 332f0495dd..d15d1ea7d6 100644 --- a/source/java/org/alfresco/repo/rule/BaseRuleTest.java +++ b/source/java/org/alfresco/repo/rule/BaseRuleTest.java @@ -118,7 +118,8 @@ public class BaseRuleTest extends BaseSpringTest this.transactionService = (TransactionService)this.applicationContext.getBean("transactionComponent"); this.authenticationComponent = (AuthenticationComponent)this.applicationContext.getBean("authenticationComponent"); - authenticationComponent.setSystemUserAsCurrentUser(); + //authenticationComponent.setSystemUserAsCurrentUser(); + authenticationComponent.setCurrentUser("admin"); // Get the rule type this.ruleType = this.ruleService.getRuleType(RULE_TYPE_NAME); diff --git a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java index c00ed1e840..0374d8092e 100644 --- a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java +++ b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java @@ -149,7 +149,8 @@ public class RuleServiceCoverageTest extends TestCase this.authenticationComponent = (AuthenticationComponent)applicationContext.getBean("authenticationComponent"); //authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName()); - authenticationComponent.setSystemUserAsCurrentUser(); + //authenticationComponent.setSystemUserAsCurrentUser(); + authenticationComponent.setCurrentUser("admin"); this.testStoreRef = this.nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis()); this.rootNodeRef = this.nodeService.getRootNode(this.testStoreRef); diff --git a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java index 9bf1eea747..6d0b9420b7 100644 --- a/source/java/org/alfresco/repo/rule/RuleServiceImpl.java +++ b/source/java/org/alfresco/repo/rule/RuleServiceImpl.java @@ -40,6 +40,8 @@ import org.alfresco.service.cmr.rule.Rule; import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.service.cmr.rule.RuleServiceException; import org.alfresco.service.cmr.rule.RuleType; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.util.GUID; @@ -92,6 +94,11 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService */ private DictionaryService dictionaryService; + /** + * The permission service + */ + private PermissionService permissionService; + /** * The action service implementation which we need for some things. */ @@ -179,6 +186,16 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService this.dictionaryService = dictionaryService; } + /** + * Set the permission service + * + * @param permissionService the permission service + */ + public void setPermissionService(PermissionService permissionService) + { + this.permissionService = permissionService; + } + /** * Set the global rules disabled flag * @@ -572,49 +589,56 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService */ public void saveRule(NodeRef nodeRef, Rule rule) { - disableRules(); - try - { - if (this.nodeService.exists(nodeRef) == false) - { - throw new RuleServiceException("The node does not exist."); - } - - NodeRef ruleNodeRef = rule.getNodeRef(); - if (ruleNodeRef == null) - { - if (this.nodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == false) - { - // Add the actionable aspect - this.nodeService.addAspect(nodeRef, RuleModel.ASPECT_RULES, null); - } - - // Create the action node - ruleNodeRef = this.nodeService.createNode( - getSavedRuleFolderRef(nodeRef), - ContentModel.ASSOC_CONTAINS, - QName.createQName(RuleModel.RULE_MODEL_URI, ASSOC_NAME_RULES_PREFIX + GUID.generate()), - RuleModel.TYPE_RULE).getChildRef(); - - // Set the rule node reference and the owning node reference - rule.setNodeRef(ruleNodeRef); - } - - // Update the properties of the rule - this.nodeService.setProperty(ruleNodeRef, ContentModel.PROP_TITLE, rule.getTitle()); - this.nodeService.setProperty(ruleNodeRef, ContentModel.PROP_DESCRIPTION, rule.getDescription()); - this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_RULE_TYPE, (Serializable)rule.getRuleTypes()); - this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_APPLY_TO_CHILDREN, rule.isAppliedToChildren()); - this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_EXECUTE_ASYNC, rule.getExecuteAsynchronously()); - this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_DISABLED, rule.getRuleDisabled()); - - // Save the rule's action - saveAction(ruleNodeRef, rule); - } - finally - { - enableRules(); - } + if (this.permissionService.hasPermission(nodeRef, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED) + { + disableRules(); + try + { + if (this.nodeService.exists(nodeRef) == false) + { + throw new RuleServiceException("The node does not exist."); + } + + NodeRef ruleNodeRef = rule.getNodeRef(); + if (ruleNodeRef == null) + { + if (this.nodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == false) + { + // Add the actionable aspect + this.nodeService.addAspect(nodeRef, RuleModel.ASPECT_RULES, null); + } + + // Create the action node + ruleNodeRef = this.nodeService.createNode( + getSavedRuleFolderRef(nodeRef), + ContentModel.ASSOC_CONTAINS, + QName.createQName(RuleModel.RULE_MODEL_URI, ASSOC_NAME_RULES_PREFIX + GUID.generate()), + RuleModel.TYPE_RULE).getChildRef(); + + // Set the rule node reference and the owning node reference + rule.setNodeRef(ruleNodeRef); + } + + // Update the properties of the rule + this.nodeService.setProperty(ruleNodeRef, ContentModel.PROP_TITLE, rule.getTitle()); + this.nodeService.setProperty(ruleNodeRef, ContentModel.PROP_DESCRIPTION, rule.getDescription()); + this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_RULE_TYPE, (Serializable)rule.getRuleTypes()); + this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_APPLY_TO_CHILDREN, rule.isAppliedToChildren()); + this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_EXECUTE_ASYNC, rule.getExecuteAsynchronously()); + this.nodeService.setProperty(ruleNodeRef, RuleModel.PROP_DISABLED, rule.getRuleDisabled()); + + // Save the rule's action + saveAction(ruleNodeRef, rule); + } + finally + { + enableRules(); + } + } + else + { + throw new RuleServiceException("Insufficient permissions to save a rule."); + } } /** @@ -667,22 +691,29 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService */ public void removeRule(NodeRef nodeRef, Rule rule) { - if (this.nodeService.exists(nodeRef) == true && - this.nodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true) + if (this.permissionService.hasPermission(nodeRef, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED) { - disableRules(nodeRef); - try - { - NodeRef ruleNodeRef = rule.getNodeRef(); - if (ruleNodeRef != null) - { - this.nodeService.removeChild(getSavedRuleFolderRef(nodeRef), ruleNodeRef); - } - } - finally - { - enableRules(nodeRef); - } + if (this.nodeService.exists(nodeRef) == true && + this.nodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true) + { + disableRules(nodeRef); + try + { + NodeRef ruleNodeRef = rule.getNodeRef(); + if (ruleNodeRef != null) + { + this.nodeService.removeChild(getSavedRuleFolderRef(nodeRef), ruleNodeRef); + } + } + finally + { + enableRules(nodeRef); + } + } + } + else + { + throw new RuleServiceException("Insufficient permissions to remove a rule."); } } @@ -691,20 +722,27 @@ public class RuleServiceImpl implements RuleService, RuntimeRuleService */ public void removeAllRules(NodeRef nodeRef) { - if (this.nodeService.exists(nodeRef) == true && - this.nodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true) + if (this.permissionService.hasPermission(nodeRef, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED) { - NodeRef folder = getSavedRuleFolderRef(nodeRef); - if (folder != null) - { - List ruleChildAssocs = this.nodeService.getChildAssocs( - folder, - RegexQNamePattern.MATCH_ALL, ASSOC_NAME_RULES_REGEX); - for (ChildAssociationRef ruleChildAssoc : ruleChildAssocs) - { - this.nodeService.removeChild(folder, ruleChildAssoc.getChildRef()); - } - } + if (this.nodeService.exists(nodeRef) == true && + this.nodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true) + { + NodeRef folder = getSavedRuleFolderRef(nodeRef); + if (folder != null) + { + List ruleChildAssocs = this.nodeService.getChildAssocs( + folder, + RegexQNamePattern.MATCH_ALL, ASSOC_NAME_RULES_REGEX); + for (ChildAssociationRef ruleChildAssoc : ruleChildAssocs) + { + this.nodeService.removeChild(folder, ruleChildAssoc.getChildRef()); + } + } + } + } + else + { + throw new RuleServiceException("Insufficient permissions to remove a rule."); } } diff --git a/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java b/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java index 10f34d4820..cdadf1e724 100644 --- a/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java +++ b/source/java/org/alfresco/repo/rule/RuleServiceImplTest.java @@ -27,6 +27,8 @@ import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator; import org.alfresco.repo.action.executer.ImageTransformActionExecuter; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.transform.AbstractContentTransformerTest; +import org.alfresco.repo.transaction.TransactionUtil; +import org.alfresco.repo.transaction.TransactionUtil.TransactionWork; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ActionCondition; import org.alfresco.service.cmr.repository.ContentWriter; @@ -34,7 +36,10 @@ import org.alfresco.service.cmr.repository.CyclicChildRelationshipException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.rule.Rule; import org.alfresco.service.cmr.rule.RuleType; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; +import org.apache.commons.digester.SetRootRule; /** @@ -44,7 +49,17 @@ import org.alfresco.service.namespace.QName; */ public class RuleServiceImplTest extends BaseRuleTest { - + AuthenticationService authenticationService; + PermissionService permissionService; + + @Override + protected void onSetUpInTransaction() throws Exception + { + super.onSetUpInTransaction(); + this.permissionService = (PermissionService)this.applicationContext.getBean("permissionService"); + this.authenticationService = (AuthenticationService)this.applicationContext.getBean("authenticationService"); + } + /** * Test get rule type */ @@ -296,6 +311,59 @@ public class RuleServiceImplTest extends BaseRuleTest ContentModel.TYPE_CONTAINER).getChildRef(); } + public void testRuleServicePermissionsConsumer() + { + this.authenticationService.createAuthentication("conUser", "password".toCharArray()); + this.permissionService.setPermission(this.nodeRef, "conUser", PermissionService.CONSUMER, true); + this.permissionService.setInheritParentPermissions(this.nodeRef, true); + + this.authenticationService.authenticate("conUser", "password".toCharArray()); + Rule rule = createTestRule(); + try + { + this.ruleService.saveRule(this.nodeRef, rule); + // Fail + fail("Consumers cannot create rules."); + } + catch (Exception exception) + { + // Ok + } + + } + + public void testRuleServicePermissionsEditor() + { + this.authenticationService.createAuthentication("editorUser", "password".toCharArray()); + this.permissionService.setPermission(this.nodeRef, "editorUser", PermissionService.EDITOR, true); + this.permissionService.setInheritParentPermissions(this.nodeRef, true); + + this.authenticationService.authenticate("editorUser", "password".toCharArray()); + Rule rule = createTestRule(); + try + { + this.ruleService.saveRule(this.nodeRef, rule); + // Fail + fail("Editors cannot create rules."); + } + catch (Exception exception) + { + // Ok + } + } + + public void testRuleServicePermissionsCoordinator() + { + this.authenticationService.createAuthentication("coordUser", "password".toCharArray()); + this.permissionService.setPermission(this.nodeRef, "coordUser", PermissionService.COORDINATOR, true); + this.permissionService.setInheritParentPermissions(this.nodeRef, true); + + this.authenticationService.authenticate("admin", "admin".toCharArray()); + Rule rule2 = createTestRule(); + this.ruleService.saveRule(this.nodeRef, rule2); + this.authenticationService.clearCurrentSecurityContext(); + } + /** * Tests the rule inheritance within the store, checking that the cache is reset correctly when * rules are added and removed. 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 7a9b576895..cf3fa13ae6 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneSearcherImpl2.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneSearcherImpl2.java @@ -49,6 +49,9 @@ import org.alfresco.service.namespace.NamespacePrefixResolver; import org.alfresco.service.namespace.QName; import org.alfresco.util.ISO9075; import org.alfresco.util.SearchLanguageConversion; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.Term; +import org.apache.lucene.index.TermEnum; import org.apache.lucene.search.Hits; import org.apache.lucene.search.Query; import org.apache.lucene.search.Searcher; @@ -230,7 +233,7 @@ public class LuceneSearcherImpl2 extends LuceneBase2 implements LuceneSearcher2 switch (sd.getSortType()) { case FIELD: - if (searcher.getReader().getFieldNames().contains(sd.getField())) + if (fieldHasTerm(searcher.getReader(), sd.getField())) { fields[index++] = new SortField(sd.getField(), !sd.isAscending()); } @@ -308,6 +311,35 @@ public class LuceneSearcherImpl2 extends LuceneBase2 implements LuceneSearcher2 } } + private static boolean fieldHasTerm(IndexReader indexReader, String field) + { + try + { + TermEnum termEnum = indexReader.terms(new Term(field, "")); + try + { + if (termEnum.next()) + { + Term first = termEnum.term(); + return first.field().equals(field); + } + else + { + return false; + } + } + finally + { + termEnum.close(); + } + } + catch (IOException e) + { + throw new SearcherException("Could not find terms for sort field ", e); + } + + } + public ResultSet query(StoreRef store, String language, String query) { return query(store, language, query, null, null); 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 d049131c30..ddde7715ce 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 @@ -834,8 +834,16 @@ public class IndexInfo // luceneIndexer.flushPending(); IndexReader deltaReader = buildAndRegisterDeltaReader(id); - IndexReader reader = new MultiReader(new IndexReader[] { + IndexReader reader = null; + if (deletions == null || deletions.size() == 0) + { + reader = new MultiReader(new IndexReader[] {mainIndexReader, deltaReader }); + } + else + { + reader = new MultiReader(new IndexReader[] { new FilterIndexReaderByNodeRefs2(mainIndexReader, deletions, deleteOnlyNodes), deltaReader }); + } reader = ReferenceCountingReadOnlyIndexReaderFactory.createReader("MainReader"+id, reader); ReferenceCounting refCounting = (ReferenceCounting)reader; refCounting.incrementReferenceCount(); 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 be0f3ad747..171dc4f4c0 100644 --- a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPGroupExportSource.java +++ b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPGroupExportSource.java @@ -1,790 +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; - - 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); - - } -} +/* + * 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/LDAPPersonExportSource.java b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java index c9b929183f..1b05e495b3 100644 --- a/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java +++ b/source/java/org/alfresco/repo/security/authentication/ldap/LDAPPersonExportSource.java @@ -1,342 +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 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; - } -} +/* + * 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; + } +} \ No newline at end of file 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 1549425147..0713337710 100644 --- a/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthority.java +++ b/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthority.java @@ -16,6 +16,8 @@ */ package org.alfresco.repo.security.permissions.dynamic; +import java.io.Serializable; + import org.alfresco.model.ContentModel; import org.alfresco.repo.security.permissions.DynamicAuthority; import org.alfresco.service.cmr.lock.LockService; @@ -44,9 +46,13 @@ public class LockOwnerDynamicAuthority implements DynamicAuthority, Initializing } if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY)) { - NodeRef original = DefaultTypeConverter.INSTANCE.convert( - NodeRef.class, nodeService.getProperty(nodeRef, ContentModel.PROP_COPY_REFERENCE)); - if (nodeService.exists(original)) + NodeRef original = null; + Serializable reference = nodeService.getProperty(nodeRef, ContentModel.PROP_COPY_REFERENCE); + if (reference != null) + { + original = DefaultTypeConverter.INSTANCE.convert(NodeRef.class, reference); + } + if (original != null && nodeService.exists(original)) { return (lockService.getLockStatus(original) == LockStatus.LOCK_OWNER); } 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 eb07041b43..656967357c 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.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; - } - } -} +/* + * 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 d03bc09118..8f2acca924 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java @@ -1,1839 +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 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 - -} +/* + * 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/acegi/ACLEntryVoter.java b/source/java/org/alfresco/repo/security/permissions/impl/acegi/ACLEntryVoter.java index fef50dd7f4..149bfcc17c 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/acegi/ACLEntryVoter.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/acegi/ACLEntryVoter.java @@ -44,7 +44,6 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; /** - * * @author andyh */ @@ -165,14 +164,11 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean } /** - * This implementation supports only MethodSecurityInterceptor, - * because it queries the presented MethodInvocation. + * This implementation supports only MethodSecurityInterceptor, because it queries the presented MethodInvocation. * * @param clazz * the secure object - * - * @return true if the secure object is - * MethodInvocation, false otherwise + * @return true if the secure object is MethodInvocation, false otherwise */ public boolean supports(Class clazz) { @@ -253,7 +249,15 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean testNodeRef = (NodeRef) invocation.getArguments()[cad.parameter]; if (log.isDebugEnabled()) { - log.debug("\tPermission test on node " + nodeService.getPath(testNodeRef)); + if (nodeService.exists(testNodeRef)) + { + log.debug("\tPermission test on node " + nodeService.getPath(testNodeRef)); + } + else + { + log.debug("\tPermission test on non-existing node " +testNodeRef); + } + } } else if (ChildAssociationRef.class.isAssignableFrom(params[cad.parameter])) @@ -263,7 +267,14 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean testNodeRef = ((ChildAssociationRef) invocation.getArguments()[cad.parameter]).getChildRef(); if (log.isDebugEnabled()) { - log.debug("\tPermission test on node " + nodeService.getPath(testNodeRef)); + if (nodeService.exists(testNodeRef)) + { + log.debug("\tPermission test on node " + nodeService.getPath(testNodeRef)); + } + else + { + log.debug("\tPermission test on non-existing node " + testNodeRef); + } } } } @@ -284,6 +295,14 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean testNodeRef = nodeService.getPrimaryParent(child).getParentRef(); if (log.isDebugEnabled()) { + if (nodeService.exists(testNodeRef)) + { + log.debug("\tPermission test for parent on node " + nodeService.getPath(testNodeRef)); + } + else + { + log.debug("\tPermission test for parent on non-existing node " + testNodeRef); + } log.debug("\tPermission test for parent on node " + nodeService.getPath(testNodeRef)); } } @@ -295,8 +314,17 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean testNodeRef = ((ChildAssociationRef) invocation.getArguments()[cad.parameter]).getParentRef(); if (log.isDebugEnabled()) { - log.debug("\tPermission test for parent on child assoc ref for node " - + nodeService.getPath(testNodeRef)); + if (nodeService.exists(testNodeRef)) + { + log.debug("\tPermission test for parent on child assoc ref for node " + + nodeService.getPath(testNodeRef)); + } + else + { + log.debug("\tPermission test for parent on child assoc ref for non existing node " + + testNodeRef); + } + } } 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 e9a87a88f0..d7c6938916 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,966 +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(); - 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)); - - } - -} +/* + * 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/person/PersonServiceImpl.java b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java index ea5571f075..74d656bf1a 100644 --- a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java +++ b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java @@ -1,388 +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 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 - -} +/* + * 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/template/Classification.java b/source/java/org/alfresco/repo/template/Classification.java new file mode 100644 index 0000000000..3c55a5d0f6 --- /dev/null +++ b/source/java/org/alfresco/repo/template/Classification.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.template; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.alfresco.repo.jscript.CategoryTemplateNode; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.TemplateImageResolver; +import org.alfresco.service.cmr.repository.TemplateNode; +import org.alfresco.service.cmr.search.CategoryService; +import org.alfresco.service.namespace.QName; + +/** + * Support for finding classifications and their root categories. + * + * @author Andy Hind + */ +public final class Classification +{ + private ServiceRegistry services; + private TemplateImageResolver imageResolver; + private StoreRef storeRef; + + public Classification(StoreRef storeRef, ServiceRegistry services, TemplateImageResolver imageResolver) + { + this.storeRef = storeRef; + this.services = services; + this.imageResolver = imageResolver; + } + + /** + * Find all the category nodes in a given classification. + * + * @param aspect + * + * @return all the category nodes in a given classification. + */ + public List getAllCategoryNodes(String aspect) + { + return buildCategoryNodes(services.getCategoryService().getCategories(storeRef, createQName(aspect), + CategoryService.Depth.ANY)); + } + + /** + * Find all the category nodes in a given classification. + * + * @param aspect + * + * @return all the category nodes in a given classification. + */ + public List getAllCategoryNodes(QName aspect) + { + return buildCategoryNodes(services.getCategoryService().getCategories(storeRef, aspect, + CategoryService.Depth.ANY)); + } + + /** + * @return all the aspects that define a classification. + */ + public List getAllClassificationAspects() + { + Collection aspects = services.getCategoryService().getClassificationAspects(); + ArrayList answer = new ArrayList(aspects.size()); + answer.addAll(aspects); + return answer; + } + + /** + * Get the root categories in a classification. + * + * @param aspect + * + * @return List of TemplateNode + */ + public List getRootCategories(String aspect) + { + return buildCategoryNodes(services.getCategoryService().getRootCategories(storeRef, createQName(aspect))); + } + + + private List buildCategoryNodes(Collection cars) + { + ArrayList categoryNodes = new ArrayList(cars.size()); + for (ChildAssociationRef car : cars) + { + categoryNodes.add(new CategoryTemplateNode(car.getChildRef(), this.services, this.imageResolver)); + } + return categoryNodes; + } + + private QName createQName(String s) + { + QName qname; + if (s.indexOf(QName.NAMESPACE_BEGIN) != -1) + { + qname = QName.createQName(s); + } + else + { + qname = QName.createQName(s, this.services.getNamespaceService()); + } + return qname; + } +} diff --git a/source/java/org/alfresco/repo/template/FreeMarkerProcessor.java b/source/java/org/alfresco/repo/template/FreeMarkerProcessor.java index 2ba4994524..6aae071809 100644 --- a/source/java/org/alfresco/repo/template/FreeMarkerProcessor.java +++ b/source/java/org/alfresco/repo/template/FreeMarkerProcessor.java @@ -301,6 +301,13 @@ public class FreeMarkerProcessor implements TemplateProcessor // current date/time is useful to have and isn't supplied by FreeMarker by default model.put("date", new Date()); + // Session support + model.put("session", new Session(services, imageResolver)); + + // Classification support + + model.put("classification", new Classification(companyHome.getStoreRef(), services, imageResolver)); + // add custom method objects model.put("hasAspect", new HasAspectMethod()); model.put("message", new I18NMessageMethod()); diff --git a/source/java/org/alfresco/repo/template/Session.java b/source/java/org/alfresco/repo/template/Session.java new file mode 100644 index 0000000000..e1007de8c9 --- /dev/null +++ b/source/java/org/alfresco/repo/template/Session.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.template; + +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.TemplateImageResolver; + +/** + * Support session information in free marker templates. + * + * @author Andy Hind + */ +public class Session +{ + + private ServiceRegistry services; + + @SuppressWarnings("unused") + private TemplateImageResolver imageResolver; + + public Session(ServiceRegistry services, TemplateImageResolver imageResolver) + { + this.services = services; + this.imageResolver = imageResolver; + } + + /** + * Get the current authentication ticket. + * + * @return + */ + public String getTicket() + { + return services.getAuthenticationService().getCurrentTicket(); + } +} diff --git a/source/java/org/alfresco/repo/version/common/counter/VersionCounterService.java b/source/java/org/alfresco/repo/version/common/counter/VersionCounterService.java index fa41e2e373..c45aeb35ec 100644 --- a/source/java/org/alfresco/repo/version/common/counter/VersionCounterService.java +++ b/source/java/org/alfresco/repo/version/common/counter/VersionCounterService.java @@ -59,4 +59,16 @@ public interface VersionCounterService * @param storeRef the store reference */ public void resetVersionNumber(StoreRef storeRef); + + /** + * Sets the version number for a specified store. + * + * WARNING: calling this method will completely reset the current + * version count for the specified store and cannot be undone. + * + * @param storeRef the store reference + * @param versionCount the new version count + */ + public void setVersionNumber(StoreRef storeRef, int versionCount); + } diff --git a/source/java/org/alfresco/repo/workflow/WorkflowDeployer.java b/source/java/org/alfresco/repo/workflow/WorkflowDeployer.java index 0755746654..a6c3d20d3c 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowDeployer.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowDeployer.java @@ -31,11 +31,10 @@ import org.alfresco.service.cmr.workflow.WorkflowDeployment; import org.alfresco.service.cmr.workflow.WorkflowException; import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.AbstractLifecycleBean; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.io.ClassPathResource; @@ -44,7 +43,7 @@ import org.springframework.core.io.ClassPathResource; * * @author davidc */ -public class WorkflowDeployer implements ApplicationListener +public class WorkflowDeployer extends AbstractLifecycleBean { // Logging support private static Log logger = LogFactory.getLog("org.alfresco.repo.workflow"); @@ -222,16 +221,16 @@ public class WorkflowDeployer implements ApplicationListener } } - /* - * (non-Javadoc) - * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) - */ - public void onApplicationEvent(ApplicationEvent event) + @Override + protected void onBootstrap(ApplicationEvent event) { - if (event instanceof ContextRefreshedEvent) - { - deploy(); - } + deploy(); + } + + @Override + protected void onShutdown(ApplicationEvent event) + { + // NOOP } } diff --git a/source/java/org/alfresco/repo/workflow/WorkflowInterpreter.java b/source/java/org/alfresco/repo/workflow/WorkflowInterpreter.java new file mode 100644 index 0000000000..90eda03c7d --- /dev/null +++ b/source/java/org/alfresco/repo/workflow/WorkflowInterpreter.java @@ -0,0 +1,707 @@ +/* + * 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.workflow; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.i18n.I18NUtil; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.workflow.WorkflowDefinition; +import org.alfresco.service.cmr.workflow.WorkflowDeployment; +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.cmr.workflow.WorkflowTask; +import org.alfresco.service.cmr.workflow.WorkflowTaskState; +import org.alfresco.service.cmr.workflow.WorkflowTransition; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.ApplicationContextHelper; +import org.springframework.context.ApplicationContext; +import org.springframework.core.io.ClassPathResource; + +/** + * An interactive console for Workflows. + * + * @author davidc + */ +public class WorkflowInterpreter +{ + // Service dependencies + private WorkflowService workflowService; + private NamespaceService namespaceService; + private PersonService personService; + + /** + * The reader for interaction. + */ + private BufferedReader fIn; + + /** + * Current context + */ + private WorkflowDefinition currentWorkflowDef = null; + private WorkflowPath currentPath = null; + private String currentDeploy = null; + + /** + * Last command issued + */ + private String lastCommand = null; + + /** + * Variables + */ + private Map vars = new HashMap(); + + + /** + * Main entry point. + * + * Syntax: AVMInteractiveConsole storage (new|old). + */ + public static void main(String[] args) + { + ApplicationContext context = ApplicationContextHelper.getApplicationContext(); + WorkflowInterpreter console = (WorkflowInterpreter)context.getBean("workflowInterpreter"); + AuthenticationUtil.setSystemUserAsCurrentUser(); + console.rep(); + System.exit(0); + } + + /** + * Make up a new console. + */ + public WorkflowInterpreter() + { + fIn = new BufferedReader(new InputStreamReader(System.in)); + } + + /** + * @param workflowService The Workflow Service + */ + public void setWorkflowService(WorkflowService workflowService) + { + this.workflowService = workflowService; + } + + /** + * @param namespaceService namespaceService + */ + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + /** + * @param personService personService + */ + public void setPersonService(PersonService personService) + { + this.personService = personService; + } + + /** + * A Read-Eval-Print loop. + */ + public void rep() + { + while (true) + { + System.out.print("ok> "); + try + { + String line = fIn.readLine(); + if (line.equals("exit")) + { + return; + } + long startms = System.currentTimeMillis(); + System.out.print(interpretCommand(line)); + System.out.println("" + (System.currentTimeMillis() - startms) + "ms"); + } + catch (Exception e) + { + e.printStackTrace(System.err); + System.out.println(""); + } + } + } + + /** + * Interpret a single command using the BufferedReader passed in for any data needed. + * + * @param line The unparsed command + * @return The textual output of the command. + */ + public String interpretCommand(String line) + throws IOException + { + String[] command = line.split(" "); + if (command.length == 0) + { + command = new String[1]; + command[0] = line; + } + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + PrintStream out = new PrintStream(bout); + + // repeat last command? + if (command[0].equals("r")) + { + if (lastCommand == null) + { + return "No command entered yet."; + } + return "repeating command " + lastCommand + "\n\n" + interpretCommand(lastCommand); + } + + // remember last command + lastCommand = line; + + // execute command + if (command[0].equals("help")) + { + String helpFile = I18NUtil.getMessage("workflow_console.help"); + ClassPathResource helpResource = new ClassPathResource(helpFile); + byte[] helpBytes = new byte[500]; + InputStream helpStream = helpResource.getInputStream(); + try + { + int read = helpStream.read(helpBytes); + while (read != -1) + { + bout.write(helpBytes, 0, read); + read = helpStream.read(helpBytes); + } + } + finally + { + helpStream.close(); + } + } + + else if (command[0].equals("show")) + { + if (command.length < 2) + { + return "Syntax Error.\n"; + } + + else if (command[1].equals("definitions")) + { + List defs = workflowService.getDefinitions(); + for (WorkflowDefinition def : defs) + { + out.println("id: " + def.id + " , name: " + def.name + " , title: " + def.title + " , version: " + def.version); + } + } + + else if (command[1].equals("workflows")) + { + if (currentWorkflowDef == null) + { + return "workflow definition not in use. Enter command use .\n"; + } + List workflows = workflowService.getActiveWorkflows(currentWorkflowDef.id); + for (WorkflowInstance workflow : workflows) + { + out.println("id: " + workflow.id + " , desc: " + workflow.description + " , start date: " + workflow.startDate + " , def: " + workflow.definition.title); + } + } + + else if (command[1].equals("paths")) + { + String workflowId = (command.length == 3) ? command[2] : (currentPath == null) ? null : currentPath.instance.id; + if (workflowId == null) + { + return "Syntax Error. Workflow Id not specified.\n"; + } + List paths = workflowService.getWorkflowPaths(workflowId); + for (WorkflowPath path : paths) + { + out.println("path id: " + path.id + " , node: " + path.node.name); + } + } + + else if (command[1].equals("tasks")) + { + String pathId = (command.length == 3) ? command[2] : (currentPath == null) ? null : currentPath.id; + if (pathId == null) + { + return "Syntax Error. Path Id not specified.\n"; + } + List tasks = workflowService.getTasksForWorkflowPath(pathId); + for (WorkflowTask task : tasks) + { + out.println("task id: " + task.id + " , name: " + task.name + " , properties: " + task.properties.size()); + } + } + + else if (command[1].equals("transitions")) + { + String workflowId = (command.length == 3) ? command[2] : (currentPath == null) ? null : currentPath.instance.id; + if (workflowId == null) + { + return "Syntax Error. Workflow Id not specified.\n"; + } + List paths = workflowService.getWorkflowPaths(workflowId); + for (WorkflowPath path : paths) + { + out.println("path: " + path.id + " , node: " + path.node.name + " , active: " + path.active); + List tasks = workflowService.getTasksForWorkflowPath(path.id); + for (WorkflowTask task : tasks) + { + out.println(" task id: " + task.id + " , name: " + task.name + " , properties: " + task.properties.size()); + } + for (WorkflowTransition transition : path.node.transitions) + { + out.println(" transition id: " + ((transition.id == null || transition.id.equals("")) ? "[default]" : transition.id) + " , title: " + transition.title); + } + } + } + + else if (command[1].equals("my")) + { + if (command.length != 3) + { + return "Syntax Error.\n"; + } + + if (command[2].equals("tasks")) + { + out.println(AuthenticationUtil.getCurrentUserName() + ":"); + List tasks = workflowService.getAssignedTasks(AuthenticationUtil.getCurrentUserName(), WorkflowTaskState.IN_PROGRESS); + for (WorkflowTask task : tasks) + { + out.println("id: " + task.id + " , name: " + task.name + " , properties: " + task.properties.size() + " , workflow: " + task.path.instance.id + " , path: " + task.path.id); + } + } + + else if (command[2].equals("completed")) + { + out.println(AuthenticationUtil.getCurrentUserName() + ":"); + List tasks = workflowService.getAssignedTasks(AuthenticationUtil.getCurrentUserName(), WorkflowTaskState.COMPLETED); + for (WorkflowTask task : tasks) + { + out.println("id: " + task.id + " , name " + task.name + " , properties: " + task.properties.size() + " , workflow: " + task.path.instance.id + " , path: " + task.path.id); + } + } + else + { + return "Syntax Error.\n"; + } + } + else + { + return "Syntax Error.\n"; + } + } + + else if (command[0].equals("desc")) + { + if (command.length < 2) + { + return "Syntax Error.\n"; + } + + if (command[1].equals("task")) + { + if (command.length != 3) + { + return "Syntax Error.\n"; + } + WorkflowTask task = workflowService.getTaskById(command[2]); + out.println("id: " + task.id); + out.println("name: " + task.name); + out.println("title: " + task.title); + out.println("description: " + task.description); + out.println("state: " + task.state); + out.println("path: " + task.path.id); + out.println("transitions: " + task.path.node.transitions.length); + for (WorkflowTransition transition : task.path.node.transitions) + { + out.println(" transition: " + ((transition == null || transition.id.equals("")) ? "[default]" : transition.id) + " , title: " + transition.title + " , desc: " + transition.description); + } + out.println("properties: " + task.properties.size()); + for (Map.Entry prop : task.properties.entrySet()) + { + out.println(" " + prop.getKey() + " = " + prop.getValue()); + } + } + + else if (command[1].equals("workflow")) + { + if (command.length != 3) + { + return "Syntax Error.\n"; + } + WorkflowInstance workflow = workflowService.getWorkflowById(command[2]); + out.println("definition: " + workflow.definition.name); + out.println("id: " + workflow.id); + out.println("description: " + workflow.description); + out.println("active: " + workflow.active); + out.println("start date: " + workflow.startDate); + out.println("end date: " + workflow.endDate); + out.println("initiator: " + workflow.initiator); + out.println("context: " + workflow.context); + out.println("package: " + workflow.workflowPackage); + } + else + { + return "Syntax Error.\n"; + } + } + + else if (command[0].equals("deploy")) + { + if (command.length != 2) + { + return "Syntax Error.\n"; + } + ClassPathResource workflowDef = new ClassPathResource(command[1]); + WorkflowDeployment deployment = workflowService.deployDefinition("jbpm", workflowDef.getInputStream(), MimetypeMap.MIMETYPE_XML); + WorkflowDefinition def = deployment.definition; + for (String problem : deployment.problems) + { + out.println(problem); + } + out.println("deployed definition id: " + def.id + " , name: " + def.name + " , title: " + def.title + " , version: " + def.version); + currentDeploy = command[1]; + out.print(interpretCommand("use " + def.id)); + } + + else if (command[0].equals("redeploy")) + { + if (currentDeploy == null) + { + return "nothing to redeploy\n"; + } + out.print(interpretCommand("deploy " + currentDeploy)); + } + + else if (command[0].equals("use")) + { + if (command.length == 1) + { + out.println("definition: " + ((currentWorkflowDef == null) ? "None" : currentWorkflowDef.id + " , name: " + currentWorkflowDef.title)); + out.println("workflow: " + ((currentPath == null) ? "None" : currentPath.instance.id + " , active: " + currentPath.instance.active)); + out.println("path: " + ((currentPath == null) ? "None" : currentPath.id + " , node: " + currentPath.node.title)); + } + else if (command.length > 1) + { + if (command[1].equals("definition")) + { + if (command.length != 3) + { + return "Syntax Error.\n"; + } + WorkflowDefinition def = workflowService.getDefinitionById(command[2]); + if (def == null) + { + return "Not found.\n"; + } + currentWorkflowDef = def; + currentPath = null; + out.print(interpretCommand("use")); + } + + else if (command[1].equals("workflow")) + { + if (command.length != 3) + { + return "Syntax Error.\n"; + } + WorkflowInstance instance = workflowService.getWorkflowById(command[2]); + currentWorkflowDef = instance.definition; + currentPath = workflowService.getWorkflowPaths(instance.id).get(0); + out.print(interpretCommand("use")); + } + else + { + return "Syntax Error.\n"; + } + } + + } + + else if (command[0].equals("user")) + { + if (command.length == 2) + { + AuthenticationUtil.setCurrentUser(command[1]); + } + out.println("using user " + AuthenticationUtil.getCurrentUserName()); + } + + else if (command[0].equals("start")) + { + Map params = new HashMap(); + for (int i = 1; i < command.length; i++) + { + String[] param = command[i].split("="); + QName qname = QName.createQName(param[0], namespaceService); + if (param.length == 1) + { + if (!vars.containsKey(qname)) + { + return "var " + qname + " not found.\n"; + } + params.put(qname, vars.get(qname)); + } + else if (param.length == 2) + { + params.put(qname, param[1]); + } + else + { + return "Syntax Error.\n"; + } + } + WorkflowPath path = workflowService.startWorkflow(currentWorkflowDef.id, params); + out.println("started workflow id: " + path.instance.id + ", path: " + path.id + " , node: " + path.node.name + " , def: " + path.instance.definition.title); + currentPath = path; + } + + else if (command[0].equals("update")) + { + if (command.length < 3) + { + return "Syntax Error.\n"; + } + + if (command[1].equals("task")) + { + if (command.length < 4) + { + return "Syntax Error.\n"; + } + Map params = new HashMap(); + for (int i = 3; i < command.length; i++) + { + String[] param = command[i].split("="); + QName qname = QName.createQName(param[0], namespaceService); + if (param.length == 1) + { + if (!vars.containsKey(qname)) + { + return "var " + qname + " not found.\n"; + } + params.put(qname, vars.get(qname)); + } + else if (param.length == 2) + { + params.put(qname, param[1]); + } + else + { + return "Syntax Error.\n"; + } + } + WorkflowTask task = workflowService.updateTask(command[2], params, null, null); + out.println("updated task id: " + command[2] + ", properties: " + task.properties.size()); + } + else + { + return "Syntax Error.\n"; + } + } + + else if (command[0].equals("signal")) + { + if (command.length < 2) + { + return "Syntax Error.\n"; + } + WorkflowPath path = workflowService.signal(command[1], (command.length == 3) ? command[2] : null); + out.println("signal sent - path id: " + path.id + " , node: " + path.node.name); + } + + else if (command[0].equals("end")) + { + if (command.length < 3) + { + return "Syntax Error.\n"; + } + if (command[1].equals("task")) + { + WorkflowTask task = workflowService.endTask(command[2], (command.length == 4) ? command[3] : null); + out.println("signal sent - path id: " + task.path.id + " , node: " + task.path.node.name); + } + else if (command[1].equals("workflow")) + { + String workflowId = (command.length == 3) ? command[2] : (currentPath == null) ? null : currentPath.instance.id; + if (workflowId == null) + { + return "Syntax Error. Workflow Id not specified.\n"; + } + workflowService.cancelWorkflow(workflowId); + out.println("cancelled workflow" + workflowId); + } + else + { + return "Syntax Error.\n"; + } + } + + else if (command[0].equals("var")) + { + if (command.length == 1) + { + for (Map.Entry entry : vars.entrySet()) + { + out.println(entry.getKey() + " = " + entry.getValue()); + } + } + else if (command.length == 2) + { + String[] param = command[1].split("="); + if (param.length == 0) + { + return "Syntax Error.\n"; + } + if (param.length == 1) + { + QName qname = QName.createQName(param[0], namespaceService); + vars.remove(qname); + out.println("deleted var " + qname); + } + else if (param.length == 2) + { + boolean multi = false; + if (param[0].endsWith("*")) + { + param[0] = param[0].substring(0, param[0].length() -1); + multi = true; + } + QName qname = QName.createQName(param[0], namespaceService); + String[] strValues = param[1].split(","); + if (!multi && strValues.length > 1) + { + return "Syntax Error.\n"; + } + if (!multi) + { + vars.put(qname, strValues[0]); + } + else + { + List values = new ArrayList(); + for (String strValue : strValues) + { + values.add(strValue); + } + vars.put(qname, (Serializable)values); + } + out.println("set var " + qname + " = " + vars.get(qname)); + } + else + { + return "Syntax Error.\n"; + } + } + else if (command.length == 4) + { + if (command[2].equals("person")) + { + boolean multi = false; + if (command[1].endsWith("*")) + { + command[1] = command[1].substring(0, command[1].length() -1); + multi = true; + } + QName qname = QName.createQName(command[1], namespaceService); + String[] strValues = command[3].split(","); + if (!multi && strValues.length > 1) + { + return "Syntax Error.\n"; + } + if (!multi) + { + NodeRef auth = personService.getPerson(strValues[0]); + vars.put(qname, auth); + } + else + { + List values = new ArrayList(); + for (String strValue : strValues) + { + NodeRef auth = personService.getPerson(strValue); + values.add(auth); + } + vars.put(qname, (Serializable)values); + } + out.println("set var " + qname + " = " + vars.get(qname)); + } + else + { + return "Syntax Error.\n"; + } + } + else + { + return "Syntax Error.\n"; + } + } + + else + { + return "Syntax Error.\n"; + } + + out.flush(); + String retVal = new String(bout.toByteArray()); + out.close(); + return retVal; + } + + + /** + * Get currently used workflow definition + * + * @return workflow definition + */ + public WorkflowDefinition getCurrentWorkflowDef() + { + return currentWorkflowDef; + } + + /** + * Get current user name + * + * @return user name + */ + public String getCurrentUserName() + { + return AuthenticationUtil.getCurrentUserName(); + } + +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java b/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java index dc8737b20d..f0dca684f4 100644 --- a/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java +++ b/source/java/org/alfresco/repo/workflow/WorkflowPackageImpl.java @@ -25,6 +25,7 @@ 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.search.SearchService; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.workflow.WorkflowException; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; @@ -47,6 +48,7 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent private SearchService searchService; private NodeService nodeService; private NamespaceService namespaceService; + private PermissionService permissionService; private NodeRef systemWorkflowContainer = null; @@ -74,6 +76,11 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent this.nodeService = nodeService; } + public void setPermissionService(PermissionService permissionService) + { + this.permissionService = permissionService; + } + /** * @param namespaceService namespace service */ @@ -113,6 +120,8 @@ public class WorkflowPackageImpl implements WorkflowPackageComponent 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(); + // TODO: For now, grant full access to everyone + permissionService.setPermission(container, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true); isSystemPackage = true; } diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java index 9e1cfbabf0..74a293728f 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngine.java @@ -311,10 +311,25 @@ public class JBPMEngine extends BPMEngine /* (non-Javadoc) * @see org.alfresco.repo.workflow.WorkflowDefinitionComponent#getDefinitionById(java.lang.String) */ - public WorkflowDefinition getDefinitionById(String workflowDefinitionId) + public WorkflowDefinition getDefinitionById(final String workflowDefinitionId) { - // TODO - throw new UnsupportedOperationException(); + try + { + return (WorkflowDefinition)jbpmTemplate.execute(new JbpmCallback() + { + public Object doInJbpm(JbpmContext context) + { + // retrieve process + GraphSession graphSession = context.getGraphSession(); + ProcessDefinition processDefinition = graphSession.getProcessDefinition(getJbpmId(workflowDefinitionId)); + return processDefinition == null ? null : createWorkflowDefinition(processDefinition); + } + }); + } + catch(JbpmException e) + { + throw new WorkflowException("Failed to retrieve workflow definition '" + workflowDefinitionId + "'", e); + } } /* (non-Javadoc) @@ -1714,7 +1729,7 @@ public class JBPMEngine extends BPMEngine workflowTransition.id = transition.getName(); Node node = transition.getFrom(); workflowTransition.isDefault = node.getDefaultLeavingTransition().equals(transition); - if (workflowTransition.id.length() == 0) + if (workflowTransition.id == null || workflowTransition.id.length() == 0) { workflowTransition.title = getLabel(DEFAULT_TRANSITION_LABEL, TITLE_LABEL, workflowTransition.id); workflowTransition.description = getLabel(DEFAULT_TRANSITION_LABEL, DESC_LABEL, workflowTransition.title); diff --git a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java index 3e927d4bba..47c9465e0d 100644 --- a/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java +++ b/source/java/org/alfresco/repo/workflow/jbpm/JBPMEngineTest.java @@ -341,8 +341,10 @@ public class JBPMEngineTest extends BaseSpringTest public void testSignal() { + Map parameters = new HashMap(); + parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "testNode"), testNodeRef); WorkflowDefinition workflowDef = getTestDefinition(); - WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, null); + WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters); assertNotNull(path); WorkflowPath updatedPath = workflowComponent.signal(path.id, path.node.transitions[1].id); assertNotNull(updatedPath); @@ -374,6 +376,26 @@ public class JBPMEngineTest extends BaseSpringTest } + public void xtestMultiAssign() + { + WorkflowDefinition workflowDef = getTestDefinition(); + List bpm_assignees = new ArrayList(); + bpm_assignees.add("admin"); + bpm_assignees.add("bob"); + bpm_assignees.add("fred"); + Map parameters = new HashMap(); + parameters.put(QName.createQName(NamespaceService.BPM_MODEL_1_0_URI, "assignees"), (Serializable)bpm_assignees); + parameters.put(QName.createQName(NamespaceService.DEFAULT_URI, "testNode"), testNodeRef); + WorkflowPath path = workflowComponent.startWorkflow(workflowDef.id, parameters); + assertNotNull(path); + List tasks = workflowComponent.getTasksForWorkflowPath(path.id); + assertNotNull(tasks); + assertEquals(1, tasks.size()); + WorkflowTask updatedTask = taskComponent.endTask(tasks.get(0).id, "multi"); + assertNotNull(updatedTask); + } + + public void testEndTask() { WorkflowDefinition workflowDef = getTestDefinition(); diff --git a/source/java/org/alfresco/service/cmr/action/ActionService.java b/source/java/org/alfresco/service/cmr/action/ActionService.java index 171051fc94..b34b500e8f 100644 --- a/source/java/org/alfresco/service/cmr/action/ActionService.java +++ b/source/java/org/alfresco/service/cmr/action/ActionService.java @@ -202,7 +202,7 @@ public interface ActionService * @param nodeRef the node reference * @param action the action */ - @Auditable(key = Auditable.Key.ARG_1, parameters = {"nodeRef", "action" }) + @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef", "action" }) void saveAction(NodeRef nodeRef, Action action); /** @@ -211,7 +211,7 @@ public interface ActionService * @param nodeRef the node reference * @return the list of actions */ - @Auditable(key = Auditable.Key.ARG_1, parameters = {"nodeRef"}) + @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef"}) List getActions(NodeRef nodeRef); /** diff --git a/source/java/org/alfresco/service/cmr/repository/CopyService.java b/source/java/org/alfresco/service/cmr/repository/CopyService.java index d69e77e82a..857fb7431a 100644 --- a/source/java/org/alfresco/service/cmr/repository/CopyService.java +++ b/source/java/org/alfresco/service/cmr/repository/CopyService.java @@ -74,6 +74,7 @@ public interface CopyService * @param destinationAssocTypeQName the type of the new child assoc * @param destinationQName the qualified name of the child association from the * parent to the new node + * @param copyChildren indicates that the children of the node should also be copied * * @return the new node reference */ @@ -85,10 +86,32 @@ public interface CopyService QName destinationQName, boolean copyChildren); + /** + * @see CopyService#copy(NodeRef, NodeRef, QName, QName, boolean) + * + * Ensures the copy name is the same as the origional or is renamed to prevent duplicate names. + * + * @param sourceNodeRef the node reference used as the source of the copy + * @param destinationParent the intended parent of the new node + * @param destinationAssocTypeQName the type of the new child assoc + * @param destinationQName the qualified name of the child association from the + * parent to the new node + * @param copyChildren indicates that the children of the node should also be copied + * + * @return the new node reference + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = {"sourceNodeRef", "destinationParent", "destinationAssocTypeQName", "destinationQName", "copyChildren"}) + public NodeRef copyAndRename( + NodeRef sourceNodeRef, + NodeRef destinationParent, + QName destinationAssocTypeQName, + QName destinationQName, + boolean copyChildren); + /** * By default children of the source node are not copied. * - * @see NodeCopyService#copy(NodeRef, NodeRef, QName, QName, boolean) + * @see CopyService#copy(NodeRef, NodeRef, QName, QName, boolean) * * @param sourceNodeRef the node reference used as the source of the copy * @param destinationParent the intended parent of the new node @@ -142,4 +165,5 @@ public interface CopyService */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef"}) public List getCopies(NodeRef nodeRef); + } diff --git a/source/java/org/alfresco/service/cmr/repository/ScriptImplementation.java b/source/java/org/alfresco/service/cmr/repository/ScriptImplementation.java new file mode 100644 index 0000000000..cb8353abba --- /dev/null +++ b/source/java/org/alfresco/service/cmr/repository/ScriptImplementation.java @@ -0,0 +1,20 @@ +/** + * + */ +package org.alfresco.service.cmr.repository; + +/** + * Interface to represent a server side script implementation + * + * @author Roy Wetherall + * + */ +public interface ScriptImplementation +{ + /** + * Returns the name of the script + * + * @return the name of the script + */ + String getScriptName(); +} diff --git a/source/java/org/alfresco/service/cmr/repository/ScriptService.java b/source/java/org/alfresco/service/cmr/repository/ScriptService.java index ad742600f5..80112477f7 100644 --- a/source/java/org/alfresco/service/cmr/repository/ScriptService.java +++ b/source/java/org/alfresco/service/cmr/repository/ScriptService.java @@ -83,4 +83,12 @@ public interface ScriptService @Auditable(parameters = {"script", "model"}) public Object executeScriptString(String script, Map model) throws ScriptException; + + /** + * Registers a script implementation with the script service + * + * @param script the script implementation + */ + @Auditable(parameters = {"script"}) + public void registerScript(ScriptImplementation script); } diff --git a/source/java/org/alfresco/service/cmr/repository/TemplateNode.java b/source/java/org/alfresco/service/cmr/repository/TemplateNode.java index 6d2a05b55c..bd3ce6bea0 100644 --- a/source/java/org/alfresco/service/cmr/repository/TemplateNode.java +++ b/source/java/org/alfresco/service/cmr/repository/TemplateNode.java @@ -60,7 +60,7 @@ import freemarker.ext.dom.NodeModel; * * @author Kevin Roast */ -public final class TemplateNode implements Serializable +public class TemplateNode implements Serializable { private static final long serialVersionUID = 1234390333739034171L; @@ -78,7 +78,7 @@ public final class TemplateNode implements Serializable private Map> assocs = null; /** Cached values */ - private NodeRef nodeRef; + protected NodeRef nodeRef; private String name; private QName type; private String path; @@ -87,15 +87,16 @@ public final class TemplateNode implements Serializable private QNameMap properties; private List permissions = null; private boolean propsRetrieved = false; - private ServiceRegistry services = null; + protected ServiceRegistry services = null; private Boolean isDocument = null; private Boolean isContainer = null; private String displayPath = null; private String mimetype = null; private Long size = null; - private TemplateImageResolver imageResolver = null; + protected TemplateImageResolver imageResolver = null; private TemplateNode parent = null; private ChildAssociationRef primaryParentAssoc = null; + private Boolean isCategory = null; // ------------------------------------------------------------------------------ @@ -360,6 +361,20 @@ public final class TemplateNode implements Serializable return locked; } + /** + * @return true if the node is a Category instance + */ + public boolean getIsCategory() + { + if (isCategory == null) + { + DictionaryService dd = this.services.getDictionaryService(); + isCategory = Boolean.valueOf(dd.isSubClass(getType(), ContentModel.TYPE_CATEGORY)); + } + + return isCategory.booleanValue(); + } + /** * @return the parent node */ @@ -482,17 +497,17 @@ public final class TemplateNode implements Serializable */ public NodeModel getXmlNodeModel() { - try - { - return NodeModel.parse(new InputSource(new StringReader(getContent()))); - } - catch (Throwable err) - { - if (logger.isDebugEnabled()) - logger.debug(err.getMessage(), err); - - return null; - } + try + { + return NodeModel.parse(new InputSource(new StringReader(getContent()))); + } + catch (Throwable err) + { + if (logger.isDebugEnabled()) + logger.debug(err.getMessage(), err); + + return null; + } } /** @@ -661,14 +676,18 @@ public final class TemplateNode implements Serializable } + // ------------------------------------------------------------------------------ // Audit API - + /** + * @return a list of AuditInfo objects describing the Audit Trail for this node instance + */ public List getAuditTrail() { return this.services.getAuditService().getAuditTrail(this.nodeRef); } + // ------------------------------------------------------------------------------ // Misc helpers