From 4872eb9909fcdb1e496e43263d60ab7dd38b4d05 Mon Sep 17 00:00:00 2001 From: Derek Hulley Date: Thu, 17 Jun 2010 19:35:49 +0000 Subject: [PATCH] Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-5 to HEAD: 20678: DAO5 branch: Preparation for merge back to HEAD 20689: Merged DAO4 to DAO5 - Removed all 'dbscripts/create/3.x/SomeDialect' and replaced with 'dbscripts/create/SomeDialect' DB create scripts are taken from latest DAO4 - TODO: FixAuthoritiesCrcValuesPatch needs query implementation in PatchDAO Merged DAO3 to DAO4 - Reapplied fixes for ALF-713 (race condition on Usages) 19350: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-2 to BRANCHES/DEV/V3.3-DAO-REFACTOR-3: 18939: SAIL-4 :2nd stage branch for DAO refactor off HEAD rev 18898 18948: Merged V3.3-DAO-REFACTOR to V3.3-DAO-REFACTOR-2 18202: Dev branch for DAO refactor 18252: SAIL-233: QName.hbm.xml 18295: Added missing CREATE TABLE statements for QName-related code 18324: SAIL-234: Node.hbm.xml: Node aspects initial integration 18355: Added 'setValue' method to manually update the cached value 18356: MV property stressing lowered to speed test up 18357: SAIL-234: Node.hbm.xml 18376: Pulled all Alfresco-related create SQL into script 18389: SAIL-234: Permissions DAO refactor - initial checkpoint 18390: Formatting only (line-endings) 18400: SAIL-234: Node.hbm.xml 18418: SAIL-234: Node.hbm.xml: 'alf_node_assoc' CRUD 18429: SAIL-234: Node.hbm.xml: Cleaned out all Hibernate references to NodeAssocImpl 18457: SAIL-234: Permissions DAO refactor 18959: Merged DEV/V3.3-DAO-REFACTOR to DEV/V3.3-DAO-REFACTOR-2 18479: SAIL-234: Node.hbm.xml - fix updateNode (missing id when saving oldDummyNode) 18482: SAIL-235: remove Permissions.hbm.xml 18517: SAIL-235: Permissions DAO refactor 18523: SAIL-234: Node.hbm.xml 18524: SAIL-235: Permissions DAO refactor 18960: Merged DEV/V3.3-DAO-REFACTOR to DEV/V3.3-DAO-REFACTOR-2 18533: Flipped back to Windows line endings 18535: Formatting-only (eol) 18540: Formatting-only (eol) 18541: SAIL-235: Permissions DAO refactor 18543: SAIL-234: Node.hbm.xml: Start alf_store changes 18567: SAIL-235: Permissions DAO refactor 18596: SAIL-305: Alfresco DDL - formatted/rationalized and added missing indexes & fk constraints 18603: SAIL-311: Minor cleanup for schema upgrade scripts (V3.3) 18604: SAIL-311: Remove empty dirs 18619: SAIL-274: Locale.hbm.xml 18621: Added method to create default ACL 18622: SAIL-234: Node.hbm.xml: Store, Transaction, Server and some node 18624: Formatting only (eol) 18631: SAIL-235: Permissions DAO refactor 18633: SAIL-235: Permissions DAO refactor - do not expose CRUD for AceContext (or AuthorityAlias) since currently unused 18639: getLocale(Locale) should return null if it doesn't exist 18640: SAIL-234 NodeDAO: More replacement of node queries and updates 18648: SAIL-310: Create SQL script for core repo tables (All DB ports) 18651: SAIL-234 NodeDAO: Moves across stores handle presence of target deleted nodes 18961: Merged DEV/V3.3-DAO-REFACTOR to DEV/V3.3-DAO-REFACTOR-2 18658: SAIL-274 Locale DAO: Missing getValueKey() method 18662: SAIL-235: Permissions DAO refactor - further cleanup (of DbAccessControlList usage, including copyACLs) 18664: DB scripts porting for PostgreSQL finished. 18668: SAIL-234 Node DAO: Note in case Transaction Change ID is dropped from indexes 18669: SAIL-234 Node DAO: deleteNode and archive (store move) fixes 18672: DB scripts porting for Oracle finished. 18675: SAIL-235: Permissions DAO refactor 18677: DB scripts porting for DB2 finished. 18964: Merged DEV/V3.3-DAO-REFACTOR to DEV/V3.3-DAO-REFACTOR-2 18687: Execute a callback with retries 18688: SAIL-234 Node DAO: Child association creation 18690: SAIL-234 Node DAO: Comment out raw creation of stores as it breaks subsequent bootstrap checks 18691: SAIL-234 Node DAO: More replacement of alf_child_assoc handling 18713: Commented about needing a more efficient removeChildAssociation method 18714: SAIL-234 Node DAO: Replaced queries on alf_child_assoc 18715: SAIL-234 Node DAO: More alf_child_assoc query replacement 18727: SAIL-234 Node DAO: alf_child_assoc queries complete 18737: SAIL-234 Node DAO: Tweaks to newNode and implemented prependPaths 18741: SAIL-234 and SAIL-334: Moved UsageDelta Hibernate code and queries over to UsageDeltaDAO 18748: SAIL-234 Node DAO: fix NPE (EditionServiceImplTest) 18769: SAIL-234 Node DAO: alf_node_properties ground work 18786: SAIL-234 Node DAO: alf_node_properties and cm:auditable properties 18810: Added EqualsHelper.getMapComparison 18813: TransactionalCache propagates cache clears and removals during rollback 18826: SAIL-234 Node DAO: Moved over sundry references to NodeDaoService to NodeDAO 18849: SAIL-237: UsageDelta.hbm.xml - eol formatting only (including removal of unwanted svn:eol-style=native property) 18869: SAIL-234 NodeDAO: Fixed more references to 'nodeDaoService' 18895: SAIL-234 NodeDAO: Queries for alf_transaction 18899: SAIL-234 Node DAO: Fixed bean fetching for 'nodeDAO' 18909: SAIL-234 NodeDAO: Fixes to getNodeRefStatus and various txn queries 18916: SAIL-234 NodeDAO: Fixed moveNode alf_child_assoc updates 18922: SAIL-235: DAO refactoring: Permission.hbm.xml 18930: SAIL-235: DAO refactoring: Permission.hbm.xml 18932: SAIL-234 NodeDAO: Fixing up gotchas, javadocs and some naming 18933: SAIL-234 NodeDAO: Minor neatening 18935: SAIL-234 Node DAO: Caches for ID to NodeRef and StoreRef 18936: EHCache config files line endings 18938: SAIL-237: Usage DAO refactor - initial checkpoint 18945: SAIL-235: DAO refactoring: Permission.hbm.xml. Move Node. 18975: Fix for move-node ACL jiggery-pokery 19067: SAIL-4: fix VersionHistoryImpl.getSuccessors (causing VersionServiceImplTest.testGetVersionHistorySameWorkspace failure) 19068: SAIL-234: fix VersionMigratorTest.testMigrateOneVersion 19074: SAIL-237: Usage DAO - update to common iBatis mapping pattern(s) to ease DB porting 19076: SAIL-231: Activities DAO - update to common iBatis mapping pattern(s) 19077: SAIL-232: AppliedPatch DAO - minor cleanup (comments & formatting only) 19092: Merging HEAD to DEV/V3.3-DAO-REFACTOR-2 18973: Temporarily comment out AVMTestSuite and run AVM tests individually 19056: AVM unit test improvements 19097: SAIL-235: DAO refactoring: Permission.hbm.xml: Additional index to support queries to find the id and acl id for the primary children of a node. 19185: SAIL-238: Permissions DAO - (minor) update to common iBatis mapping pattern 19289: SAIL-234 NodeDAO: Node cache replaces NodeRef cache 19302: SAIL-234 Node DAO: Added cache for node properties 19318: SAIL-4: AVM DAO - (minor) update to common iBatis mapping pattern 20690: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-4 to BRANCHES/DEV/V3.3-DAO-REFACTOR-5: 20063: (RECORD ONLY) DAO refactor branch V4 20146: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-3 to BRANCHES/DEV/V3.3-DAO-REFACTOR-4: 19401: SAIL-234 Node DAO: Fix permission service tests (setPrimaryChildrenSharedAclId needs to invalidate nodesCache) 19428: Fixed TransactionalCache issue with null and NullValueMarker 19429: Took empty cm:content creation out of FileFolderService#createImpl 19430: SAIL-234 Node DAO: Tweaks around caching and cm:auditable 19431: SAIL-4 DAO Refactor: Exception thrown when attempting writes in read-only txn have changed 19436: SAIL-234 Node DAO: Fix NPE during cm:auditable update 19475: Allow debugging of code without stepping into trivial stuff 19476: Follow-up on 19429 by ensuring CIFS/FTP set a mimetype on the ContentWriter 19477: SAIL-234 Node DAO: Leverage DAO better for NodeService.addProperties 19478: SAIL-234 NodeDAO: Added toString() for ParentAssocsInfo (cache value for parent assocs) 19479: SAIL-234 Node DAO: Fixed for parent association and property caches 19480: Made TransactionAwareSingleton bind-key a GUID 19481: SAIL-234 Node DAO: Reinstated 100K collection property tests 19482: SAIL-234 Node DAO: Node and property cache fixes highlighted by unit tests 19483: SAIL-234 Node DAO: Start on NodeBulkLoader implementation 19595: SAIL-234 Node DAO: Fix moveNode to detect cyclic relationship prior to updating ACLs for moved tree FileFolderServiceImplTest.testETHREEOH_3088_MoveIntoSelf) 20147: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-3 to BRANCHES/DEV/V3.3-DAO-REFACTOR-4: 19602: (RECORD ONLY) Reintegrated with HEAD up to rev 19433 19621: (RECORD ONLY) SAIL-347 19683: (RECORD ONLY) Reverse-merged 19621 for SAIL-347 19722: (RECORD ONLY) Merged /alfresco/HEAD:r19434-19721 20150: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-3 to BRANCHES/DEV/V3.3-DAO-REFACTOR-4: 19741: Merged DEV\V3.3-DAO-REFACTOR-2 to DEV\V3.3-DAO-REFACTOR-3 19739: Extended "move" tests 19743: Fix AuditableAspectTest.testAddAspect (to allow for node modified date tolerance) 19748: Remaining part of merge from HEAD to V3.3-DAO-REFACTOR-3 19367: Merged BRANCHES/V3.2 to HEAD: 19286: Fix for ALF-626 "Using 'null' as an authority argument in clearPermissions() cause a java.lang.NullPointerException" 19755: SAIL-234 Node DAO: Fix RepoAdminServiceImplTest.testConcurrentDynamicModelDelete (handle InvalidNodeRefException after getChildAssocs) 20692: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-4 to BRANCHES/DEV/V3.3-DAO-REFACTOR-5: - Retired all 1.3 and 1.4 upgrade scripts ... R.I.P. - Fixed CRC patch for Authorities (only tested on MySQL) - Fixed SQL patch revision numbers and bumped version schema number up 20158: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-3 to BRANCHES/DEV/V3.3-DAO-REFACTOR-4: 19773: SQL mappings and scripts: SAIL-310, SAIL-304, SAIL-303 and SAIL-347 19774: Futher fix for SAIL-310: Sequence patch must take into account sequences created for 3.3 19851: SAIL-371 (SAIL-294) NodeDAO fallout: Fix QName and Namespace read/write handling and bean name in unit test 20183: Merged DAO3 to DAO4 19852: SAIL-370: Remove LinkValidation 19853: SAIL-239 (SAIL-294) Attributes.hbm.xml: Added ability to attach arbitrary property to unique context 19857: SAIL-373 Fallout from Permissions DAO refactor (SAIL-235) 19864: SAIL-239 (SAIL-294): Removed AttributeService RMI API 19865: More SAIL-239 (SAIL-294): Removed AttributeService RMI API 20208: DAO-refactor implementation of ALF-2712 query improvements 20209: Merged BRANCHES/DEV/V3.3-DAO-REFACTOR-3 to BRANCHES/DEV/V3.3-DAO-REFACTOR-4: 20060: Removal of AttributeService for SAIL-239 (SAIL-294) 20348: SAIL-371 (SAIL-294): Protect collection properties during map insert and retrieval 20547: SAIL-371 (SAIL-294) Attributes.hbm.xml: implement getAttributes + fixes 20573: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests and other fallout 20597: SAIL-239 Attributes.hbm.xml: WCM/AVM locking test fixes (wip) 20598: SAIL-239 Attributes.hbm.xml: WCM/AVM locking test fixes (wip) - fix AssetServiceImplTest.testSimpleLockFile NPE 20600: Fix PropertyValueDAOTest.testPropertyValue_Enum (follow-on to r20060 for SAIL-239 - which introduces ENUM prop vals) 20601: Fix UsageDAOTest.testCreateAndDeleteUsageDeltas NPE (would also affect ContentStoreCleanerScalabilityRunner) 20603: Fix CMISPropertyServiceTest.* (fallout from r20146 <- r19429 <- Took empty cm:content creation out of FileFolderService#createImpl) 20604: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests - TransferServiceImplTest.* 20618: SAIL-371 (SAIL-294): NodeDAO: AuditableAspectTest (fix testCreateNodeWithAuditableProperties_ALF_2565 + add remove aspect test) 20624: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests - UserUsageTest.* 20626: Fixed random keys for RuleTrigger NodeRef tracking 20635: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests - PersonTest.testSplitDuplicates 20642: SAIL-371 (SAIL-294) DAO: Fixed CacheTest 20643: Removed must of the 'distribute' target's dependencies. Not for HEAD 20645: Follow-on to r20643 (Removed most of the 'distribute' target's dependencies. Not for HEAD) 20654: SAIL-371 (SAIL-294): NodeDAO: DMDeploymentTargetTest.* (do not try to remove mandatory aspects) 20655: SAIL-371 (SAIL-294): NodeDAO: Initial fix for TaggingServiceImplTest.testTagScopeUpdateViaNodePolicies (+ minor test cleanup) 20657: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests - VersionMigratorTest.testMigrateOneVersion (cm:accessed not returned if null) 20658: Merged (back merge only - no merge info) BRANCHES/V3.3 to BRANCHES/DEV/V3.3-DAO-REFACTOR-4: 20090: Dynamic models: minor improvements to DictionaryModelType 20554: Improvement to model delete validation (investigating intermittent failure of RepoAdminServiceImplTest.testSimpleDynamicModelViaNodeService) 20662: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests - RecordsManagementAuditServiceImplTest.* (we now ignore attempt to update 'cm:modifier' prop so update 'cm:title' prop instead) 20666: SAIL-371 (SAIL-294): NodeDAO: Fix unit tests - ADMLuceneTest.* 20668: SAIL-239 (SAIL-294) - delete WCM locks + tests (follow-on to r20060) 20674: SAIL-371 (SAIL-294) NodeDAO fallout: Cleaner and additional checks for ContentStoreCleaner 20675: SAIL-371 (SAIL-294) NodeDAO fallout: Fixed handling of ContentData git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@20693 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .externalToolBuilders/JibX.launch | 5 +- config/alfresco/action-services-context.xml | 16 - config/alfresco/application-context-core.xml | 1 - .../alfresco/attributes-service-context.xml | 152 +- .../authentication-services-context.xml | 4 +- .../alfresco/authority-services-context.xml | 4 +- config/alfresco/avm-services-context.xml | 580 +- config/alfresco/bootstrap-context.xml | 36 +- config/alfresco/cache-context.xml | 505 +- config/alfresco/content-services-context.xml | 3 - config/alfresco/core-services-context.xml | 11 +- config/alfresco/dao/dao-context.xml | 124 +- .../post-create-indexes-02.sql | 8 - .../org.hibernate.dialect.Dialect/sample.sql | 4 - .../sample.sql | 4 - .../AlfrescoPostCreate-2.2-Extra.sql | 41 - .../post-create-indexes-04.sql | 12 - .../post-create-indexes-04.sql | 12 - .../AlfrescoPostCreate-3.2-Indexes.sql | 11 - .../AlfrescoCreate-3.3-RepoTables.sql | 44 - .../AlfrescoCreate-3.3-RepoTables.sql | 48 - .../AlfrescoPostCreate-JBPM-Extra.sql} | 0 .../AlfrescoCreate-AuditTables.sql} | 0 .../AlfrescoCreate-AvmTables.sql} | 0 .../AlfrescoCreate-ContentTables.sql} | 0 .../AlfrescoCreate-LockTables.sql} | 0 .../AlfrescoCreate-PropertyValueTables.sql} | 2 + .../AlfrescoCreate-RepoTables.sql | 503 ++ .../AlfrescoCreate-AuditTables.sql} | 0 .../AlfrescoCreate-AvmTables.sql} | 14 + .../AlfrescoCreate-ContentTables.sql} | 0 .../AlfrescoCreate-LockTables.sql} | 0 .../AlfrescoCreate-PropertyValueTables.sql} | 4 +- .../AlfrescoCreate-RepoTables.sql | 530 ++ .../AlfrescoSchemaMigrate-1.3.sql | 653 -- ...scoSchemaUpdate-1.4-TxnCommitTimeIndex.sql | 17 - .../AlfrescoSchemaUpdate-1.4-1.sql | 130 - .../AlfrescoSchemaUpdate-1.4-2.sql | 66 - .../AddFKIndexes.sql} | 0 .../AddFKIndexes.sql} | 0 .../create-activities-extras.sql | 2 +- .../create-activities-extras.sql | 0 .../fix-AVM-seqs.sql | 23 + ...{fix-Repo-seqs_1.sql => fix-Repo-seqs.sql} | 8 +- .../property-unique-ctx-value.sql | 25 + .../fix-AVM-seqs.sql | 33 + .../fix-Repo-seqs.sql | 55 +- .../fix-Repo-seqs_1.sql | 28 - .../property-unique-ctx-value.sql | 25 + config/alfresco/ehcache-default.xml | 208 +- config/alfresco/ehcache-transactional.xml | 15 - .../ehcache-custom.xml.sample.cluster | 430 +- .../extension/mt/mt-context.xml.sample | 3 - config/alfresco/hibernate-context.xml | 218 - .../alfresco/ibatis/alfresco-SqlMapConfig.xml | 11 +- .../activities-common-SqlMap.xml | 66 +- .../appliedpatch-common-SqlMap.xml | 42 +- .../avm-common-SqlMap.xml | 56 +- .../content-common-SqlMap.xml | 4 +- .../locale-common-SqlMap.xml | 69 + .../node-common-SqlMap.xml | 864 +++ .../node-update-acl-SqlMap.xml | 33 + .../patch-common-SqlMap.xml | 13 + .../permissions-common-SqlMap.xml | 661 ++ .../propval-common-SqlMap.xml | 36 +- .../qname-common-SqlMap.xml | 2 - .../usage-common-SqlMap.xml | 200 + .../activities-insert-SqlMap.xml | 21 +- .../locale-insert-SqlMap.xml | 16 + .../node-insert-SqlMap.xml | 51 + .../node-update-acl-SqlMap.xml | 27 + .../permissions-insert-SqlMap.xml | 65 + .../usage-insert-SqlMap.xml | 16 + .../activities-insert-SqlMap.xml | 19 +- .../avm-insert-SqlMap.xml | 24 +- .../locale-insert-SqlMap.xml | 18 + .../node-insert-SqlMap.xml | 58 + .../permissions-insert-SqlMap.xml | 81 + .../propval-insert-SqlMap.xml | 8 +- .../usage-insert-SqlMap.xml | 17 + config/alfresco/index-recovery-context.xml | 4 +- .../messages/action-config.properties | 5 - .../alfresco/messages/avm-messages.properties | 2 +- .../linkvalidation-messages.properties | 3 - .../messages/patch-service.properties | 7 +- config/alfresco/model/systemModel.xml | 9 - config/alfresco/node-services-context.xml | 14 +- .../alfresco/patch/patch-services-context.xml | 199 +- config/alfresco/public-services-context.xml | 85 +- .../public-services-security-context.xml | 4 +- config/alfresco/remote-services-context.xml | 438 +- config/alfresco/repository.properties | 20 - config/alfresco/usage-services-context.xml | 2 +- config/alfresco/version.properties | 2 +- config/alfresco/wcm-services-context.xml | 4 +- .../workflow/submit_processdefinition.xml | 29 +- .../workflow/wcm-workflow-messages.properties | 2 - config/alfresco/workflow/wcmWorkflowModel.xml | 46 +- .../cmis/mapping/CMISPropertyServiceTest.java | 34 +- .../filesys/repo/ContentNetworkFile.java | 12 +- .../linkvalidation/HrefConcordanceEntry.java | 61 - .../linkvalidation/HrefDifference.java | 121 - .../alfresco/linkvalidation/HrefManifest.java | 73 - .../linkvalidation/HrefManifestEntry.java | 51 - .../linkvalidation/HrefStatusMap.java | 70 - .../HrefValidationProgress.java | 152 - .../LinkValidationAbortedException.java | 62 - .../linkvalidation/LinkValidationAction.java | 226 - .../LinkValidationException.java | 61 - .../linkvalidation/LinkValidationReport.java | 259 - .../linkvalidation/LinkValidationService.java | 194 - .../LinkValidationServiceBootstrap.java | 62 - .../java/org/alfresco/model/ContentModel.java | 3 - .../org/alfresco/model/WCMWorkflowModel.java | 1 - .../activities/hibernate/Activities.hbm.xml | 70 - .../alfresco/repo/admin/RepoServerMgmt.java | 21 - .../repo/admin/RepoServerMgmtMBean.java | 8 - .../repo/admin/patch/AppliedPatch.java | 2 +- .../repo/admin/patch/impl/AVMGuidPatch.java | 128 +- .../patch/impl/AVMLayeredSnapshotPatch.java | 152 +- .../admin/patch/impl/AVMLockingPatch.java | 69 - .../impl/AbstractPermissionChangePatch.java | 103 +- .../patch/impl/ContentUrlConverterPatch.java | 11 - .../admin/patch/impl/DmPermissionsPatch.java | 33 +- .../impl/FixAuthoritiesCrcValuesPatch.java | 211 +- .../patch/impl/FixNameCrcValuesPatch.java | 15 +- .../patch/impl/InvalidNameEndingPatch.java | 15 +- .../impl/LinkNodeFileExtensionPatch.java | 410 +- .../MoveWCMToGroupBasedPermissionsPatch.java | 12 +- .../impl/NodePropertySerializablePatch.java | 132 - .../admin/patch/impl/PersonUsagePatch.java | 29 +- .../ResetWCMToGroupBasedPermissionsPatch.java | 607 +- .../impl/WCMPostPermissionSnapshotPatch.java | 24 +- .../repo/attributes/AbstractAttribute.java | 367 - .../AtrributeMethodNotImplemented.java | 36 - .../repo/attributes/AttrQueryHelperImpl.java | 66 - .../repo/attributes/AttrQueryTest.java | 68 - .../alfresco/repo/attributes/Attribute.java | 648 -- .../repo/attributes/AttributeConverter.java | 54 - .../repo/attributes/AttributeDAO.java | 84 - .../repo/attributes/AttributeImpl.java | 110 - .../AttributeMethodNotImplemented.java | 36 - .../repo/attributes/AttributeServiceImpl.java | 926 +-- .../repo/attributes/AttributeServiceTest.java | 413 +- .../AttributeServiceTransportService.java | 295 - .../AttributeUnsupportedQueryType.java | 36 - .../repo/attributes/AttributeValue.java | 56 - .../repo/attributes/BooleanAttribute.java | 28 - .../repo/attributes/BooleanAttributeImpl.java | 81 - .../attributes/BooleanAttributeValue.java | 73 - .../repo/attributes/ByteAttribute.java | 28 - .../repo/attributes/ByteAttributeImpl.java | 80 - .../repo/attributes/ByteAttributeValue.java | 72 - .../repo/attributes/DoubleAttribute.java | 28 - .../repo/attributes/DoubleAttributeImpl.java | 80 - .../repo/attributes/DoubleAttributeValue.java | 73 - .../repo/attributes/FloatAttribute.java | 28 - .../repo/attributes/FloatAttributeImpl.java | 80 - .../repo/attributes/FloatAttributeValue.java | 73 - .../repo/attributes/GlobalAttributeEntry.java | 42 - .../attributes/GlobalAttributeEntryDAO.java | 66 - .../attributes/GlobalAttributeEntryImpl.java | 73 - .../repo/attributes/IntAttribute.java | 28 - .../repo/attributes/IntAttributeImpl.java | 80 - .../repo/attributes/IntAttributeValue.java | 72 - .../repo/attributes/ListAttribute.java | 28 - .../repo/attributes/ListAttributeImpl.java | 192 - .../repo/attributes/ListAttributeValue.java | 117 - .../alfresco/repo/attributes/ListEntry.java | 47 - .../repo/attributes/ListEntryDAO.java | 77 - .../repo/attributes/ListEntryImpl.java | 110 - .../repo/attributes/ListEntryKey.java | 114 - .../repo/attributes/LongAttribute.java | 28 - .../repo/attributes/LongAttributeImpl.java | 80 - .../repo/attributes/LongAttributeValue.java | 72 - .../repo/attributes/MapAttribute.java | 28 - .../repo/attributes/MapAttributeImpl.java | 186 - .../repo/attributes/MapAttributeValue.java | 132 - .../alfresco/repo/attributes/MapEntry.java | 45 - .../alfresco/repo/attributes/MapEntryDAO.java | 82 - .../repo/attributes/MapEntryImpl.java | 114 - .../alfresco/repo/attributes/MapEntryKey.java | 114 - .../attributes/SerializableAttribute.java | 28 - .../attributes/SerializableAttributeImpl.java | 81 - .../SerializableAttributeValue.java | 73 - .../repo/attributes/ShortAttribute.java | 28 - .../repo/attributes/ShortAttributeImpl.java | 80 - .../repo/attributes/ShortAttributeValue.java | 73 - .../repo/attributes/StringAttribute.java | 28 - .../repo/attributes/StringAttributeImpl.java | 81 - .../repo/attributes/StringAttributeValue.java | 73 - .../hibernate/AttributeDAOHibernate.java | 172 - .../attributes/hibernate/Attributes.hbm.xml | 96 - .../GlobalAttributeEntryDAOHibernate.java | 95 - .../hibernate/ListEntryDAOHibernate.java | 96 - .../hibernate/MapEntryDAOHibernate.java | 103 - .../repo/audit/AuditableAspectTest.java | 150 +- .../java/org/alfresco/repo/avm/AVMDAOs.java | 346 +- .../repo/avm/AVMExpiredContentProcessor.java | 11 +- .../org/alfresco/repo/avm/AVMInterpreter.java | 1943 +++-- .../repo/avm/AVMLockingAwareService.java | 416 +- .../java/org/alfresco/repo/avm/AVMNode.java | 53 +- .../org/alfresco/repo/avm/AVMNodeDAO.java | 261 +- .../org/alfresco/repo/avm/AVMNodeImpl.java | 1161 +-- .../org/alfresco/repo/avm/AVMNodeService.java | 3940 +++++----- .../org/alfresco/repo/avm/AVMRepository.java | 6912 ++++++++--------- .../org/alfresco/repo/avm/AVMServiceImpl.java | 36 +- .../repo/avm/AVMServicePermissionsTest.java | 92 +- .../alfresco/repo/avm/AVMServiceTestBase.java | 1128 ++- .../org/alfresco/repo/avm/AVMStoreImpl.java | 3930 +++++----- .../alfresco/repo/avm/AVMSyncServiceImpl.java | 483 +- .../alfresco/repo/avm/DirectoryNodeImpl.java | 31 +- .../repo/avm/LayeredDirectoryNodeImpl.java | 41 +- .../repo/avm/LayeredFileNodeImpl.java | 71 +- .../org/alfresco/repo/avm/OrphanReaper.java | 15 - .../alfresco/repo/avm/PlainFileNodeImpl.java | 9 +- .../avm/actions/AVMUndoSandboxListAction.java | 288 +- .../repo/avm/ibatis/AVMNodeDAOIbatis.java | 64 +- .../repo/avm/ibatis/AVMStoreDAOIbatis.java | 34 +- .../avm/ibatis/AVMStorePropertyDAOIbatis.java | 33 +- .../repo/avm/locking/AVMLockingBootstrap.java | 67 - .../avm/locking/AVMLockingServiceImpl.java | 1085 ++- .../avm/locking/AVMLockingServiceTest.java | 543 +- .../repo/avm/wf/AVMSubmitLinkChecker.java | 133 - .../org/alfresco/repo/cache/CacheTest.java | 72 +- .../repo/cache/TransactionalCache.java | 72 +- .../repo/cache/lookup/EntityLookupCache.java | 36 +- .../content/cleanup/ContentStoreCleaner.java | 11 - .../ContentStoreCleanerScalabilityRunner.java | 85 +- .../cleanup/ContentStoreCleanerTest.java | 77 +- .../repo/dictionary/DictionaryModelType.java | 2 +- .../DictionaryRepositoryBootstrap.java | 45 +- .../repo/domain/AccessControlListDAO.java | 15 +- .../repo/domain/DbAccessControlEntry.java | 105 - .../domain/DbAccessControlEntryContext.java | 99 - .../repo/domain/DbAccessControlList.java | 144 +- .../domain/DbAccessControlListChangeSet.java | 34 - .../domain/DbAccessControlListMember.java | 82 - .../org/alfresco/repo/domain/DbAuthority.java | 63 - .../repo/domain/DbAuthorityAlias.java | 64 - .../alfresco/repo/domain/DbPermission.java | 76 - .../alfresco/repo/domain/DbPermissionKey.java | 103 - .../alfresco/repo/domain/DomainTestSuite.java | 9 +- .../alfresco/repo/domain/LocaleEntity.java | 41 - .../java/org/alfresco/repo/domain/Node.java | 16 +- .../alfresco/repo/domain/PropertyMapKey.java | 127 - .../alfresco/repo/domain/PropertyValue.java | 83 +- .../repo/domain/PropertyValueTest.java | 1 - .../org/alfresco/repo/domain/Transaction.java | 43 - .../org/alfresco/repo/domain/UsageDelta.java | 36 - .../alfresco/repo/domain/UsageDeltaDAO.java | 59 - .../alfresco/repo/domain/avm/AVMNodeDAO.java | 52 +- .../domain/avm/AVMNodePropertyEntity.java | 1 - .../domain/avm/AVMStorePropertyEntity.java | 1 - .../domain/avm/AbstractAVMNodeDAOImpl.java | 379 +- .../domain/avm/ibatis/AVMNodeDAOImpl.java | 76 +- .../AbstractContentDataDAOImpl.java | 29 +- .../repo/domain/control/ControlDAO.java | 20 +- .../encoding/AbstractEncodingDAOImpl.java | 138 +- .../domain/hibernate/AclDaoComponentImpl.java | 2578 ------ .../hibernate/DMAccessControlListDAO.java | 412 - .../DbAccessControlEntryContextImpl.java | 157 - .../hibernate/DbAccessControlEntryImpl.java | 238 - .../DbAccessControlListChangeSetImpl.java | 75 - .../hibernate/DbAccessControlListImpl.java | 279 - .../DbAccessControlListMemberImpl.java | 169 - .../hibernate/DbAuthorityAliasImpl.java | 149 - .../domain/hibernate/DbAuthorityImpl.java | 140 - .../domain/hibernate/DbPermissionImpl.java | 203 - .../domain/hibernate/HibernateHelper.java | 72 - .../hibernate/HibernateLocaleDAOImpl.java | 213 - .../hibernate/HibernateUsageDeltaDAO.java | 251 - .../repo/domain/hibernate/Locale.hbm.xml | 39 - .../repo/domain/hibernate/Node.hbm.xml | 651 +- .../hibernate/NodeAccessControlListDAO.java | 158 - .../repo/domain/hibernate/NodeAssocImpl.java | 294 - .../repo/domain/hibernate/NodeImpl.java | 45 +- .../OldADMPermissionsDaoComponentImpl.java | 103 - .../repo/domain/hibernate/Permission.hbm.xml | 439 -- .../repo/domain/hibernate/Transaction.hbm.xml | 2 +- .../domain/hibernate/TransactionImpl.java | 2 +- .../repo/domain/hibernate/UsageDelta.hbm.xml | 87 - .../repo/domain/hibernate/UsageDeltaImpl.java | 85 - .../domain/locale/AbstractLocaleDAOImpl.java | 225 + .../repo/domain/{ => locale}/LocaleDAO.java | 42 +- .../domain/{ => locale}/LocaleDAOTest.java | 117 +- .../LocaleEntity.java} | 228 +- .../domain/locale/ibatis/LocaleDAOImpl.java | 82 + .../repo/domain/node/AbstractNodeDAOImpl.java | 2940 +++++++ .../node/AuditablePropertiesEntity.java | 481 ++ .../repo/domain/node/ChildAssocEntity.java | 528 ++ .../org/alfresco/repo/domain/node/Node.java | 55 + .../repo/domain/node/NodeAspectsEntity.java | 77 + .../repo/domain/node/NodeAssocEntity.java | 124 + .../alfresco/repo/domain/node/NodeDAO.java | 607 ++ .../repo/domain/node/NodeDAOTest.java | 156 + .../alfresco/repo/domain/node/NodeEntity.java | 246 + .../repo/domain/node/NodeIdAndAclId.java | 37 + .../repo/domain/node/NodePropertyEntity.java | 95 + .../repo/domain/node/NodePropertyHelper.java | 657 ++ .../repo/domain/node/NodePropertyKey.java | 134 + .../domain/{ => node}/NodePropertyValue.java | 46 +- .../repo/domain/node/NodeUpdateEntity.java | 129 + .../repo/domain/node/ParentAssocsInfo.java | 181 + .../node/PrimaryChildrenAclUpdateEntity.java | 79 + .../node/ReferenceablePropertiesEntity.java | 127 + .../repo/domain/node/ServerEntity.java | 86 + .../repo/domain/node/StoreEntity.java | 117 + .../repo/domain/node/Transaction.java | 40 + .../repo/domain/node/TransactionEntity.java | 110 + .../domain/node/TransactionQueryEntity.java | 173 + .../repo/domain/node/ibatis/NodeDAOImpl.java | 1244 +++ .../patch/AbstractAppliedPatchDAOImpl.java | 2 +- .../domain/patch/AbstractPatchDAOImpl.java | 96 +- .../repo/domain/patch/AppliedPatchDAO.java | 2 +- .../domain/patch/AppliedPatchDAOTest.java | 2 +- .../repo/domain/patch/AppliedPatchEntity.java | 2 +- .../alfresco/repo/domain/patch/PatchDAO.java | 68 + .../patch/ibatis/AppliedPatchDAOImpl.java | 2 +- .../domain/patch/ibatis/IdListOfIdsParam.java | 54 + .../domain/patch/ibatis/PatchDAOImpl.java | 299 +- .../permissions/ADMAccessControlListDAO.java | 446 ++ .../ADMPermissionsDaoComponentImpl.java} | 106 +- .../AVMAccessControlListDAO.java | 337 +- .../AVMPermissionsDaoComponentImpl.java} | 101 +- .../permissions/AbstractAclCrudDAOImpl.java | 1008 +++ .../AbstractPermissionsDaoComponentImpl.java | 101 +- .../alfresco/repo/domain/permissions/Ace.java | 45 + .../repo/domain/permissions/AceContext.java | 40 + .../domain/permissions/AceContextEntity.java | 186 + .../repo/domain/permissions/AceEntity.java | 173 + .../alfresco/repo/domain/permissions/Acl.java | 103 + .../repo/domain/permissions/AclChangeSet.java | 37 + .../permissions/AclChangeSetEntity.java | 102 + .../repo/domain/permissions/AclCrudDAO.java | 123 + .../domain/permissions/AclCrudDAOTest.java | 349 + .../repo/domain/permissions/AclDAO.java | 177 + .../repo/domain/permissions/AclDAOImpl.java | 1789 +++++ .../repo/domain/permissions/AclEntity.java | 246 + .../repo/domain/permissions/AclMember.java | 65 + .../domain/permissions/AclMemberEntity.java | 194 + .../repo/domain/permissions/Authority.java | 39 + .../domain/permissions/AuthorityAlias.java | 39 + .../permissions/AuthorityAliasEntity.java | 126 + .../domain/permissions/AuthorityEntity.java | 136 + .../repo/domain/permissions/Permission.java | 39 + .../domain/permissions/PermissionEntity.java | 149 + .../permissions/ibatis/AclCrudDAOImpl.java | 468 ++ .../propval/AbstractPropertyValueDAOImpl.java | 126 +- .../propval/DefaultPropertyTypeConverter.java | 18 +- .../domain/propval/PropertyTypeConverter.java | 1 + .../PropertyUniqueConstraintViolation.java | 130 +- .../propval/PropertyUniqueContextEntity.java | 12 + .../repo/domain/propval/PropertyValueDAO.java | 64 +- .../domain/propval/PropertyValueDAOTest.java | 105 +- .../domain/propval/PropertyValueEntity.java | 21 + .../propval/ibatis/PropertyValueDAOImpl.java | 51 +- .../domain/qname/AbstractQNameDAOImpl.java | 2 +- .../repo/domain/qname/NamespaceEntity.java | 2 +- .../alfresco/repo/domain/qname/QNameDAO.java | 2 +- .../repo/domain/qname/QNameDAOTest.java | 2 +- .../repo/domain/qname/QNameEntity.java | 2 +- .../domain/qname/ibatis/QNameDAOImpl.java | 2 +- .../repo/domain/schema/SchemaBootstrap.java | 32 +- .../domain/usage/AbstractUsageDAOImpl.java | 154 + .../alfresco/repo/domain/usage/UsageDAO.java | 126 + .../repo/domain/usage/UsageDAOTest.java | 239 + .../repo/domain/usage/UsageDelta.java | 37 + .../repo/domain/usage/UsageDeltaEntity.java | 103 + .../domain/usage/ibatis/UsageDAOImpl.java | 206 + .../org/alfresco/repo/jscript/AVMNode.java | 24 +- .../filefolder/FileFolderServiceImpl.java | 25 +- .../repo/node/AbstractNodeServiceImpl.java | 2 + .../repo/node/BaseNodeServiceTest.java | 33 - .../alfresco/repo/node/NodeBulkLoader.java | 2 +- .../repo/node/NodeServicePolicies.java | 3 + .../cleanup/AbstractNodeCleanupWorker.java | 10 +- .../repo/node/db/DbNodeServiceImpl.java | 1445 ++-- .../repo/node/db/DbNodeServiceImplTest.java | 71 +- .../node/db/DeletedNodeCleanupWorker.java | 10 +- .../db/IndexChildrenWhereRequiredWorker.java | 142 - .../alfresco/repo/node/db/NodeDaoService.java | 634 +- .../HibernateNodeDaoServiceImpl.java | 3983 +--------- .../index/AVMRemoteSnapshotTrackerTest.java | 9 +- .../node/index/AbstractReindexComponent.java | 190 +- .../index/FullIndexRecoveryComponent.java | 15 +- .../index/FullIndexRecoveryComponentTest.java | 25 +- .../node/index/IndexTransactionTracker.java | 12 +- .../index/IndexTransactionTrackerTest.java | 5 +- .../MissingContentReindexComponentTest.java | 6 +- .../repo/props/PropertyValueComponent.java | 144 - .../props/PropertyValueComponentImpl.java | 245 - .../props/PropertyValueComponentTest.java | 146 - .../repo/remote/AttributeServiceRemote.java | 263 - .../ruletrigger/CreateNodeRuleTrigger.java | 17 +- .../OnCreateChildAssociationRuleTrigger.java | 10 +- .../OnPropertyUpdateRuleTrigger.java | 7 +- .../repo/rule/ruletrigger/RuleTrigger.java | 3 + .../impl/lucene/ADMLuceneIndexerImpl.java | 2 +- .../search/impl/lucene/ADMLuceneTest.java | 83 +- .../authentication/AuthenticationContext.java | 2 - .../AuthenticationContextImpl.java | 1 - .../AuthenticationServiceImpl.java | 3 - .../security/authority/AuthorityDAOImpl.java | 14 +- .../authority/AuthorityServiceTest.java | 6 +- .../AccessControlListProperties.java | 3 +- .../SimpleAccessControlListProperties.java | 54 +- .../impl/AbstractPermissionTest.java | 10 +- .../permissions/impl/AclDaoComponent.java | 263 - .../permissions/impl/AclDaoComponentTest.java | 40 +- .../ExceptionTranslatorMethodInterceptor.java | 6 + .../impl/PermissionServiceImpl.java | 5 +- .../impl/PermissionServiceTest.java | 357 +- .../security/person/PersonServiceImpl.java | 72 +- .../ChainingUserRegistrySynchronizer.java | 35 +- .../repo/tagging/TaggingServiceImpl.java | 20 +- .../repo/tagging/TaggingServiceImplTest.java | 11 +- .../repo/template/AVMTemplateNode.java | 32 +- .../repo/tenant/MultiTAdminServiceImpl.java | 98 +- .../transaction/CheckTransactionAdvice.java | 67 +- .../TransactionAwareSingleton.java | 14 +- .../TransactionServiceImplTest.java | 9 +- .../repo/transfer/AbstractNodeFilter.java | 2 +- .../repo/transfer/manifest/package-info.java | 2 +- .../alfresco/repo/usage/ContentUsageImpl.java | 1199 +-- .../alfresco/repo/usage/UsageServiceImpl.java | 132 +- .../usage/UserUsageTrackingComponent.java | 1180 ++- .../usage/UserUsageTrackingComponentTest.java | 775 +- .../repo/version/VersionMigrator.java | 68 +- .../repo/version/VersionMigratorTest.java | 22 +- .../version/common/VersionHistoryImpl.java | 109 +- .../service/cmr/attributes/AttrAndQuery.java | 66 - .../service/cmr/attributes/AttrNotQuery.java | 49 - .../service/cmr/attributes/AttrOrQuery.java | 66 - .../service/cmr/attributes/AttrQuery.java | 46 - .../cmr/attributes/AttrQueryEquals.java | 45 - .../service/cmr/attributes/AttrQueryGT.java | 48 - .../service/cmr/attributes/AttrQueryGTE.java | 49 - .../cmr/attributes/AttrQueryHelper.java | 50 - .../service/cmr/attributes/AttrQueryLT.java | 48 - .../service/cmr/attributes/AttrQueryLTE.java | 48 - .../service/cmr/attributes/AttrQueryLike.java | 49 - .../service/cmr/attributes/AttrQueryNE.java | 48 - .../cmr/attributes/AttributeService.java | 439 +- .../DuplicateAttributeException.java | 61 + .../service/cmr/avm/locking/AVMLock.java | 200 - .../cmr/avm/locking/AVMLockingException.java | 76 +- .../cmr/avm/locking/AVMLockingService.java | 282 +- .../cmr/remote/AttributeServiceTransport.java | 244 - .../repository/AbstractStoreException.java | 16 +- .../AssociationExistsException.java | 30 +- .../cmr/repository/AssociationRef.java | 32 +- .../repository/InvalidStoreRefException.java | 2 +- .../service/cmr/repository/NodeService.java | 34 +- .../cmr/repository/StoreExistsException.java | 9 +- .../datatype/DefaultTypeConverter.java | 74 +- .../datatype/DefaultTypeConverterTest.java | 32 +- .../service/cmr/usage/UsageService.java | 131 +- .../wcm/AbstractWCMServiceImplTest.java | 415 +- .../org/alfresco/wcm/asset/AssetService.java | 107 - .../alfresco/wcm/asset/AssetServiceImpl.java | 108 +- .../wcm/sandbox/SandboxConstants.java | 1 - .../alfresco/wcm/sandbox/SandboxFactory.java | 24 +- .../alfresco/wcm/sandbox/SandboxService.java | 3 +- .../wcm/sandbox/SandboxServiceImpl.java | 18 +- .../wcm/sandbox/SandboxServiceImplTest.java | 20 + .../java/org/alfresco/wcm/util/WCMUtil.java | 3 + .../wcm/webproject/WebProjectServiceImpl.java | 22 +- .../webproject/WebProjectServiceImplTest.java | 36 +- source/test-resources/tenant/mt-context.xml | 3 - 470 files changed, 39121 insertions(+), 44771 deletions(-) delete mode 100644 config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.Dialect/post-create-indexes-02.sql delete mode 100644 config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.Dialect/sample.sql delete mode 100644 config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.MySQLInnoDBDialect/sample.sql delete mode 100644 config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-2.2-Extra.sql delete mode 100644 config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/post-create-indexes-04.sql delete mode 100644 config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.MySQLInnoDBDialect/post-create-indexes-04.sql delete mode 100644 config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-3.2-Indexes.sql delete mode 100644 config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-3.3-RepoTables.sql delete mode 100644 config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-3.3-RepoTables.sql rename config/alfresco/dbscripts/create/{3.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-3.2-JBPM-Extra.sql => org.hibernate.dialect.Dialect/AlfrescoPostCreate-JBPM-Extra.sql} (100%) rename config/alfresco/dbscripts/create/{3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-AuditTables.sql => org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-AuditTables.sql} (100%) rename config/alfresco/dbscripts/create/{3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-AvmTables.sql => org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-AvmTables.sql} (100%) rename config/alfresco/dbscripts/create/{3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-ContentTables.sql => org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-ContentTables.sql} (100%) rename config/alfresco/dbscripts/create/{3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-LockTables.sql => org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-LockTables.sql} (100%) rename config/alfresco/dbscripts/create/{3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-PropertyValueTables.sql => org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-PropertyValueTables.sql} (94%) create mode 100644 config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-RepoTables.sql rename config/alfresco/dbscripts/create/{3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-AuditTables.sql => org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-AuditTables.sql} (100%) rename config/alfresco/dbscripts/create/{3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-AvmTables.sql => org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-AvmTables.sql} (91%) rename config/alfresco/dbscripts/create/{3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-ContentTables.sql => org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-ContentTables.sql} (100%) rename config/alfresco/dbscripts/create/{3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-LockTables.sql => org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-LockTables.sql} (100%) rename config/alfresco/dbscripts/create/{3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-PropertyValueTables.sql => org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-PropertyValueTables.sql} (94%) create mode 100644 config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-RepoTables.sql delete mode 100644 config/alfresco/dbscripts/upgrade/1.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaMigrate-1.3.sql delete mode 100644 config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.Dialect/AlfrescoSchemaUpdate-1.4-TxnCommitTimeIndex.sql delete mode 100644 config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-1.4-1.sql delete mode 100644 config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-1.4-2.sql rename config/alfresco/dbscripts/{create/2.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-2.2-MappedFKIndexes.sql => upgrade/2.2/org.hibernate.dialect.Dialect/AddFKIndexes.sql} (100%) rename config/alfresco/dbscripts/{create/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-2.2-MappedFKIndexes.sql => upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AddFKIndexes.sql} (100%) rename config/alfresco/dbscripts/{create => upgrade}/3.0/org.hibernate.dialect.Dialect/create-activities-extras.sql (97%) rename config/alfresco/dbscripts/{create => upgrade}/3.0/org.hibernate.dialect.PostgreSQLDialect/create-activities-extras.sql (100%) mode change 100644 => 100755 create mode 100755 config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.Dialect/fix-AVM-seqs.sql rename config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.Dialect/{fix-Repo-seqs_1.sql => fix-Repo-seqs.sql} (70%) mode change 100644 => 100755 create mode 100755 config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.MySQLInnoDBDialect/property-unique-ctx-value.sql create mode 100755 config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/fix-AVM-seqs.sql delete mode 100644 config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/fix-Repo-seqs_1.sql create mode 100755 config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/property-unique-ctx-value.sql delete mode 100644 config/alfresco/ehcache-transactional.xml create mode 100644 config/alfresco/ibatis/org.hibernate.dialect.Dialect/locale-common-SqlMap.xml create mode 100644 config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-common-SqlMap.xml create mode 100644 config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-update-acl-SqlMap.xml create mode 100644 config/alfresco/ibatis/org.hibernate.dialect.Dialect/permissions-common-SqlMap.xml create mode 100644 config/alfresco/ibatis/org.hibernate.dialect.Dialect/usage-common-SqlMap.xml create mode 100644 config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/locale-insert-SqlMap.xml create mode 100644 config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/node-insert-SqlMap.xml create mode 100644 config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/node-update-acl-SqlMap.xml create mode 100644 config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/permissions-insert-SqlMap.xml create mode 100644 config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/usage-insert-SqlMap.xml create mode 100755 config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/locale-insert-SqlMap.xml create mode 100755 config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/node-insert-SqlMap.xml create mode 100755 config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/permissions-insert-SqlMap.xml create mode 100755 config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/usage-insert-SqlMap.xml delete mode 100644 config/alfresco/messages/linkvalidation-messages.properties delete mode 100644 source/java/org/alfresco/linkvalidation/HrefConcordanceEntry.java delete mode 100644 source/java/org/alfresco/linkvalidation/HrefDifference.java delete mode 100644 source/java/org/alfresco/linkvalidation/HrefManifest.java delete mode 100644 source/java/org/alfresco/linkvalidation/HrefManifestEntry.java delete mode 100644 source/java/org/alfresco/linkvalidation/HrefStatusMap.java delete mode 100644 source/java/org/alfresco/linkvalidation/HrefValidationProgress.java delete mode 100644 source/java/org/alfresco/linkvalidation/LinkValidationAbortedException.java delete mode 100644 source/java/org/alfresco/linkvalidation/LinkValidationAction.java delete mode 100644 source/java/org/alfresco/linkvalidation/LinkValidationException.java delete mode 100644 source/java/org/alfresco/linkvalidation/LinkValidationReport.java delete mode 100644 source/java/org/alfresco/linkvalidation/LinkValidationService.java delete mode 100644 source/java/org/alfresco/linkvalidation/LinkValidationServiceBootstrap.java delete mode 100644 source/java/org/alfresco/repo/activities/hibernate/Activities.hbm.xml delete mode 100644 source/java/org/alfresco/repo/admin/patch/impl/AVMLockingPatch.java delete mode 100644 source/java/org/alfresco/repo/admin/patch/impl/NodePropertySerializablePatch.java delete mode 100644 source/java/org/alfresco/repo/attributes/AbstractAttribute.java delete mode 100644 source/java/org/alfresco/repo/attributes/AtrributeMethodNotImplemented.java delete mode 100644 source/java/org/alfresco/repo/attributes/AttrQueryHelperImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/AttrQueryTest.java delete mode 100644 source/java/org/alfresco/repo/attributes/Attribute.java delete mode 100644 source/java/org/alfresco/repo/attributes/AttributeConverter.java delete mode 100644 source/java/org/alfresco/repo/attributes/AttributeDAO.java delete mode 100644 source/java/org/alfresco/repo/attributes/AttributeImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/AttributeMethodNotImplemented.java delete mode 100644 source/java/org/alfresco/repo/attributes/AttributeServiceTransportService.java delete mode 100644 source/java/org/alfresco/repo/attributes/AttributeUnsupportedQueryType.java delete mode 100644 source/java/org/alfresco/repo/attributes/AttributeValue.java delete mode 100644 source/java/org/alfresco/repo/attributes/BooleanAttribute.java delete mode 100644 source/java/org/alfresco/repo/attributes/BooleanAttributeImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/BooleanAttributeValue.java delete mode 100644 source/java/org/alfresco/repo/attributes/ByteAttribute.java delete mode 100644 source/java/org/alfresco/repo/attributes/ByteAttributeImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/ByteAttributeValue.java delete mode 100644 source/java/org/alfresco/repo/attributes/DoubleAttribute.java delete mode 100644 source/java/org/alfresco/repo/attributes/DoubleAttributeImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/DoubleAttributeValue.java delete mode 100644 source/java/org/alfresco/repo/attributes/FloatAttribute.java delete mode 100644 source/java/org/alfresco/repo/attributes/FloatAttributeImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/FloatAttributeValue.java delete mode 100644 source/java/org/alfresco/repo/attributes/GlobalAttributeEntry.java delete mode 100644 source/java/org/alfresco/repo/attributes/GlobalAttributeEntryDAO.java delete mode 100644 source/java/org/alfresco/repo/attributes/GlobalAttributeEntryImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/IntAttribute.java delete mode 100644 source/java/org/alfresco/repo/attributes/IntAttributeImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/IntAttributeValue.java delete mode 100644 source/java/org/alfresco/repo/attributes/ListAttribute.java delete mode 100644 source/java/org/alfresco/repo/attributes/ListAttributeImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/ListAttributeValue.java delete mode 100644 source/java/org/alfresco/repo/attributes/ListEntry.java delete mode 100644 source/java/org/alfresco/repo/attributes/ListEntryDAO.java delete mode 100644 source/java/org/alfresco/repo/attributes/ListEntryImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/ListEntryKey.java delete mode 100644 source/java/org/alfresco/repo/attributes/LongAttribute.java delete mode 100644 source/java/org/alfresco/repo/attributes/LongAttributeImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/LongAttributeValue.java delete mode 100644 source/java/org/alfresco/repo/attributes/MapAttribute.java delete mode 100644 source/java/org/alfresco/repo/attributes/MapAttributeImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/MapAttributeValue.java delete mode 100644 source/java/org/alfresco/repo/attributes/MapEntry.java delete mode 100644 source/java/org/alfresco/repo/attributes/MapEntryDAO.java delete mode 100644 source/java/org/alfresco/repo/attributes/MapEntryImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/MapEntryKey.java delete mode 100644 source/java/org/alfresco/repo/attributes/SerializableAttribute.java delete mode 100644 source/java/org/alfresco/repo/attributes/SerializableAttributeImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/SerializableAttributeValue.java delete mode 100644 source/java/org/alfresco/repo/attributes/ShortAttribute.java delete mode 100644 source/java/org/alfresco/repo/attributes/ShortAttributeImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/ShortAttributeValue.java delete mode 100644 source/java/org/alfresco/repo/attributes/StringAttribute.java delete mode 100644 source/java/org/alfresco/repo/attributes/StringAttributeImpl.java delete mode 100644 source/java/org/alfresco/repo/attributes/StringAttributeValue.java delete mode 100644 source/java/org/alfresco/repo/attributes/hibernate/AttributeDAOHibernate.java delete mode 100644 source/java/org/alfresco/repo/attributes/hibernate/Attributes.hbm.xml delete mode 100644 source/java/org/alfresco/repo/attributes/hibernate/GlobalAttributeEntryDAOHibernate.java delete mode 100644 source/java/org/alfresco/repo/attributes/hibernate/ListEntryDAOHibernate.java delete mode 100644 source/java/org/alfresco/repo/attributes/hibernate/MapEntryDAOHibernate.java delete mode 100644 source/java/org/alfresco/repo/avm/locking/AVMLockingBootstrap.java delete mode 100644 source/java/org/alfresco/repo/avm/wf/AVMSubmitLinkChecker.java delete mode 100644 source/java/org/alfresco/repo/domain/DbAccessControlEntry.java delete mode 100644 source/java/org/alfresco/repo/domain/DbAccessControlEntryContext.java delete mode 100644 source/java/org/alfresco/repo/domain/DbAccessControlListChangeSet.java delete mode 100644 source/java/org/alfresco/repo/domain/DbAccessControlListMember.java delete mode 100644 source/java/org/alfresco/repo/domain/DbAuthority.java delete mode 100644 source/java/org/alfresco/repo/domain/DbAuthorityAlias.java delete mode 100644 source/java/org/alfresco/repo/domain/DbPermission.java delete mode 100644 source/java/org/alfresco/repo/domain/DbPermissionKey.java delete mode 100644 source/java/org/alfresco/repo/domain/LocaleEntity.java delete mode 100644 source/java/org/alfresco/repo/domain/PropertyMapKey.java delete mode 100644 source/java/org/alfresco/repo/domain/Transaction.java delete mode 100644 source/java/org/alfresco/repo/domain/UsageDelta.java delete mode 100644 source/java/org/alfresco/repo/domain/UsageDeltaDAO.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/DMAccessControlListDAO.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/DbAccessControlEntryContextImpl.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/DbAccessControlEntryImpl.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListChangeSetImpl.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListImpl.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListMemberImpl.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/DbAuthorityAliasImpl.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/DbAuthorityImpl.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/DbPermissionImpl.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/HibernateHelper.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/HibernateLocaleDAOImpl.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/HibernateUsageDeltaDAO.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/Locale.hbm.xml delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/NodeAccessControlListDAO.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/NodeAssocImpl.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/OldADMPermissionsDaoComponentImpl.java delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/UsageDelta.hbm.xml delete mode 100644 source/java/org/alfresco/repo/domain/hibernate/UsageDeltaImpl.java create mode 100644 source/java/org/alfresco/repo/domain/locale/AbstractLocaleDAOImpl.java rename source/java/org/alfresco/repo/domain/{ => locale}/LocaleDAO.java (66%) rename source/java/org/alfresco/repo/domain/{ => locale}/LocaleDAOTest.java (57%) rename source/java/org/alfresco/repo/domain/{hibernate/LocaleEntityImpl.java => locale/LocaleEntity.java} (62%) create mode 100644 source/java/org/alfresco/repo/domain/locale/ibatis/LocaleDAOImpl.java create mode 100644 source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java create mode 100644 source/java/org/alfresco/repo/domain/node/AuditablePropertiesEntity.java create mode 100644 source/java/org/alfresco/repo/domain/node/ChildAssocEntity.java create mode 100644 source/java/org/alfresco/repo/domain/node/Node.java create mode 100644 source/java/org/alfresco/repo/domain/node/NodeAspectsEntity.java create mode 100644 source/java/org/alfresco/repo/domain/node/NodeAssocEntity.java create mode 100644 source/java/org/alfresco/repo/domain/node/NodeDAO.java create mode 100644 source/java/org/alfresco/repo/domain/node/NodeDAOTest.java create mode 100644 source/java/org/alfresco/repo/domain/node/NodeEntity.java create mode 100644 source/java/org/alfresco/repo/domain/node/NodeIdAndAclId.java create mode 100644 source/java/org/alfresco/repo/domain/node/NodePropertyEntity.java create mode 100644 source/java/org/alfresco/repo/domain/node/NodePropertyHelper.java create mode 100644 source/java/org/alfresco/repo/domain/node/NodePropertyKey.java rename source/java/org/alfresco/repo/domain/{ => node}/NodePropertyValue.java (93%) create mode 100644 source/java/org/alfresco/repo/domain/node/NodeUpdateEntity.java create mode 100644 source/java/org/alfresco/repo/domain/node/ParentAssocsInfo.java create mode 100644 source/java/org/alfresco/repo/domain/node/PrimaryChildrenAclUpdateEntity.java create mode 100644 source/java/org/alfresco/repo/domain/node/ReferenceablePropertiesEntity.java create mode 100644 source/java/org/alfresco/repo/domain/node/ServerEntity.java create mode 100644 source/java/org/alfresco/repo/domain/node/StoreEntity.java create mode 100644 source/java/org/alfresco/repo/domain/node/Transaction.java create mode 100644 source/java/org/alfresco/repo/domain/node/TransactionEntity.java create mode 100644 source/java/org/alfresco/repo/domain/node/TransactionQueryEntity.java create mode 100644 source/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java create mode 100644 source/java/org/alfresco/repo/domain/patch/ibatis/IdListOfIdsParam.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/ADMAccessControlListDAO.java rename source/java/org/alfresco/repo/domain/{hibernate/DMPermissionsDaoComponentImpl.java => permissions/ADMPermissionsDaoComponentImpl.java} (66%) rename source/java/org/alfresco/repo/domain/{hibernate => permissions}/AVMAccessControlListDAO.java (80%) rename source/java/org/alfresco/repo/domain/{hibernate/PermissionsDaoComponentImpl.java => permissions/AVMPermissionsDaoComponentImpl.java} (68%) create mode 100644 source/java/org/alfresco/repo/domain/permissions/AbstractAclCrudDAOImpl.java rename source/java/org/alfresco/repo/domain/{hibernate => permissions}/AbstractPermissionsDaoComponentImpl.java (89%) create mode 100644 source/java/org/alfresco/repo/domain/permissions/Ace.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AceContext.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AceContextEntity.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AceEntity.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/Acl.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AclChangeSet.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AclChangeSetEntity.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AclCrudDAO.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AclCrudDAOTest.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AclDAO.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AclDAOImpl.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AclEntity.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AclMember.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AclMemberEntity.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/Authority.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AuthorityAlias.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AuthorityAliasEntity.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/AuthorityEntity.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/Permission.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/PermissionEntity.java create mode 100644 source/java/org/alfresco/repo/domain/permissions/ibatis/AclCrudDAOImpl.java rename source/java/org/alfresco/repo/{props => domain/propval}/PropertyUniqueConstraintViolation.java (83%) create mode 100644 source/java/org/alfresco/repo/domain/usage/AbstractUsageDAOImpl.java create mode 100644 source/java/org/alfresco/repo/domain/usage/UsageDAO.java create mode 100644 source/java/org/alfresco/repo/domain/usage/UsageDAOTest.java create mode 100644 source/java/org/alfresco/repo/domain/usage/UsageDelta.java create mode 100644 source/java/org/alfresco/repo/domain/usage/UsageDeltaEntity.java create mode 100644 source/java/org/alfresco/repo/domain/usage/ibatis/UsageDAOImpl.java delete mode 100644 source/java/org/alfresco/repo/node/db/IndexChildrenWhereRequiredWorker.java delete mode 100644 source/java/org/alfresco/repo/props/PropertyValueComponent.java delete mode 100644 source/java/org/alfresco/repo/props/PropertyValueComponentImpl.java delete mode 100644 source/java/org/alfresco/repo/props/PropertyValueComponentTest.java delete mode 100644 source/java/org/alfresco/repo/remote/AttributeServiceRemote.java delete mode 100644 source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponent.java delete mode 100644 source/java/org/alfresco/service/cmr/attributes/AttrAndQuery.java delete mode 100644 source/java/org/alfresco/service/cmr/attributes/AttrNotQuery.java delete mode 100644 source/java/org/alfresco/service/cmr/attributes/AttrOrQuery.java delete mode 100644 source/java/org/alfresco/service/cmr/attributes/AttrQuery.java delete mode 100644 source/java/org/alfresco/service/cmr/attributes/AttrQueryEquals.java delete mode 100644 source/java/org/alfresco/service/cmr/attributes/AttrQueryGT.java delete mode 100644 source/java/org/alfresco/service/cmr/attributes/AttrQueryGTE.java delete mode 100644 source/java/org/alfresco/service/cmr/attributes/AttrQueryHelper.java delete mode 100644 source/java/org/alfresco/service/cmr/attributes/AttrQueryLT.java delete mode 100644 source/java/org/alfresco/service/cmr/attributes/AttrQueryLTE.java delete mode 100644 source/java/org/alfresco/service/cmr/attributes/AttrQueryLike.java delete mode 100644 source/java/org/alfresco/service/cmr/attributes/AttrQueryNE.java create mode 100644 source/java/org/alfresco/service/cmr/attributes/DuplicateAttributeException.java delete mode 100644 source/java/org/alfresco/service/cmr/avm/locking/AVMLock.java delete mode 100644 source/java/org/alfresco/service/cmr/remote/AttributeServiceTransport.java diff --git a/.externalToolBuilders/JibX.launch b/.externalToolBuilders/JibX.launch index aadf2c5fa3..7849a631a2 100644 --- a/.externalToolBuilders/JibX.launch +++ b/.externalToolBuilders/JibX.launch @@ -1,4 +1,4 @@ - + @@ -21,11 +21,12 @@ - + + diff --git a/config/alfresco/action-services-context.xml b/config/alfresco/action-services-context.xml index f26b7c4ce3..abdea3384c 100644 --- a/config/alfresco/action-services-context.xml +++ b/config/alfresco/action-services-context.xml @@ -758,22 +758,6 @@ - - - - - - - - - - false - - - 500 - - - diff --git a/config/alfresco/application-context-core.xml b/config/alfresco/application-context-core.xml index 206e21dac8..8d25887c16 100644 --- a/config/alfresco/application-context-core.xml +++ b/config/alfresco/application-context-core.xml @@ -43,5 +43,4 @@ - diff --git a/config/alfresco/attributes-service-context.xml b/config/alfresco/attributes-service-context.xml index 038ca1e8e8..45eac09fe8 100644 --- a/config/alfresco/attributes-service-context.xml +++ b/config/alfresco/attributes-service-context.xml @@ -1,141 +1,13 @@ - - - - - - - - - - - - - 500 - - - 250 - - - - - - - - - 100 - - - 100 - - - 0 - - - - - - org.alfresco.service.cmr.attributes.AttributeService - - - - - - - attrSessionSizeResourceInterceptor - - - - - - - - - - - - - - - - - - - - - - - - - - daoServiceDirtySessionInterceptor - - - - - - - - - - - - - - - - - - - - - - - daoServiceDirtySessionInterceptor - - - - - - - - - - - - - - - - - - - - daoServiceDirtySessionInterceptor - - - - - - - - - - - - - - - - - daoServiceDirtySessionInterceptor - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/authentication-services-context.xml b/config/alfresco/authentication-services-context.xml index 3a4e32dbca..00dedab58f 100644 --- a/config/alfresco/authentication-services-context.xml +++ b/config/alfresco/authentication-services-context.xml @@ -306,8 +306,8 @@ - - + + diff --git a/config/alfresco/authority-services-context.xml b/config/alfresco/authority-services-context.xml index f7ddb4a5d9..b02685ca94 100644 --- a/config/alfresco/authority-services-context.xml +++ b/config/alfresco/authority-services-context.xml @@ -88,8 +88,8 @@ - - + + diff --git a/config/alfresco/avm-services-context.xml b/config/alfresco/avm-services-context.xml index 9b0dea0e81..beabe68e52 100644 --- a/config/alfresco/avm-services-context.xml +++ b/config/alfresco/avm-services-context.xml @@ -1,309 +1,283 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1000 - - - 50 - - - 1000 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .*/#[^/]* - - - - - - - - .o - .bak - .tmp - ~ - - - - - - - - - - - - - - - - - admin - - - jbpm$wcmwf:changerequest - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1000 + + + 50 + + + 1000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + .*/#[^/]* + + + + + + + + .o + .bak + .tmp + ~ + + + + + + + + + + + + + + + + + admin + + + jbpm$wcmwf:changerequest + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - workspace://SpacesStore - - - - - - - - - - - 500 - - - 250 - - - - - - - - - 100 - - - 100 - - - 0 - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + workspace://SpacesStore + + + + + + + + + + + 500 + + + 250 + + + + + + + + + 100 + + + 100 + + + 0 + + + diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml index 6839fe47b3..b145e1a739 100644 --- a/config/alfresco/bootstrap-context.xml +++ b/config/alfresco/bootstrap-context.xml @@ -68,22 +68,17 @@ - classpath:alfresco/dbscripts/create/3.3/${db.script.dialect}/AlfrescoCreate-3.3-RepoTables.sql + classpath:alfresco/dbscripts/create/${db.script.dialect}/AlfrescoCreate-RepoTables.sql + classpath:alfresco/dbscripts/create/${db.script.dialect}/AlfrescoCreate-LockTables.sql + classpath:alfresco/dbscripts/create/${db.script.dialect}/AlfrescoCreate-ContentTables.sql + classpath:alfresco/dbscripts/create/${db.script.dialect}/AlfrescoCreate-PropertyValueTables.sql + classpath:alfresco/dbscripts/create/${db.script.dialect}/AlfrescoCreate-AuditTables.sql + classpath:alfresco/dbscripts/create/${db.script.dialect}/AlfrescoCreate-AvmTables.sql - classpath:alfresco/dbscripts/create/2.2/${db.script.dialect}/AlfrescoPostCreate-2.2-MappedFKIndexes.sql - classpath:alfresco/dbscripts/create/2.2/${db.script.dialect}/AlfrescoPostCreate-2.2-Extra.sql - classpath:alfresco/dbscripts/create/2.2/${db.script.dialect}/post-create-indexes-04.sql - classpath:alfresco/dbscripts/create/3.0/${db.script.dialect}/create-activities-extras.sql - classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-LockTables.sql - classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-ContentTables.sql - classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-PropertyValueTables.sql - classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-AuditTables.sql - classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-AvmTables.sql - classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-Indexes.sql - classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-JBPM-Extra.sql + classpath:alfresco/dbscripts/create/${db.script.dialect}/AlfrescoPostCreate-JBPM-Extra.sql @@ -92,8 +87,6 @@ - - @@ -114,7 +107,6 @@ - @@ -127,7 +119,9 @@ - + + + @@ -162,12 +156,6 @@ - - - - - - @@ -541,8 +529,8 @@ - - + + diff --git a/config/alfresco/cache-context.xml b/config/alfresco/cache-context.xml index 5b489335a5..da807c154f 100644 --- a/config/alfresco/cache-context.xml +++ b/config/alfresco/cache-context.xml @@ -9,17 +9,6 @@ --> - - - - - - - - classpath:alfresco/ehcache-transactional.xml - - - @@ -28,163 +17,19 @@ - + - + - + - org.alfresco.cache.qnameEntityCache - - - - - - - - - - - - - - - - org.alfresco.cache.qnameEntityTransactionalCache - - - 500 - - - - - - - - - - - - - - - - - org.alfresco.cache.namespaceEntityCache - - - - - - - - - - - - - - - - org.alfresco.cache.namespaceEntityTransactionalCache - - - 100 - - - - - - - - - - - - - - - - - org.alfresco.cache.localeIdCache - - - - - - - - - - - - - - - - org.alfresco.cache.localeEntityTransactionalCache - - - 100 - - - - - - - - - - - - - - - - - org.alfresco.cache.mimetypeEntityCache - - - - - - - - - - - - - - - - org.alfresco.cache.mimetypeEntityTransactionalCache - - - 100 - - - - - - - - - - - - - - - - - org.alfresco.cache.encodingEntityCache + org.alfresco.cache.propertyValueCache @@ -192,23 +37,20 @@ - + - - - - + - org.alfresco.cache.encodingEntityTransactionalCache + org.alfresco.cache.propertyValueTransactionalCache - 100 + 1000 - + @@ -232,14 +74,11 @@ - - - org.alfresco.cache.contentDataTransactionalCache - 10000 + 1000 @@ -247,7 +86,7 @@ - + @@ -262,15 +101,12 @@ - + - - - org.alfresco.cache.immutableEntityTransactionalCache @@ -279,56 +115,152 @@ - - - + + + - - - + + + - org.alfresco.cache.storeAndNodeIdCache + org.alfresco.cache.node.rootNodesCache - + - + - - - - + - org.alfresco.storeAndNodeIdTransactionalCache + org.alfresco.cache.node.rootNodesTransactionalCache + + + 50 + + + + + + + + + + + + + + + + + org.alfresco.cache.node.nodesCache + + + + + + + + + + + + + org.alfresco.cache.node.nodesTransactionalCache + + + 50000 + + + + + + + + + + + + + + + + + org.alfresco.cache.node.aspectsCache + + + + + + + + + + + + + org.alfresco.cache.node.aspectsTransactionalCache 10000 + + + + + + + + + + + + + + org.alfresco.cache.node.propertiesCache + + + + + + + + + + + + + org.alfresco.cache.node.propertiesTransactionalCache + + + 5000 + + + - + - org.alfresco.cache.parentAssocsCache + org.alfresco.cache.node.parentAssocsCache @@ -336,15 +268,12 @@ - + - - - - + - org.alfresco.parentAssocsTransactionalCache + org.alfresco.cache.node.parentAssocsTransactionalCache 80000 @@ -365,9 +294,6 @@ - - - org.alfresco.nodeRulesTransactionalCache @@ -401,9 +327,6 @@ - - - org.alfresco.userToAuthorityTransactionalCache @@ -437,9 +360,6 @@ - - - org.alfresco.authorityTransactionalCache @@ -473,10 +393,6 @@ - - - - org.alfresco.permissionsAccessTransactionalCache @@ -510,9 +426,6 @@ - - - org.alfresco.nodeOwnerTransactionalCache @@ -546,10 +459,6 @@ - - - - org.alfresco.personTransactionalCache @@ -583,9 +492,6 @@ - - - org.alfresco.ticketsTransactionalCache @@ -624,9 +530,6 @@ - - - org.alfresco.cache.avmStoreTransactionalCache @@ -656,9 +559,6 @@ - - - org.alfresco.cache.avmEntityTransactionalCache @@ -688,9 +588,6 @@ - - - org.alfresco.cache.avmVersionRootEntityTransactionalCache @@ -720,9 +617,6 @@ - - - org.alfresco.cache.avmNodeTransactionalCache @@ -753,9 +647,6 @@ - - - org.alfresco.cache.avmNodeAspectsTransactionalCache @@ -789,9 +680,6 @@ - - - org.alfresco.repo.webservices.querySessionTransactionalCache @@ -826,9 +714,6 @@ - - - org.alfresco.aclTransactionalCache @@ -836,11 +721,122 @@ 10000 - + + + + + + + + + + + + + + + + + + + org.alfresco.cache.aclEntityTransactionalCache + + + 50000 + + + + + + + + + + + + + + + + + + + + + org.alfresco.cache.authorityEntityTransactionalCache + + + 50000 + + + + + + + + + + + + + + + + + + + + + org.alfresco.cache.permissionEntityTransactionalCache + + + 50000 + + + - + @@ -862,9 +858,6 @@ - - - org.alfresco.resourceBundleBaseNamesTransactionalCache @@ -894,9 +887,6 @@ - - - org.alfresco.loadedResourceBundlesTransactionalCache @@ -926,9 +916,6 @@ - - - org.alfresco.messagesTransactionalCache @@ -963,9 +950,6 @@ - - - org.alfresco.compiledModelsTransactionalCache @@ -995,9 +979,6 @@ - - - org.alfresco.prefixesTransactionalCache @@ -1031,9 +1012,6 @@ - - - org.alfresco.webScriptsRegistryTransactionalCache @@ -1067,9 +1045,6 @@ - - - org.alfresco.routingContentStoreTransactionalCache diff --git a/config/alfresco/content-services-context.xml b/config/alfresco/content-services-context.xml index 3cc790d736..21b5414923 100644 --- a/config/alfresco/content-services-context.xml +++ b/config/alfresco/content-services-context.xml @@ -51,9 +51,6 @@ - - - diff --git a/config/alfresco/core-services-context.xml b/config/alfresco/core-services-context.xml index ed41d5c6fc..7b96191c37 100644 --- a/config/alfresco/core-services-context.xml +++ b/config/alfresco/core-services-context.xml @@ -411,7 +411,6 @@ alfresco.messages.webdav-messages alfresco.messages.copy-service alfresco.messages.avm-messages - alfresco.messages.linkvalidation-messages alfresco.messages.content-filter-languages alfresco.messages.jbpm-engine-messages @@ -448,14 +447,6 @@ - - - - - - - - @@ -721,7 +712,7 @@ - + diff --git a/config/alfresco/dao/dao-context.xml b/config/alfresco/dao/dao-context.xml index f8cefc9971..779e7151ee 100644 --- a/config/alfresco/dao/dao-context.xml +++ b/config/alfresco/dao/dao-context.xml @@ -40,9 +40,10 @@ - + + @@ -56,6 +57,23 @@ + + + + + + + + + + + + + + + + + @@ -63,12 +81,17 @@ - + - + + + + + + @@ -85,15 +108,16 @@ + - - + + @@ -132,4 +156,84 @@ + + + + + org.alfresco.repo.security.permissions.impl.PermissionsDaoComponent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.Dialect/post-create-indexes-02.sql b/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.Dialect/post-create-indexes-02.sql deleted file mode 100644 index b56282bfbe..0000000000 --- a/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.Dialect/post-create-indexes-02.sql +++ /dev/null @@ -1,8 +0,0 @@ --- --- More post-creation indexes. (Generic Schema 1.4) --- --- These are not declared in the Hibernate mappings. --- - --- Association QNames -CREATE INDEX idx_ca_qname ON alf_child_assoc (qname); diff --git a/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.Dialect/sample.sql b/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.Dialect/sample.sql deleted file mode 100644 index ba873b987c..0000000000 --- a/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.Dialect/sample.sql +++ /dev/null @@ -1,4 +0,0 @@ --- --- Insert post-creation scripts here --- This is a generic fallback for cases where specific dialects are not catered for --- \ No newline at end of file diff --git a/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.MySQLInnoDBDialect/sample.sql b/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.MySQLInnoDBDialect/sample.sql deleted file mode 100644 index ec41ade051..0000000000 --- a/config/alfresco/dbscripts/create/1.4/org.hibernate.dialect.MySQLInnoDBDialect/sample.sql +++ /dev/null @@ -1,4 +0,0 @@ --- --- Insert post-creation scripts here --- This is specific to the dialect described in the path to the file --- \ No newline at end of file diff --git a/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-2.2-Extra.sql b/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-2.2-Extra.sql deleted file mode 100644 index 59423d243f..0000000000 --- a/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-2.2-Extra.sql +++ /dev/null @@ -1,41 +0,0 @@ --- --- Title: Post-Create Constraints --- Database: Generic --- Since: V2.2 Schema 86 --- Author: Derek Hulley --- --- Certain Hibernate mappings don't allow constraints to be declared and are therefore --- explicitly required. All other constraints are automatically added by the --- Hibernate-generated script. --- --- Please contact support@alfresco.com if you need assistance with the upgrade. --- - --- --- Explicit indexes and constraints not declared in the mappings --- - -CREATE INDEX fk_alf_cass_tqn ON alf_child_assoc (type_qname_id); -ALTER TABLE alf_child_assoc ADD CONSTRAINT fk_alf_cass_tqn FOREIGN KEY (type_qname_id) REFERENCES alf_qname (id); - -CREATE INDEX fk_alf_cass_qnns ON alf_child_assoc (qname_ns_id); -ALTER TABLE alf_child_assoc ADD CONSTRAINT fk_alf_cass_qnns FOREIGN KEY (qname_ns_id) REFERENCES alf_namespace (id); - -CREATE INDEX fk_alf_node_tqn ON alf_node (type_qname_id); -ALTER TABLE alf_node ADD CONSTRAINT fk_alf_node_tqn FOREIGN KEY (type_qname_id) REFERENCES alf_qname (id); - -CREATE INDEX fk_alf_nasp_qn ON alf_node_aspects (qname_id); -ALTER TABLE alf_node_aspects ADD CONSTRAINT fk_alf_nasp_qn FOREIGN KEY (qname_id) REFERENCES alf_qname (id); - -CREATE INDEX fk_alf_nass_tqn ON alf_node_assoc (type_qname_id); -ALTER TABLE alf_node_assoc ADD CONSTRAINT fk_alf_nass_tqn FOREIGN KEY (type_qname_id) REFERENCES alf_qname (id); - -CREATE INDEX fk_alf_nprop_qn ON alf_node_properties (qname_id); -ALTER TABLE alf_node_properties ADD CONSTRAINT fk_alf_nprop_qn FOREIGN KEY (qname_id) REFERENCES alf_qname (id); - -CREATE INDEX fk_alf_nprop_loc ON alf_node_properties (locale_id); -ALTER TABLE alf_node_properties ADD CONSTRAINT fk_alf_nprop_loc FOREIGN KEY (locale_id) REFERENCES alf_locale (id); - -CREATE INDEX fk_alf_perm_tqn ON alf_permission (type_qname_id); -ALTER TABLE alf_permission ADD CONSTRAINT fk_alf_perm_tqn FOREIGN KEY (type_qname_id) REFERENCES alf_qname (id); - diff --git a/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/post-create-indexes-04.sql b/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/post-create-indexes-04.sql deleted file mode 100644 index e7ce879199..0000000000 --- a/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/post-create-indexes-04.sql +++ /dev/null @@ -1,12 +0,0 @@ --- --- Title: Audit Path index --- Database: Generic --- Since: V2.1 Schema 81 --- Author: Andy Hind --- --- Please contact support@alfresco.com if you need assistance with the upgrade. --- --- Audit path index - - -CREATE INDEX idx_alf_adtf_pth ON alf_audit_fact (path); diff --git a/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.MySQLInnoDBDialect/post-create-indexes-04.sql b/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.MySQLInnoDBDialect/post-create-indexes-04.sql deleted file mode 100644 index 2c63c5d7dd..0000000000 --- a/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.MySQLInnoDBDialect/post-create-indexes-04.sql +++ /dev/null @@ -1,12 +0,0 @@ --- --- Title: Audit Path index --- Database: Generic --- Since: V2.1 Schema 81 --- Author: Andy Hind --- --- Please contact support@alfresco.com if you need assistance with the upgrade. --- --- Audit path index - - -CREATE INDEX idx_alf_adtf_pth ON alf_audit_fact (path(128)); diff --git a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-3.2-Indexes.sql b/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-3.2-Indexes.sql deleted file mode 100644 index 8af6895fed..0000000000 --- a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-3.2-Indexes.sql +++ /dev/null @@ -1,11 +0,0 @@ --- --- Title: Additional Indexes --- Database: Generic --- Since: V3.2 schema 2023 --- Author: davew --- --- Please contact support@alfresco.com if you need assistance with the upgrade. --- --- Additional indexes - -CREATE INDEX idx_alf_cass_qncrc on alf_child_assoc (qname_crc, type_qname_id, parent_node_id); diff --git a/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-3.3-RepoTables.sql b/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-3.3-RepoTables.sql deleted file mode 100644 index 977992bcee..0000000000 --- a/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-3.3-RepoTables.sql +++ /dev/null @@ -1,44 +0,0 @@ --- --- Title: Core Repository Tables --- Database: MySQL InnoDB --- Since: V3.3 Schema 4000 --- Author: Derek Hulley --- --- Please contact support@alfresco.com if you need assistance with the upgrade. --- - -CREATE TABLE alf_applied_patch -( - id VARCHAR(64) NOT NULL, - description TEXT, - fixes_from_schema INTEGER, - fixes_to_schema INTEGER, - applied_to_schema INTEGER, - target_schema INTEGER, - applied_on_date DATETIME, - applied_to_server VARCHAR(64), - was_executed BIT, - succeeded BIT, - report TEXT, - PRIMARY KEY (id) -) ENGINE=InnoDB; - -CREATE TABLE alf_namespace -( - id BIGINT NOT NULL AUTO_INCREMENT, - version BIGINT NOT NULL, - uri VARCHAR(100) NOT NULL, - UNIQUE (uri), - PRIMARY KEY (id) -) ENGINE=InnoDB; - -CREATE TABLE alf_qname -( - id BIGINT NOT NULL AUTO_INCREMENT, - version BIGINT NOT NULL, - ns_id BIGINT NOT NULL, - local_name VARCHAR(200) NOT NULL, - CONSTRAINT FOREIGN KEY fk_alf_qname_ns (ns_id) REFERENCES alf_namespace (id), - UNIQUE (ns_id, local_name), - PRIMARY KEY (id) -) ENGINE=InnoDB; diff --git a/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-3.3-RepoTables.sql b/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-3.3-RepoTables.sql deleted file mode 100644 index 36a7b9d0f6..0000000000 --- a/config/alfresco/dbscripts/create/3.3/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-3.3-RepoTables.sql +++ /dev/null @@ -1,48 +0,0 @@ --- --- Title: Core Repository Tables --- Database: PostgreSQL --- Since: V3.3 Schema 4000 --- Author: unknown --- --- Please contact support@alfresco.com if you need assistance with the upgrade. --- - -CREATE TABLE alf_applied_patch -( - id VARCHAR(64) NOT NULL, - description VARCHAR(1024), - fixes_from_schema INT4, - fixes_to_schema INT4, - applied_to_schema INT4, - target_schema INT4, - applied_on_date TIMESTAMP, - applied_to_server VARCHAR(64), - was_executed BOOL, - succeeded BOOL, - report VARCHAR(1024), - PRIMARY KEY (id) -); - -CREATE TABLE alf_namespace -( - id INT8 NOT NULL, - version INT8 NOT NULL, - uri VARCHAR(100) NOT NULL, - PRIMARY KEY (id) -); - -CREATE UNIQUE INDEX uri ON alf_namespace (uri); -CREATE SEQUENCE alf_namespace_seq START WITH 1 INCREMENT BY 1; - -CREATE TABLE alf_qname -( - id INT8 NOT NULL, - version INT8 NOT NULL, - ns_id INT8 NOT NULL, - local_name VARCHAR(200) NOT NULL, - CONSTRAINT fk_alf_qname_ns FOREIGN KEY (ns_id) REFERENCES alf_namespace (id), - PRIMARY KEY (id) -); -CREATE UNIQUE INDEX ns_id ON alf_qname (ns_id, local_name); -CREATE INDEX fk_alf_qname_ns ON alf_qname (ns_id); -CREATE SEQUENCE alf_qname_seq START WITH 1 INCREMENT BY 1; \ No newline at end of file diff --git a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-3.2-JBPM-Extra.sql b/config/alfresco/dbscripts/create/org.hibernate.dialect.Dialect/AlfrescoPostCreate-JBPM-Extra.sql similarity index 100% rename from config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-3.2-JBPM-Extra.sql rename to config/alfresco/dbscripts/create/org.hibernate.dialect.Dialect/AlfrescoPostCreate-JBPM-Extra.sql diff --git a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-AuditTables.sql b/config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-AuditTables.sql similarity index 100% rename from config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-AuditTables.sql rename to config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-AuditTables.sql diff --git a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-AvmTables.sql b/config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-AvmTables.sql similarity index 100% rename from config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-AvmTables.sql rename to config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-AvmTables.sql diff --git a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-ContentTables.sql b/config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-ContentTables.sql similarity index 100% rename from config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-ContentTables.sql rename to config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-ContentTables.sql diff --git a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-LockTables.sql b/config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-LockTables.sql similarity index 100% rename from config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-LockTables.sql rename to config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-LockTables.sql diff --git a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-PropertyValueTables.sql b/config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-PropertyValueTables.sql similarity index 94% rename from config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-PropertyValueTables.sql rename to config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-PropertyValueTables.sql index 6d9ab59542..53d0f6d379 100644 --- a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-3.2-PropertyValueTables.sql +++ b/config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-PropertyValueTables.sql @@ -100,10 +100,12 @@ CREATE TABLE alf_prop_unique_ctx value1_prop_id BIGINT NOT NULL, value2_prop_id BIGINT NOT NULL, value3_prop_id BIGINT NOT NULL, + prop1_id BIGINT NULL, UNIQUE INDEX idx_alf_propuctx (value1_prop_id, value2_prop_id, value3_prop_id), CONSTRAINT fk_alf_propuctx_v1 FOREIGN KEY (value1_prop_id) REFERENCES alf_prop_value (id) ON DELETE CASCADE, CONSTRAINT fk_alf_propuctx_v2 FOREIGN KEY (value2_prop_id) REFERENCES alf_prop_value (id) ON DELETE CASCADE, CONSTRAINT fk_alf_propuctx_v3 FOREIGN KEY (value3_prop_id) REFERENCES alf_prop_value (id) ON DELETE CASCADE, + CONSTRAINT fk_alf_propuctx_p1 FOREIGN KEY (prop1_id) REFERENCES alf_prop_root (id), PRIMARY KEY (id) ) ENGINE=InnoDB; diff --git a/config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-RepoTables.sql b/config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-RepoTables.sql new file mode 100644 index 0000000000..2e54b42b6b --- /dev/null +++ b/config/alfresco/dbscripts/create/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoCreate-RepoTables.sql @@ -0,0 +1,503 @@ +-- +-- Title: Core Repository Tables +-- Database: MySQL InnoDB +-- Since: V3.3 Schema 4000 +-- Author: Derek Hulley, janv +-- +-- Please contact support@alfresco.com if you need assistance with the upgrade. +-- + +CREATE TABLE alf_applied_patch +( + id VARCHAR(64) NOT NULL, + description TEXT, + fixes_from_schema INTEGER, + fixes_to_schema INTEGER, + applied_to_schema INTEGER, + target_schema INTEGER, + applied_on_date DATETIME, + applied_to_server VARCHAR(64), + was_executed BIT, + succeeded BIT, + report TEXT, + PRIMARY KEY (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_namespace +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + uri VARCHAR(100) NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY uri (uri) +) ENGINE=InnoDB; + +CREATE TABLE alf_qname +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + ns_id BIGINT NOT NULL, + local_name VARCHAR(200) NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY ns_id (ns_id, local_name), + KEY fk_alf_qname_ns (ns_id), + CONSTRAINT fk_alf_qname_ns FOREIGN KEY (ns_id) REFERENCES alf_namespace (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_permission +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + type_qname_id BIGINT NOT NULL, + name VARCHAR(100) NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY type_qname_id (type_qname_id, name), + KEY fk_alf_perm_tqn (type_qname_id), + CONSTRAINT fk_alf_perm_tqn FOREIGN KEY (type_qname_id) REFERENCES alf_qname (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_ace_context +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + class_context TEXT, + property_context TEXT, + kvp_context TEXT, + PRIMARY KEY (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_authority +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + authority VARCHAR(100), + crc BIGINT, + PRIMARY KEY (id), + UNIQUE KEY authority (authority, crc), + KEY idx_alf_auth_aut (authority) +) ENGINE=InnoDB; + +CREATE TABLE alf_access_control_entry +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + permission_id BIGINT NOT NULL, + authority_id BIGINT NOT NULL, + allowed BIT NOT NULL, + applies INTEGER NOT NULL, + context_id BIGINT, + PRIMARY KEY (id), + UNIQUE KEY permission_id (permission_id, authority_id, allowed, applies, context_id), + KEY fk_alf_ace_ctx (context_id), + KEY fk_alf_ace_perm (permission_id), + KEY fk_alf_ace_auth (authority_id), + CONSTRAINT fk_alf_ace_auth FOREIGN KEY (authority_id) REFERENCES alf_authority (id), + CONSTRAINT fk_alf_ace_ctx FOREIGN KEY (context_id) REFERENCES alf_ace_context (id), + CONSTRAINT fk_alf_ace_perm FOREIGN KEY (permission_id) REFERENCES alf_permission (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_acl_change_set +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_access_control_list +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + acl_id VARCHAR(36) NOT NULL, + latest BIT NOT NULL, + acl_version BIGINT NOT NULL, + inherits BIT NOT NULL, + inherits_from BIGINT, + type INTEGER NOT NULL, + inherited_acl BIGINT, + is_versioned BIT NOT NULL, + requires_version BIT NOT NULL, + acl_change_set BIGINT, + PRIMARY KEY (id), + UNIQUE KEY acl_id (acl_id, latest, acl_version), + KEY idx_alf_acl_inh (inherits, inherits_from), + KEY fk_alf_acl_acs (acl_change_set), + CONSTRAINT fk_alf_acl_acs FOREIGN KEY (acl_change_set) REFERENCES alf_acl_change_set (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_acl_member +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + acl_id BIGINT NOT NULL, + ace_id BIGINT NOT NULL, + pos INTEGER NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY aclm_acl_id (acl_id, ace_id, pos), + KEY fk_alf_aclm_acl (acl_id), + KEY fk_alf_aclm_ace (ace_id), + CONSTRAINT fk_alf_aclm_ace FOREIGN KEY (ace_id) REFERENCES alf_access_control_entry (id), + CONSTRAINT fk_alf_aclm_acl FOREIGN KEY (acl_id) REFERENCES alf_access_control_list (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_authority_alias +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + auth_id BIGINT NOT NULL, + alias_id BIGINT NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY auth_id (auth_id, alias_id), + KEY fk_alf_autha_ali (alias_id), + KEY fk_alf_autha_aut (auth_id), + CONSTRAINT fk_alf_autha_aut FOREIGN KEY (auth_id) REFERENCES alf_authority (id), + CONSTRAINT fk_alf_autha_ali FOREIGN KEY (alias_id) REFERENCES alf_authority (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_activity_feed +( + id BIGINT NOT NULL AUTO_INCREMENT, + post_id BIGINT, + post_date DATETIME NOT NULL, + activity_summary TEXT, + feed_user_id VARCHAR(255), + activity_type VARCHAR(255) NOT NULL, + activity_format VARCHAR(10), + site_network VARCHAR(255), + app_tool VARCHAR(36), + post_user_id VARCHAR(255) NOT NULL, + feed_date DATETIME NOT NULL, + PRIMARY KEY (id), + KEY feed_postdate_idx (post_date), + KEY feed_postuserid_idx (post_user_id), + KEY feed_feeduserid_idx (feed_user_id), + KEY feed_sitenetwork_idx (site_network), + KEY feed_activityformat_idx (activity_format) +) ENGINE=InnoDB; + +CREATE TABLE alf_activity_feed_control +( + id BIGINT NOT NULL AUTO_INCREMENT, + feed_user_id VARCHAR(255) NOT NULL, + site_network VARCHAR(255), + app_tool VARCHAR(36), + last_modified DATETIME NOT NULL, + PRIMARY KEY (id), + KEY feedctrl_feeduserid_idx (feed_user_id) +) ENGINE=InnoDB; + +CREATE TABLE alf_activity_post +( + sequence_id BIGINT NOT NULL AUTO_INCREMENT, + post_date DATETIME NOT NULL, + status VARCHAR(10) NOT NULL, + activity_data TEXT NOT NULL, + post_user_id VARCHAR(255) NOT NULL, + job_task_node INTEGER NOT NULL, + site_network VARCHAR(255), + app_tool VARCHAR(36), + activity_type VARCHAR(255) NOT NULL, + last_modified DATETIME NOT NULL, + PRIMARY KEY (sequence_id), + KEY post_jobtasknode_idx (job_task_node), + KEY post_status_idx (status) +) ENGINE=InnoDB; + +CREATE TABLE alf_audit_config +( + id BIGINT NOT NULL AUTO_INCREMENT, + config_url TEXT NOT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_audit_date +( + id BIGINT NOT NULL AUTO_INCREMENT, + date_only date NOT NULL, + day_of_year INTEGER NOT NULL, + day_of_month INTEGER NOT NULL, + day_of_week INTEGER NOT NULL, + week_of_year INTEGER NOT NULL, + week_of_month INTEGER NOT NULL, + month INTEGER NOT NULL, + quarter INTEGER NOT NULL, + half_year INTEGER NOT NULL, + full_year INTEGER NOT NULL, + PRIMARY KEY (id), + KEY idx_alf_adtd_woy (week_of_year), + KEY idx_alf_adtd_fy (full_year), + KEY idx_alf_adtd_q (quarter), + KEY idx_alf_adtd_wom (week_of_month), + KEY idx_alf_adtd_dom (day_of_month), + KEY idx_alf_adtd_doy (day_of_year), + KEY idx_alf_adtd_dow (day_of_week), + KEY idx_alf_adtd_m (month), + KEY idx_alf_adtd_hy (half_year), + KEY idx_alf_adtd_dat (date_only) +) ENGINE=InnoDB; + +CREATE TABLE alf_audit_source +( + id BIGINT NOT NULL AUTO_INCREMENT, + application VARCHAR(255) NOT NULL, + service VARCHAR(255), + method VARCHAR(255), + PRIMARY KEY (id), + KEY idx_alf_adts_met (method), + KEY idx_alf_adts_ser (service), + KEY idx_alf_adts_app (application) +) ENGINE=InnoDB; + +CREATE TABLE alf_audit_fact +( + id BIGINT NOT NULL AUTO_INCREMENT, + user_id VARCHAR(255) NOT NULL, + timestamp DATETIME NOT NULL, + transaction_id VARCHAR(56) NOT NULL, + session_id VARCHAR(56), + store_protocol VARCHAR(50), + store_id VARCHAR(100), + node_uuid VARCHAR(36), + path TEXT, + filtered BIT NOT NULL, + return_val TEXT, + arg_1 TEXT, + arg_2 TEXT, + arg_3 TEXT, + arg_4 TEXT, + arg_5 TEXT, + fail BIT NOT NULL, + serialized_url TEXT, + exception_message TEXT, + host_address TEXT, + client_address TEXT, + message_text TEXT, + audit_date_id BIGINT NOT NULL, + audit_conf_id BIGINT NOT NULL, + audit_source_id BIGINT NOT NULL, + PRIMARY KEY (id), + KEY idx_alf_adtf_ref (store_protocol, store_id, node_uuid), + KEY idx_alf_adtf_usr (user_id), + KEY fk_alf_adtf_src (audit_source_id), + KEY fk_alf_adtf_date (audit_date_id), + KEY fk_alf_adtf_conf (audit_conf_id), + KEY idx_alf_adtf_pth (path(128)), + CONSTRAINT fk_alf_adtf_conf FOREIGN KEY (audit_conf_id) REFERENCES alf_audit_config (id), + CONSTRAINT fk_alf_adtf_date FOREIGN KEY (audit_date_id) REFERENCES alf_audit_date (id), + CONSTRAINT fk_alf_adtf_src FOREIGN KEY (audit_source_id) REFERENCES alf_audit_source (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_server +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + ip_address VARCHAR(39) NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY ip_address (ip_address) +) ENGINE=InnoDB; + +CREATE TABLE alf_transaction +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + server_id BIGINT, + change_txn_id VARCHAR(56) NOT NULL, + commit_time_ms BIGINT, + PRIMARY KEY (id), + KEY idx_alf_txn_ctms (commit_time_ms), + KEY fk_alf_txn_svr (server_id), + CONSTRAINT fk_alf_txn_svr FOREIGN KEY (server_id) REFERENCES alf_server (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_store +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + protocol VARCHAR(50) NOT NULL, + identifier VARCHAR(100) NOT NULL, + root_node_id BIGINT, + PRIMARY KEY (id), + UNIQUE KEY protocol (protocol, identifier) +) ENGINE=InnoDB; + +CREATE TABLE alf_node +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + store_id BIGINT NOT NULL, + uuid VARCHAR(36) NOT NULL, + transaction_id BIGINT NOT NULL, + node_deleted bit NOT NULL, + type_qname_id BIGINT NOT NULL, + acl_id BIGINT, + audit_creator VARCHAR(255), + audit_created VARCHAR(30), + audit_modifier VARCHAR(255), + audit_modified VARCHAR(30), + audit_accessed VARCHAR(30), + PRIMARY KEY (id), + UNIQUE KEY store_id (store_id, uuid), + KEY idx_alf_node_del (node_deleted), + KEY fk_alf_node_acl (acl_id), + KEY fk_alf_node_txn (transaction_id), + KEY fk_alf_node_store (store_id), + KEY fk_alf_node_tqn (type_qname_id), + CONSTRAINT fk_alf_node_acl FOREIGN KEY (acl_id) REFERENCES alf_access_control_list (id), + CONSTRAINT fk_alf_node_store FOREIGN KEY (store_id) REFERENCES alf_store (id), + CONSTRAINT fk_alf_node_tqn FOREIGN KEY (type_qname_id) REFERENCES alf_qname (id), + CONSTRAINT fk_alf_node_txn FOREIGN KEY (transaction_id) REFERENCES alf_transaction (id) +) ENGINE=InnoDB; + +ALTER TABLE alf_store ADD INDEX fk_alf_store_root (root_node_id), ADD CONSTRAINT fk_alf_store_root FOREIGN KEY (root_node_id) REFERENCES alf_node (id); + +CREATE TABLE alf_child_assoc +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + parent_node_id BIGINT NOT NULL, + type_qname_id BIGINT NOT NULL, + child_node_name_crc BIGINT NOT NULL, + child_node_name VARCHAR(50) NOT NULL, + child_node_id BIGINT NOT NULL, + qname_ns_id BIGINT NOT NULL, + qname_localname VARCHAR(255) NOT NULL, + qname_crc BIGINT NOT NULL, + is_primary bit, + assoc_index INTEGER, + PRIMARY KEY (id), + UNIQUE KEY parent_node_id (parent_node_id, type_qname_id, child_node_name_crc, child_node_name), + KEY fk_alf_cass_pnode (parent_node_id), + KEY fk_alf_cass_cnode (child_node_id), + KEY fk_alf_cass_tqn (type_qname_id), + KEY fk_alf_cass_qnns (qname_ns_id), + KEY idx_alf_cass_qncrc (qname_crc, type_qname_id, parent_node_id), + KEY idx_alf_cass_pri (parent_node_id, is_primary, child_node_id), + CONSTRAINT fk_alf_cass_cnode FOREIGN KEY (child_node_id) REFERENCES alf_node (id), + CONSTRAINT fk_alf_cass_pnode FOREIGN KEY (parent_node_id) REFERENCES alf_node (id), + CONSTRAINT fk_alf_cass_qnns FOREIGN KEY (qname_ns_id) REFERENCES alf_namespace (id), + CONSTRAINT fk_alf_cass_tqn FOREIGN KEY (type_qname_id) REFERENCES alf_qname (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_locale +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + locale_str VARCHAR(20) NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY locale_str (locale_str) +) ENGINE=InnoDB; + +CREATE TABLE alf_attributes +( + id BIGINT NOT NULL AUTO_INCREMENT, + type VARCHAR(1) NOT NULL, + version BIGINT NOT NULL, + acl_id BIGINT, + bool_value BIT, + byte_value TINYINT, + short_value SMALLINT, + int_value INTEGER, + long_value BIGINT, + float_value FLOAT, + double_value DOUBLE PRECISION, + string_value TEXT, + serializable_value BLOB, + PRIMARY KEY (id), + KEY fk_alf_attr_acl (acl_id), + CONSTRAINT fk_alf_attr_acl FOREIGN KEY (acl_id) REFERENCES alf_access_control_list (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_global_attributes +( + name VARCHAR(160) NOT NULL, + attribute BIGINT, + PRIMARY KEY (name), + UNIQUE KEY attribute (attribute), + KEY fk_alf_gatt_att (attribute), + CONSTRAINT fk_alf_gatt_att FOREIGN KEY (attribute) REFERENCES alf_attributes (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_list_attribute_entries +( + list_id BIGINT NOT NULL, + mindex INTEGER NOT NULL, + attribute_id BIGINT, + PRIMARY KEY (list_id, mindex), + KEY fk_alf_lent_att (attribute_id), + KEY fk_alf_lent_latt (list_id), + CONSTRAINT fk_alf_lent_att FOREIGN KEY (attribute_id) REFERENCES alf_attributes (id), + CONSTRAINT fk_alf_lent_latt FOREIGN KEY (list_id) REFERENCES alf_attributes (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_map_attribute_entries +( + map_id BIGINT NOT NULL, + mkey VARCHAR(160) NOT NULL, + attribute_id BIGINT, + PRIMARY KEY (map_id, mkey), + KEY fk_alf_matt_matt (map_id), + KEY fk_alf_matt_att (attribute_id), + CONSTRAINT fk_alf_matt_att FOREIGN KEY (attribute_id) REFERENCES alf_attributes (id), + CONSTRAINT fk_alf_matt_matt FOREIGN KEY (map_id) REFERENCES alf_attributes (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_node_aspects +( + node_id BIGINT NOT NULL, + qname_id BIGINT NOT NULL, + PRIMARY KEY (node_id, qname_id), + KEY fk_alf_nasp_n (node_id), + KEY fk_alf_nasp_qn (qname_id), + CONSTRAINT fk_alf_nasp_n FOREIGN KEY (node_id) REFERENCES alf_node (id), + CONSTRAINT fk_alf_nasp_qn FOREIGN KEY (qname_id) REFERENCES alf_qname (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_node_assoc +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + source_node_id BIGINT NOT NULL, + target_node_id BIGINT NOT NULL, + type_qname_id BIGINT NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY source_node_id (source_node_id, target_node_id, type_qname_id), + KEY k_alf_nass_snode (source_node_id), + KEY fk_alf_nass_tnode (target_node_id), + KEY fk_alf_nass_tqn (type_qname_id), + CONSTRAINT fk_alf_nass_snode FOREIGN KEY (source_node_id) REFERENCES alf_node (id), + CONSTRAINT fk_alf_nass_tnode FOREIGN KEY (target_node_id) REFERENCES alf_node (id), + CONSTRAINT fk_alf_nass_tqn FOREIGN KEY (type_qname_id) REFERENCES alf_qname (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_node_properties +( + node_id BIGINT NOT NULL, + actual_type_n INTEGER NOT NULL, + persisted_type_n INTEGER NOT NULL, + boolean_value bit, + long_value BIGINT, + float_value float, + double_value double precision, + string_value text, + serializable_value blob, + qname_id BIGINT NOT NULL, + list_index INTEGER NOT NULL, + locale_id BIGINT NOT NULL, + PRIMARY KEY (node_id, qname_id, list_index, locale_id), + KEY fk_alf_nprop_n (node_id), + KEY fk_alf_nprop_qn (qname_id), + KEY fk_alf_nprop_loc (locale_id), + CONSTRAINT fk_alf_nprop_loc FOREIGN KEY (locale_id) REFERENCES alf_locale (id), + CONSTRAINT fk_alf_nprop_n FOREIGN KEY (node_id) REFERENCES alf_node (id), + CONSTRAINT fk_alf_nprop_qn FOREIGN KEY (qname_id) REFERENCES alf_qname (id) +) ENGINE=InnoDB; + +CREATE TABLE alf_usage_delta +( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + node_id BIGINT NOT NULL, + delta_size BIGINT NOT NULL, + PRIMARY KEY (id), + KEY fk_alf_usaged_n (node_id), + CONSTRAINT fk_alf_usaged_n FOREIGN KEY (node_id) REFERENCES alf_node (id) +) ENGINE=InnoDB; diff --git a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-AuditTables.sql b/config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-AuditTables.sql similarity index 100% rename from config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-AuditTables.sql rename to config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-AuditTables.sql diff --git a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-AvmTables.sql b/config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-AvmTables.sql similarity index 91% rename from config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-AvmTables.sql rename to config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-AvmTables.sql index cbb02f0ff2..8e2cc746b4 100644 --- a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-AvmTables.sql +++ b/config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-AvmTables.sql @@ -75,6 +75,8 @@ primary key (id) ); + create sequence avm_nodes_seq start with 1 increment by 1; + create table avm_store_properties ( id INT8 not null, avm_store_id INT8, @@ -91,6 +93,8 @@ primary key (id) ); + create sequence avm_store_properties_seq start with 1 increment by 1; + create table avm_stores ( id INT8 not null, vers INT8 not null, @@ -101,6 +105,8 @@ primary key (id) ); + create sequence avm_stores_seq start with 1 increment by 1; + create table avm_version_layered_node_entry ( version_root_id INT8 not null, md5sum varchar(32) not null, @@ -121,6 +127,8 @@ unique (version_id, avm_store_id) ); + create sequence avm_version_roots_seq start with 1 increment by 1; + alter table avm_aspects add constraint fk_avm_nasp_n foreign key (node_id) @@ -195,6 +203,12 @@ references avm_nodes (id); create index fk_avm_s_root on avm_stores(current_root_id); + alter table avm_stores + add constraint fk_avm_s_acl + foreign key (acl_id) + references alf_access_control_list (id); + create index fk_avm_s_acl on avm_stores(acl_id); + alter table avm_version_layered_node_entry add constraint fk_avm_vlne_vr foreign key (version_root_id) diff --git a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-ContentTables.sql b/config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-ContentTables.sql similarity index 100% rename from config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-ContentTables.sql rename to config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-ContentTables.sql diff --git a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-LockTables.sql b/config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-LockTables.sql similarity index 100% rename from config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-LockTables.sql rename to config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-LockTables.sql diff --git a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-PropertyValueTables.sql b/config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-PropertyValueTables.sql similarity index 94% rename from config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-PropertyValueTables.sql rename to config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-PropertyValueTables.sql index 45193dc455..357a968f64 100644 --- a/config/alfresco/dbscripts/create/3.2/org.hibernate.dialect.PostgreSQLDialect/AlfrescoPostCreate-3.2-PropertyValueTables.sql +++ b/config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-PropertyValueTables.sql @@ -109,10 +109,12 @@ CREATE TABLE alf_prop_unique_ctx version INT4 NOT NULL, value1_prop_id INT8 NOT NULL, value2_prop_id INT8 NOT NULL, - value3_prop_id INT8 NOT NULL, + value3_prop_id INT8 NOT NULL, + prop1_id INT8 NOT NULL, CONSTRAINT fk_alf_propuctx_v1 FOREIGN KEY (value1_prop_id) REFERENCES alf_prop_value (id) ON DELETE CASCADE, CONSTRAINT fk_alf_propuctx_v2 FOREIGN KEY (value2_prop_id) REFERENCES alf_prop_value (id) ON DELETE CASCADE, CONSTRAINT fk_alf_propuctx_v3 FOREIGN KEY (value3_prop_id) REFERENCES alf_prop_value (id) ON DELETE CASCADE, + CONSTRAINT fk_alf_propuctx_p1 FOREIGN KEY (prop1_id) REFERENCES alf_prop_root (id), PRIMARY KEY (id) ); CREATE UNIQUE INDEX idx_alf_propuctx ON alf_prop_unique_ctx(value1_prop_id, value2_prop_id, value3_prop_id); diff --git a/config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-RepoTables.sql b/config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-RepoTables.sql new file mode 100644 index 0000000000..c53ab7c7cd --- /dev/null +++ b/config/alfresco/dbscripts/create/org.hibernate.dialect.PostgreSQLDialect/AlfrescoCreate-RepoTables.sql @@ -0,0 +1,530 @@ +-- +-- Title: Core Repository Tables +-- Database: PostgreSQL +-- Since: V3.3 Schema 4000 +-- Author: unknown +-- +-- Please contact support@alfresco.com if you need assistance with the upgrade. +-- + +CREATE TABLE alf_applied_patch +( + id VARCHAR(64) NOT NULL, + description VARCHAR(1024), + fixes_from_schema INT4, + fixes_to_schema INT4, + applied_to_schema INT4, + target_schema INT4, + applied_on_date TIMESTAMP, + applied_to_server VARCHAR(64), + was_executed BOOL, + succeeded BOOL, + report VARCHAR(1024), + PRIMARY KEY (id) +); + +CREATE TABLE alf_namespace +( + id INT8 NOT NULL, + version INT8 NOT NULL, + uri VARCHAR(100) NOT NULL, + PRIMARY KEY (id) +); + +CREATE UNIQUE INDEX uri ON alf_namespace (uri); +CREATE SEQUENCE alf_namespace_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_qname +( + id INT8 NOT NULL, + version INT8 NOT NULL, + ns_id INT8 NOT NULL, + local_name VARCHAR(200) NOT NULL, + CONSTRAINT fk_alf_qname_ns FOREIGN KEY (ns_id) REFERENCES alf_namespace (id), + PRIMARY KEY (id) +); +CREATE UNIQUE INDEX ns_id ON alf_qname (ns_id, local_name); +CREATE INDEX fk_alf_qname_ns ON alf_qname (ns_id); +CREATE SEQUENCE alf_qname_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_permission +( + id INT8 NOT NULL, + version INT8 NOT NULL, + type_qname_id INT8 NOT NULL, + name VARCHAR(100) NOT NULL, + PRIMARY KEY (id), + CONSTRAINT fk_alf_perm_tqn FOREIGN KEY (type_qname_id) REFERENCES alf_qname (id) +); +CREATE UNIQUE INDEX type_qname_id ON alf_permission (type_qname_id, name); +CREATE INDEX fk_alf_perm_tqn ON alf_permission (type_qname_id); +CREATE SEQUENCE alf_permission_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_ace_context +( + id INT8 NOT NULL, + version INT8 NOT NULL, + class_context VARCHAR(1024), + property_context VARCHAR(1024), + kvp_context VARCHAR(1024), + PRIMARY KEY (id) +); +CREATE SEQUENCE alf_ace_context_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_authority +( + id INT8 NOT NULL, + version INT8 NOT NULL, + authority VARCHAR(100), + crc INT8, + PRIMARY KEY (id) +); +CREATE UNIQUE INDEX authority ON alf_authority (authority, crc); +CREATE INDEX idx_alf_auth_aut ON alf_authority (authority); +CREATE SEQUENCE alf_authority_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_access_control_entry +( + id INT8 NOT NULL, + version INT8 NOT NULL, + permission_id INT8 NOT NULL, + authority_id INT8 NOT NULL, + allowed BOOL NOT NULL, + applies INT4 NOT NULL, + context_id INT8, + PRIMARY KEY (id), + CONSTRAINT fk_alf_ace_auth FOREIGN KEY (authority_id) REFERENCES alf_authority (id), + CONSTRAINT fk_alf_ace_ctx FOREIGN KEY (context_id) REFERENCES alf_ace_context (id), + CONSTRAINT fk_alf_ace_perm FOREIGN KEY (permission_id) REFERENCES alf_permission (id) +); +CREATE UNIQUE INDEX permission_id ON alf_access_control_entry (permission_id, authority_id, allowed, applies, context_id); +CREATE INDEX fk_alf_ace_ctx ON alf_access_control_entry (context_id); +CREATE INDEX fk_alf_ace_perm ON alf_access_control_entry (permission_id); +CREATE INDEX fk_alf_ace_auth ON alf_access_control_entry (authority_id); +CREATE SEQUENCE alf_access_control_entry_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_acl_change_set +( + id INT8 NOT NULL, + version INT8 NOT NULL, + PRIMARY KEY (id) +); +CREATE SEQUENCE alf_acl_change_set_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_access_control_list +( + id INT8 NOT NULL, + version INT8 NOT NULL, + acl_id VARCHAR(36) NOT NULL, + latest BOOL NOT NULL, + acl_version INT8 NOT NULL, + inherits BOOL NOT NULL, + inherits_from INT8, + type INT4 NOT NULL, + inherited_acl INT8, + is_versioned BOOL NOT NULL, + requires_version BOOL NOT NULL, + acl_change_set INT8, + PRIMARY KEY (id), + CONSTRAINT fk_alf_acl_acs FOREIGN KEY (acl_change_set) REFERENCES alf_acl_change_set (id) +); +CREATE UNIQUE INDEX acl_id ON alf_access_control_list (acl_id, latest, acl_version); +CREATE INDEX idx_alf_acl_inh ON alf_access_control_list (inherits, inherits_from); +CREATE INDEX fk_alf_acl_acs ON alf_access_control_list (acl_change_set); +CREATE SEQUENCE alf_access_control_list_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_acl_member +( + id INT8 NOT NULL, + version INT8 NOT NULL, + acl_id INT8 NOT NULL, + ace_id INT8 NOT NULL, + pos INT4 NOT NULL, + PRIMARY KEY (id), + CONSTRAINT fk_alf_aclm_ace FOREIGN KEY (ace_id) REFERENCES alf_access_control_entry (id), + CONSTRAINT fk_alf_aclm_acl FOREIGN KEY (acl_id) REFERENCES alf_access_control_list (id) +); +CREATE UNIQUE INDEX aclm_acl_id ON alf_acl_member (acl_id, ace_id, pos); +CREATE INDEX fk_alf_aclm_acl ON alf_acl_member (acl_id); +CREATE INDEX fk_alf_aclm_ace ON alf_acl_member (ace_id); +CREATE SEQUENCE alf_acl_member_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_authority_alias +( + id INT8 NOT NULL, + version INT8 NOT NULL, + auth_id INT8 NOT NULL, + alias_id INT8 NOT NULL, + PRIMARY KEY (id), + CONSTRAINT fk_alf_autha_aut FOREIGN KEY (auth_id) REFERENCES alf_authority (id), + CONSTRAINT fk_alf_autha_ali FOREIGN KEY (alias_id) REFERENCES alf_authority (id) +); +CREATE UNIQUE INDEX auth_id ON alf_authority_alias (auth_id, alias_id); +CREATE INDEX fk_alf_autha_ali ON alf_authority_alias (alias_id); +CREATE INDEX fk_alf_autha_aut ON alf_authority_alias (auth_id); +CREATE SEQUENCE alf_authority_alias_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_activity_feed +( + id INT8 NOT NULL, + post_id INT8, + post_date TIMESTAMP NOT NULL, + activity_summary VARCHAR(1024), + feed_user_id VARCHAR(255), + activity_type VARCHAR(255) NOT NULL, + activity_format VARCHAR(10), + site_network VARCHAR(255), + app_tool VARCHAR(36), + post_user_id VARCHAR(255) NOT NULL, + feed_date TIMESTAMP NOT NULL, + PRIMARY KEY (id) +); +CREATE INDEX feed_postdate_idx ON alf_activity_feed (post_date); +CREATE INDEX feed_postuserid_idx ON alf_activity_feed (post_user_id); +CREATE INDEX feed_feeduserid_idx ON alf_activity_feed (feed_user_id); +CREATE INDEX feed_sitenetwork_idx ON alf_activity_feed (site_network); +CREATE INDEX feed_activityformat_idx ON alf_activity_feed (activity_format); +CREATE SEQUENCE alf_activity_feed_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_activity_feed_control +( + id INT8 NOT NULL, + feed_user_id VARCHAR(255) NOT NULL, + site_network VARCHAR(255), + app_tool VARCHAR(36), + last_modified TIMESTAMP NOT NULL, + PRIMARY KEY (id) +); +CREATE INDEX feedctrl_feeduserid_idx ON alf_activity_feed_control (feed_user_id); +CREATE SEQUENCE alf_activity_feed_control_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_activity_post +( + sequence_id INT8 NOT NULL, + post_date TIMESTAMP NOT NULL, + status VARCHAR(10) NOT NULL, + activity_data VARCHAR(1024) NOT NULL, + post_user_id VARCHAR(255) NOT NULL, + job_task_node INT4 NOT NULL, + site_network VARCHAR(255), + app_tool VARCHAR(36), + activity_type VARCHAR(255) NOT NULL, + last_modified TIMESTAMP NOT NULL, + PRIMARY KEY (sequence_id) +); +CREATE INDEX post_jobtasknode_idx ON alf_activity_post (job_task_node); +CREATE INDEX post_status_idx ON alf_activity_post (status); +CREATE SEQUENCE alf_activity_post_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_audit_config +( + id INT8 NOT NULL, + config_url VARCHAR(1024) NOT NULL, + PRIMARY KEY (id) +); +CREATE SEQUENCE alf_audit_config_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_audit_date +( + id INT8 NOT NULL, + date_only DATE NOT NULL, + day_of_year INT4 NOT NULL, + day_of_month INT4 NOT NULL, + day_of_week INT4 NOT NULL, + week_of_year INT4 NOT NULL, + week_of_month INT4 NOT NULL, + month INT4 NOT NULL, + quarter INT4 NOT NULL, + half_year INT4 NOT NULL, + full_year INT4 NOT NULL, + PRIMARY KEY (id) +); +CREATE INDEX idx_alf_adtd_woy ON alf_audit_date (week_of_year); +CREATE INDEX idx_alf_adtd_fy ON alf_audit_date (full_year); +CREATE INDEX idx_alf_adtd_q ON alf_audit_date (quarter); +CREATE INDEX idx_alf_adtd_wom ON alf_audit_date (week_of_month); +CREATE INDEX idx_alf_adtd_dom ON alf_audit_date (day_of_month); +CREATE INDEX idx_alf_adtd_doy ON alf_audit_date (day_of_year); +CREATE INDEX idx_alf_adtd_dow ON alf_audit_date (day_of_week); +CREATE INDEX idx_alf_adtd_m ON alf_audit_date (month); +CREATE INDEX idx_alf_adtd_hy ON alf_audit_date (half_year); +CREATE INDEX idx_alf_adtd_dat ON alf_audit_date (date_only); +CREATE SEQUENCE alf_audit_date_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_audit_source +( + id INT8 NOT NULL, + application VARCHAR(255) NOT NULL, + service VARCHAR(255), + method VARCHAR(255), + PRIMARY KEY (id) +); +CREATE INDEX idx_alf_adts_met ON alf_audit_source (method); +CREATE INDEX idx_alf_adts_ser ON alf_audit_source (service); +CREATE INDEX idx_alf_adts_app ON alf_audit_source (application); +CREATE SEQUENCE alf_audit_source_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_audit_fact +( + id INT8 NOT NULL, + user_id VARCHAR(255) NOT NULL, + timestamp TIMESTAMP NOT NULL, + transaction_id VARCHAR(56) NOT NULL, + session_id VARCHAR(56), + store_protocol VARCHAR(50), + store_id VARCHAR(100), + node_uuid VARCHAR(36), + path VARCHAR(1024), + filtered BOOL NOT NULL, + return_val VARCHAR(1024), + arg_1 VARCHAR(1024), + arg_2 VARCHAR(1024), + arg_3 VARCHAR(1024), + arg_4 VARCHAR(1024), + arg_5 VARCHAR(1024), + fail BOOL NOT NULL, + serialized_url VARCHAR(1024), + exception_message VARCHAR(1024), + host_address VARCHAR(1024), + client_address VARCHAR(1024), + message_text VARCHAR(1024), + audit_date_id INT8 NOT NULL, + audit_conf_id INT8 NOT NULL, + audit_source_id INT8 NOT NULL, + PRIMARY KEY (id), + CONSTRAINT fk_alf_adtf_conf FOREIGN KEY (audit_conf_id) REFERENCES alf_audit_config (id), + CONSTRAINT fk_alf_adtf_date FOREIGN KEY (audit_date_id) REFERENCES alf_audit_date (id), + CONSTRAINT fk_alf_adtf_src FOREIGN KEY (audit_source_id) REFERENCES alf_audit_source (id) +); +CREATE INDEX idx_alf_adtf_ref ON alf_audit_fact (store_protocol, store_id, node_uuid); +CREATE INDEX idx_alf_adtf_usr ON alf_audit_fact (user_id); +CREATE INDEX fk_alf_adtf_src ON alf_audit_fact (audit_source_id); +CREATE INDEX fk_alf_adtf_date ON alf_audit_fact (audit_date_id); +CREATE INDEX fk_alf_adtf_conf ON alf_audit_fact (audit_conf_id); +CREATE INDEX idx_alf_adtf_pth ON alf_audit_fact (path); +CREATE SEQUENCE alf_audit_fact_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_server +( + id INT8 NOT NULL, + version INT8 NOT NULL, + ip_address VARCHAR(39) NOT NULL, + PRIMARY KEY (id) +); +CREATE UNIQUE INDEX ip_address ON alf_server (ip_address); +CREATE SEQUENCE alf_server_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_transaction +( + id INT8 NOT NULL, + version INT8 NOT NULL, + server_id INT8, + change_txn_id VARCHAR(56) NOT NULL, + commit_time_ms INT8, + PRIMARY KEY (id), + CONSTRAINT fk_alf_txn_svr FOREIGN KEY (server_id) REFERENCES alf_server (id) +); +CREATE INDEX idx_alf_txn_ctms ON alf_transaction (commit_time_ms); +CREATE INDEX fk_alf_txn_svr ON alf_transaction (server_id); +CREATE SEQUENCE alf_transaction_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_store +( + id INT8 NOT NULL, + version INT8 NOT NULL, + protocol VARCHAR(50) NOT NULL, + identifier VARCHAR(100) NOT NULL, + root_node_id INT8, + PRIMARY KEY (id) +); +CREATE UNIQUE INDEX protocol ON alf_store (protocol, identifier); +CREATE SEQUENCE alf_store_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_node +( + id INT8 NOT NULL, + version INT8 NOT NULL, + store_id INT8 NOT NULL, + uuid VARCHAR(36) NOT NULL, + transaction_id INT8 NOT NULL, + node_deleted BOOL NOT NULL, + type_qname_id INT8 NOT NULL, + acl_id INT8, + audit_creator VARCHAR(255), + audit_created VARCHAR(30), + audit_modifier VARCHAR(255), + audit_modified VARCHAR(30), + audit_accessed VARCHAR(30), + PRIMARY KEY (id), + CONSTRAINT fk_alf_node_acl FOREIGN KEY (acl_id) REFERENCES alf_access_control_list (id), + CONSTRAINT fk_alf_node_store FOREIGN KEY (store_id) REFERENCES alf_store (id), + CONSTRAINT fk_alf_node_tqn FOREIGN KEY (type_qname_id) REFERENCES alf_qname (id), + CONSTRAINT fk_alf_node_txn FOREIGN KEY (transaction_id) REFERENCES alf_transaction (id) +); +CREATE UNIQUE INDEX store_id ON alf_node (store_id, uuid); +CREATE INDEX idx_alf_node_del ON alf_node (node_deleted); +CREATE INDEX fk_alf_node_acl ON alf_node (acl_id); +CREATE INDEX fk_alf_node_txn ON alf_node (transaction_id); +CREATE INDEX fk_alf_node_store ON alf_node (store_id); +CREATE INDEX fk_alf_node_tqn ON alf_node (type_qname_id); +CREATE SEQUENCE alf_node_seq START WITH 1 INCREMENT BY 1; + +CREATE INDEX fk_alf_store_root ON alf_store (root_node_id); +ALTER TABLE alf_store ADD CONSTRAINT fk_alf_store_root FOREIGN KEY (root_node_id) REFERENCES alf_node (id); + +CREATE TABLE alf_child_assoc +( + id INT8 NOT NULL, + version INT8 NOT NULL, + parent_node_id INT8 NOT NULL, + type_qname_id INT8 NOT NULL, + child_node_name_crc INT8 NOT NULL, + child_node_name VARCHAR(50) NOT NULL, + child_node_id INT8 NOT NULL, + qname_ns_id INT8 NOT NULL, + qname_localname VARCHAR(255) NOT NULL, + qname_crc INT8 NOT NULL, + is_primary BOOL, + assoc_index INT4, + PRIMARY KEY (id), + CONSTRAINT fk_alf_cass_cnode FOREIGN KEY (child_node_id) REFERENCES alf_node (id), + CONSTRAINT fk_alf_cass_pnode FOREIGN KEY (parent_node_id) REFERENCES alf_node (id), + CONSTRAINT fk_alf_cass_qnns FOREIGN KEY (qname_ns_id) REFERENCES alf_namespace (id), + CONSTRAINT fk_alf_cass_tqn FOREIGN KEY (type_qname_id) REFERENCES alf_qname (id) +); +CREATE UNIQUE INDEX parent_node_id ON alf_child_assoc (parent_node_id, type_qname_id, child_node_name_crc, child_node_name); +CREATE INDEX fk_alf_cass_pnode ON alf_child_assoc (parent_node_id); +CREATE INDEX fk_alf_cass_cnode ON alf_child_assoc (child_node_id); +CREATE INDEX fk_alf_cass_tqn ON alf_child_assoc (type_qname_id); +CREATE INDEX fk_alf_cass_qnns ON alf_child_assoc (qname_ns_id); +CREATE INDEX idx_alf_cass_qncrc ON alf_child_assoc (qname_crc, type_qname_id, parent_node_id); +CREATE SEQUENCE alf_child_assoc_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_locale +( + id INT8 NOT NULL, + version INT8 NOT NULL, + locale_str VARCHAR(20) NOT NULL, + PRIMARY KEY (id) +); +CREATE UNIQUE INDEX locale_str ON alf_locale (locale_str); +CREATE SEQUENCE alf_locale_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_attributes +( + id INT8 NOT NULL, + type VARCHAR(1) NOT NULL, + version INT8 NOT NULL, + acl_id INT8, + bool_value BOOL, + byte_value INT2, + short_value INT4, + int_value INT4, + long_value INT8, + float_value FLOAT4, + double_value FLOAT8, + string_value VARCHAR(1024), + serializable_value BYTEA, + PRIMARY KEY (id), + CONSTRAINT fk_alf_attr_acl FOREIGN KEY (acl_id) REFERENCES alf_access_control_list (id) +); +CREATE INDEX fk_alf_attr_acl ON alf_attributes (acl_id); +CREATE SEQUENCE alf_attributes_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_global_attributes +( + name VARCHAR(160) NOT NULL, + attribute INT8, + PRIMARY KEY (name), + CONSTRAINT fk_alf_gatt_att FOREIGN KEY (attribute) REFERENCES alf_attributes (id) +); +CREATE UNIQUE INDEX attribute ON alf_global_attributes (attribute); +CREATE INDEX fk_alf_gatt_att ON alf_global_attributes (attribute); + +CREATE TABLE alf_list_attribute_entries +( + list_id INT8 NOT NULL, + mindex INT4 NOT NULL, + attribute_id INT8, + PRIMARY KEY (list_id, mindex), + CONSTRAINT fk_alf_lent_att FOREIGN KEY (attribute_id) REFERENCES alf_attributes (id), + CONSTRAINT fk_alf_lent_latt FOREIGN KEY (list_id) REFERENCES alf_attributes (id) +); +CREATE INDEX fk_alf_lent_att ON alf_list_attribute_entries (attribute_id); +CREATE INDEX fk_alf_lent_latt ON alf_list_attribute_entries (list_id); + +CREATE TABLE alf_map_attribute_entries +( + map_id INT8 NOT NULL, + mkey VARCHAR(160) NOT NULL, + attribute_id INT8, + PRIMARY KEY (map_id, mkey), + CONSTRAINT fk_alf_matt_att FOREIGN KEY (attribute_id) REFERENCES alf_attributes (id), + CONSTRAINT fk_alf_matt_matt FOREIGN KEY (map_id) REFERENCES alf_attributes (id) +); +CREATE INDEX fk_alf_matt_matt ON alf_map_attribute_entries (map_id); +CREATE INDEX fk_alf_matt_att ON alf_map_attribute_entries (attribute_id); + +CREATE TABLE alf_node_aspects +( + node_id INT8 NOT NULL, + qname_id INT8 NOT NULL, + PRIMARY KEY (node_id, qname_id), + CONSTRAINT fk_alf_nasp_n FOREIGN KEY (node_id) REFERENCES alf_node (id), + CONSTRAINT fk_alf_nasp_qn FOREIGN KEY (qname_id) REFERENCES alf_qname (id) +); +CREATE INDEX fk_alf_nasp_n ON alf_node_aspects (node_id); +CREATE INDEX fk_alf_nasp_qn ON alf_node_aspects (qname_id); + +CREATE TABLE alf_node_assoc +( + id INT8 NOT NULL, + version INT8 NOT NULL, + source_node_id INT8 NOT NULL, + target_node_id INT8 NOT NULL, + type_qname_id INT8 NOT NULL, + PRIMARY KEY (id), + CONSTRAINT fk_alf_nass_snode FOREIGN KEY (source_node_id) REFERENCES alf_node (id), + CONSTRAINT fk_alf_nass_tnode FOREIGN KEY (target_node_id) REFERENCES alf_node (id), + CONSTRAINT fk_alf_nass_tqn FOREIGN KEY (type_qname_id) REFERENCES alf_qname (id) +); +CREATE UNIQUE INDEX source_node_id ON alf_node_assoc (source_node_id, target_node_id, type_qname_id); +CREATE INDEX k_alf_nass_snode ON alf_node_assoc (source_node_id); +CREATE INDEX fk_alf_nass_tnode ON alf_node_assoc (target_node_id); +CREATE INDEX fk_alf_nass_tqn ON alf_node_assoc (type_qname_id); +CREATE SEQUENCE alf_node_assoc_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE alf_node_properties +( + node_id INT8 NOT NULL, + actual_type_n INT4 NOT NULL, + persisted_type_n INT4 NOT NULL, + boolean_value BOOL, + long_value INT8, + float_value FLOAT4, + double_value FLOAT8, + string_value VARCHAR(1024), + serializable_value BYTEA, + qname_id INT8 NOT NULL, + list_index INT4 NOT NULL, + locale_id INT8 NOT NULL, + PRIMARY KEY (node_id, qname_id, list_index, locale_id), + CONSTRAINT fk_alf_nprop_loc FOREIGN KEY (locale_id) REFERENCES alf_locale (id), + CONSTRAINT fk_alf_nprop_n FOREIGN KEY (node_id) REFERENCES alf_node (id), + CONSTRAINT fk_alf_nprop_qn FOREIGN KEY (qname_id) REFERENCES alf_qname (id) +); +CREATE INDEX fk_alf_nprop_n ON alf_node_properties (node_id); +CREATE INDEX fk_alf_nprop_qn ON alf_node_properties (qname_id); +CREATE INDEX fk_alf_nprop_loc ON alf_node_properties (locale_id); + +CREATE TABLE alf_usage_delta +( + id INT8 NOT NULL, + version INT8 NOT NULL, + node_id INT8 NOT NULL, + delta_size INT8 NOT NULL, + PRIMARY KEY (id), + CONSTRAINT fk_alf_usaged_n FOREIGN KEY (node_id) REFERENCES alf_node (id) +); +CREATE INDEX fk_alf_usaged_n ON alf_usage_delta (node_id); +CREATE SEQUENCE alf_usage_delta_seq START WITH 1 INCREMENT BY 1; diff --git a/config/alfresco/dbscripts/upgrade/1.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaMigrate-1.3.sql b/config/alfresco/dbscripts/upgrade/1.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaMigrate-1.3.sql deleted file mode 100644 index 7d436ee983..0000000000 --- a/config/alfresco/dbscripts/upgrade/1.3/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaMigrate-1.3.sql +++ /dev/null @@ -1,653 +0,0 @@ --- ------------------------------------------------------ --- Alfresco Schema conversion V1.2.1 to V1.3 --- --- Author: Derek Hulley --- ------------------------------------------------------ - --- --- Create temporary 1.3 schema --- - -CREATE TABLE `T_access_control_entry` ( - `id` bigint(20) NOT NULL auto_increment, - `protocol` varchar(50) default NULL, - `identifier` varchar(100) default NULL, - `uuid` varchar(36) default NULL, - `typeUri` varchar(100) default NULL, - `typeName` varchar(100) default NULL, - `name` varchar(100) default NULL, - `recipient` varchar(100) default NULL, - `acl_id` bigint(20), - `permission_id` bigint(20), - `authority_id` varchar(100), - `allowed` bit(1) NOT NULL, - PRIMARY KEY (`id`) -); -ALTER TABLE `T_access_control_entry` ADD INDEX `IDX_REF`(`protocol`, `identifier`, `uuid`); - -CREATE TABLE `T_access_control_list` ( - `id` bigint(20) NOT NULL auto_increment, - `protocol` varchar(50) NOT NULL, - `identifier` varchar(100) NOT NULL, - `uuid` varchar(36) NOT NULL, - `inherits` bit(1) NOT NULL, - PRIMARY KEY (`id`) -); -ALTER TABLE `T_access_control_list` ADD INDEX `IDX_REF`(`protocol`, `identifier`, `uuid`); - -CREATE TABLE `T_applied_patch` ( - `id` varchar(32) NOT NULL, - `description` text, - `fixes_from_schema` int(11) default NULL, - `fixes_to_schema` int(11) default NULL, - `applied_to_schema` int(11) default NULL, - `target_schema` int(11) default NULL, - `applied_on_date` datetime default NULL, - `applied_to_server` varchar(64) default NULL, - `was_executed` bit(1) default NULL, - `succeeded` bit(1) default NULL, - `report` text -); - -CREATE TABLE `T_auth_ext_keys` ( - `id` varchar(100) NOT NULL, - `externalKey` varchar(100) NOT NULL -); - -CREATE TABLE `T_authority` ( - `recipient` varchar(100) NOT NULL -); - -CREATE TABLE `T_child_assoc` ( - `id` bigint(20) NOT NULL auto_increment, - `parent_node_id` bigint(20) default NULL, - `parent_protocol` varchar(50) default NULL, - `parent_identifier` varchar(100) default NULL, - `parent_uuid` varchar(36) default NULL, - `child_node_id` bigint(20) default NULL, - `child_protocol` varchar(50) default NULL, - `child_identifier` varchar(100) default NULL, - `child_uuid` varchar(36) default NULL, - `type_qname` varchar(255) NOT NULL, - `qname` varchar(255) NOT NULL, - `is_primary` bit(1) default NULL, - `assoc_index` int(11) default NULL, - PRIMARY KEY (`id`) -); -ALTER TABLE `T_child_assoc` ADD INDEX `IDX_REF_PARENT`(`parent_protocol`, `parent_identifier`, `parent_uuid`); -ALTER TABLE `T_child_assoc` ADD INDEX `IDX_REF_CHILD`(`child_protocol`, `child_identifier`, `child_uuid`); - -CREATE TABLE `T_node` ( - `id` bigint(20) NOT NULL auto_increment, - `protocol` varchar(50) NOT NULL, - `identifier` varchar(100) NOT NULL, - `uuid` varchar(36) NOT NULL, - `acl_id` bigint(20) default NULL, - `type_qname` varchar(255) NOT NULL, - PRIMARY KEY (`id`) -); -ALTER TABLE `T_node` ADD INDEX `IDX_REF`(`protocol`, `identifier`, `uuid`); - -CREATE TABLE `T_node_aspects` ( - `protocol` varchar(50) NOT NULL, - `identifier` varchar(100) NOT NULL, - `uuid` varchar(36) NOT NULL, - `node_id` bigint(20), - `qname` varchar(200) default NULL -); -ALTER TABLE `T_node_aspects` ADD INDEX `IDX_REF`(`protocol`, `identifier`, `uuid`); - -CREATE TABLE `T_node_assoc` ( - `id` bigint(20) NOT NULL auto_increment, - `source_node_id` bigint(20) default NULL, - `source_protocol` varchar(50) default NULL, - `source_identifier` varchar(100) default NULL, - `source_uuid` varchar(36) default NULL, - `target_node_id` bigint(20) default NULL, - `target_protocol` varchar(50) default NULL, - `target_identifier` varchar(100) default NULL, - `target_uuid` varchar(36) default NULL, - `type_qname` varchar(255) NOT NULL, - PRIMARY KEY (`id`) -); -ALTER TABLE `T_node_assoc` ADD INDEX `IDX_REF_SOURCE`(`source_protocol`, `source_identifier`, `source_uuid`); -ALTER TABLE `T_node_assoc` ADD INDEX `IDX_REF_TARGET`(`target_protocol`, `target_identifier`, `target_uuid`); - -CREATE TABLE `T_node_properties` ( - `protocol` varchar(50) NOT NULL, - `identifier` varchar(100) NOT NULL, - `uuid` varchar(36) NOT NULL, - `node_id` bigint(20), - `actual_type` varchar(15) NOT NULL, - `multi_valued` bit(1) NOT NULL, - `persisted_type` varchar(15) NOT NULL, - `boolean_value` bit(1) default NULL, - `long_value` bigint(20) default NULL, - `float_value` float default NULL, - `double_value` double default NULL, - `string_value` text, - `serializable_value` blob, - `qname` varchar(200) NOT NULL -); -ALTER TABLE `t_node_properties` ADD INDEX `IDX_REF`(`protocol`, `identifier`, `uuid`); - -CREATE TABLE `T_node_status` ( - `protocol` varchar(50) NOT NULL, - `identifier` varchar(100) NOT NULL, - `guid` varchar(36) NOT NULL, - `node_id` bigint(20) default NULL, - `change_txn_id` varchar(56) NOT NULL, - `deleted` bit(1) NOT NULL -); -ALTER TABLE `t_node_status` ADD INDEX `IDX_REF`(`protocol`, `identifier`, `guid`); - -CREATE TABLE `T_permission` ( - `id` bigint(20) NOT NULL auto_increment, - `type_qname` varchar(200) NOT NULL, - `name` varchar(100) NOT NULL, - PRIMARY KEY (`id`) -); - -CREATE TABLE `T_store` ( - `protocol` varchar(50) NOT NULL, - `identifier` varchar(100) NOT NULL, - `root_node_id` bigint(20) default NULL -); -ALTER TABLE `t_store` ADD INDEX `IDX_STORE_REF`(`protocol`, `identifier`); - -CREATE TABLE `T_version_count` ( - `protocol` varchar(50) NOT NULL, - `identifier` varchar(100) NOT NULL, - `version_count` int(11) NOT NULL -); - --- --- Copy data from old tables to intermediate tables --- - -insert into T_store (protocol, identifier) - select protocol, identifier from store; - -insert into T_node (protocol, identifier, uuid, type_qname) - select protocol, identifier, guid, type_qname from node; - -update T_store tstore set root_node_id = - (select tnode.id from T_node tnode where - tnode.protocol = tstore.protocol and - tnode.identifier = tstore.identifier and - tnode.uuid = - (select ostore.root_guid from store ostore where - ostore.protocol = tstore.protocol and - ostore.identifier = tstore.identifier - ) - ); - -insert into t_version_count (protocol, identifier, version_count) - select protocol, identifier, version_count from version_count; - -insert into t_node_status (protocol, identifier, guid, change_txn_id, deleted) - select protocol, identifier, guid, change_txn_id, deleted from node_status; -update T_node_status tstatus set node_id = - (select tnode.id from T_node tnode where - tnode.protocol = tstatus.protocol and - tnode.identifier = tstatus.identifier and - tnode.uuid = tstatus.guid - ); - -insert into T_node_properties - ( - protocol, identifier, uuid, actual_type, multi_valued, persisted_type, - boolean_value, long_value, float_value, double_value, string_value, serializable_value, qname - ) - select - protocol, identifier, guid, actual_type, multi_valued, persisted_type, - boolean_value, long_value, float_value, double_value, string_value, serializable_value, qname - from node_properties; -update T_node_properties tproperties set node_id = - (select tnode.id from T_node tnode where - tnode.protocol = tproperties.protocol and - tnode.identifier = tproperties.identifier and - tnode.uuid = tproperties.uuid - ); - -insert into T_node_aspects - ( - protocol, identifier, uuid, qname - ) - select - protocol, identifier, guid, qname - from node_aspects; -update T_node_aspects taspects set node_id = - (select tnode.id from T_node tnode where - tnode.protocol = taspects.protocol and - tnode.identifier = taspects.identifier and - tnode.uuid = taspects.uuid - ); - -insert into T_child_assoc - ( - parent_protocol, parent_identifier, parent_uuid, - child_protocol, child_identifier, child_uuid, - type_qname, qname, is_primary, assoc_index - ) - select - parent_protocol, parent_identifier, parent_guid, - child_protocol, child_identifier, child_guid, - type_qname, qname, isPrimary, assoc_index - from - child_assoc; -update T_child_assoc tassoc set parent_node_id = - (select tnode.id from T_node tnode where - tnode.protocol = tassoc.parent_protocol and - tnode.identifier = tassoc.parent_identifier and - tnode.uuid = tassoc.parent_uuid - ); -update T_child_assoc tassoc set child_node_id = - (select tnode.id from T_node tnode where - tnode.protocol = tassoc.child_protocol and - tnode.identifier = tassoc.child_identifier and - tnode.uuid = tassoc.child_uuid - ); - -insert into T_node_assoc - ( - source_protocol, source_identifier, source_uuid, - target_protocol, target_identifier, target_uuid, - type_qname - ) - select - source_protocol, source_identifier, source_guid, - target_protocol, target_identifier, target_guid, - type_qname - from - node_assoc; -update T_node_assoc tassoc set source_node_id = - (select tnode.id from T_node tnode where - tnode.protocol = tassoc.source_protocol and - tnode.identifier = tassoc.source_identifier and - tnode.uuid = tassoc.source_uuid - ); -update T_node_assoc tassoc set target_node_id = - (select tnode.id from T_node tnode where - tnode.protocol = tassoc.target_protocol and - tnode.identifier = tassoc.target_identifier and - tnode.uuid = tassoc.target_uuid - ); - -insert into T_permission - ( - type_qname, name - ) - select - CONCAT('{', type_uri, '}', type_name), name - from - permission_ref; - -insert into T_access_control_list - ( - protocol, identifier, uuid, inherits - ) - select - protocol, identifier, guid, inherits - from node_permission; -update T_node tnode set acl_id = - (select tacl.id from T_access_control_list tacl where - tacl.protocol = tnode.protocol and - tacl.identifier = tnode.identifier and - tacl.uuid = tnode.uuid - ); - -insert into T_auth_ext_keys - ( - id, externalKey - ) - select - id, externalKey - from - externalkeys; - -insert into T_authority - ( - recipient - ) - select - recipient - from - recipient; - -insert into T_access_control_entry - ( - protocol, identifier, uuid, - typeUri, typeName, name, - recipient, - allowed - ) - select - protocol, identifier, guid, - typeUri, typeName, name, - recipient, - allowed - from node_perm_entry; -update T_access_control_entry tentry - set - acl_id = - ( - select - tacl.id - from T_access_control_list tacl - join T_node tnode on tacl.id = tnode.acl_id - where - tnode.protocol = tentry.protocol and - tnode.identifier = tentry.identifier and - tnode.uuid = tentry.uuid - ); -update T_access_control_entry tentry - set - tentry.permission_id = - ( - select - tpermission.id - from T_permission tpermission - where - tpermission.type_qname = CONCAT('{', tentry.typeUri, '}', tentry.typeName) and - tpermission.name = tentry.name - ); -update T_access_control_entry tentry - set - tentry.authority_id = - ( - select - tauthority.recipient - from T_authority tauthority - where - tauthority.recipient = tentry.recipient - ); -delete from T_access_control_list where id not in (select distinct(acl_id) id from t_access_control_entry where acl_id is not null); -delete from T_access_control_entry where acl_id is null; -update T_node set acl_id = null where acl_id not in (select id from t_access_control_list); - --- --- Create New schema (MySQL) --- - -SET FOREIGN_KEY_CHECKS = 0; - -DROP TABLE child_assoc; -DROP TABLE node_assoc; -DROP TABLE node_properties; -DROP TABLE node_aspects; -DROP TABLE node; -DROP TABLE node_status; -DROP TABLE version_count; -DROP TABLE store; -DROP TABLE node_perm_entry; -DROP TABLE node_permission; -DROP TABLE permission_ref; -DROP TABLE recipient; -DROP TABLE externalKeys; - -CREATE TABLE `access_control_entry` ( - `id` bigint(20) NOT NULL auto_increment, - `acl_id` bigint(20) NOT NULL, - `permission_id` bigint(20) NOT NULL, - `authority_id` varchar(100) NOT NULL, - `allowed` bit(1) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `acl_id` (`acl_id`,`permission_id`,`authority_id`), - KEY `FKF064DF7560601995` (`permission_id`), - KEY `FKF064DF75B25A50BF` (`authority_id`), - KEY `FKF064DF75B9553F6C` (`acl_id`), - CONSTRAINT `FKF064DF75B9553F6C` FOREIGN KEY (`acl_id`) REFERENCES `access_control_list` (`id`), - CONSTRAINT `FKF064DF7560601995` FOREIGN KEY (`permission_id`) REFERENCES `permission` (`id`), - CONSTRAINT `FKF064DF75B25A50BF` FOREIGN KEY (`authority_id`) REFERENCES `authority` (`recipient`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `access_control_list` ( - `id` bigint(20) NOT NULL auto_increment, - `inherits` bit(1) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `auth_ext_keys` ( - `id` varchar(100) NOT NULL, - `externalKey` varchar(100) NOT NULL, - PRIMARY KEY (`id`,`externalKey`), - KEY `FK31D3BA097B7FDE43` (`id`), - CONSTRAINT `FK31D3BA097B7FDE43` FOREIGN KEY (`id`) REFERENCES `authority` (`recipient`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `authority` ( - `recipient` varchar(100) NOT NULL, - PRIMARY KEY (`recipient`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `child_assoc` ( - `id` bigint(20) NOT NULL auto_increment, - `parent_node_id` bigint(20) default NULL, - `child_node_id` bigint(20) default NULL, - `type_qname` varchar(255) NOT NULL, - `qname` varchar(255) NOT NULL, - `is_primary` bit(1) default NULL, - `assoc_index` int(11) default NULL, - PRIMARY KEY (`id`), - KEY `FKFFC5468E74173FF4` (`child_node_id`), - KEY `FKFFC5468E8E50E582` (`parent_node_id`), - CONSTRAINT `FKFFC5468E8E50E582` FOREIGN KEY (`parent_node_id`) REFERENCES `node` (`id`), - CONSTRAINT `FKFFC5468E74173FF4` FOREIGN KEY (`child_node_id`) REFERENCES `node` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; -FKFFC5468E74173FF4 - -CREATE TABLE `node` ( - `id` bigint(20) NOT NULL auto_increment, - `protocol` varchar(50) NOT NULL, - `identifier` varchar(100) NOT NULL, - `uuid` varchar(36) NOT NULL, - `type_qname` varchar(255) NOT NULL, - `acl_id` bigint(20) default NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `protocol` (`protocol`,`identifier`,`uuid`), - KEY `FK33AE02D24ADD25` (`protocol`,`identifier`), - CONSTRAINT `FK33AE02D24ADD25` FOREIGN KEY (`protocol`, `identifier`) REFERENCES `store` (`protocol`, `identifier`), - CONSTRAINT `FK33AE02B9553F6C` FOREIGN KEY (`acl_id`) REFERENCES `access_control_list` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `node_aspects` ( - `node_id` bigint(20) NOT NULL, - `qname` varchar(200) default NULL, - KEY `FK2B91A9DE7F2C8017` (`node_id`), - CONSTRAINT `FK2B91A9DE7F2C8017` FOREIGN KEY (`node_id`) REFERENCES `node` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `node_assoc` ( - `id` bigint(20) NOT NULL auto_increment, - `source_node_id` bigint(20) default NULL, - `target_node_id` bigint(20) default NULL, - `type_qname` varchar(255) NOT NULL, - PRIMARY KEY (`id`), - KEY `FK5BAEF398B69C43F3` (`source_node_id`), - KEY `FK5BAEF398A8FC7769` (`target_node_id`), - CONSTRAINT `FK5BAEF398A8FC7769` FOREIGN KEY (`target_node_id`) REFERENCES `node` (`id`), - CONSTRAINT `FK5BAEF398B69C43F3` FOREIGN KEY (`source_node_id`) REFERENCES `node` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `node_properties` ( - `node_id` bigint(20) NOT NULL, - `actual_type` varchar(15) NOT NULL, - `multi_valued` bit(1) NOT NULL, - `persisted_type` varchar(15) NOT NULL, - `boolean_value` bit(1) default NULL, - `long_value` bigint(20) default NULL, - `float_value` float default NULL, - `double_value` double default NULL, - `string_value` text, - `serializable_value` blob, - `qname` varchar(200) NOT NULL, - PRIMARY KEY (`node_id`,`qname`), - KEY `FKC962BF907F2C8017` (`node_id`), - CONSTRAINT `FKC962BF907F2C8017` FOREIGN KEY (`node_id`) REFERENCES `node` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `node_status` ( - `protocol` varchar(50) NOT NULL, - `identifier` varchar(100) NOT NULL, - `guid` varchar(36) NOT NULL, - `node_id` bigint(20) default NULL, - `change_txn_id` varchar(56) NOT NULL, - PRIMARY KEY (`protocol`,`identifier`,`guid`), - KEY `FK38ECB8CF7F2C8017` (`node_id`), - CONSTRAINT `FK38ECB8CF7F2C8017` FOREIGN KEY (`node_id`) REFERENCES `node` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `permission` ( - `id` bigint(20) NOT NULL auto_increment, - `type_qname` varchar(200) NOT NULL, - `name` varchar(100) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `type_qname` (`type_qname`,`name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `store` ( - `protocol` varchar(50) NOT NULL, - `identifier` varchar(100) NOT NULL, - `root_node_id` bigint(20) default NULL, - PRIMARY KEY (`protocol`,`identifier`), - KEY `FK68AF8E122DBA5BA` (`root_node_id`), - CONSTRAINT `FK68AF8E122DBA5BA` FOREIGN KEY (`root_node_id`) REFERENCES `node` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `version_count` ( - `protocol` varchar(100) NOT NULL, - `identifier` varchar(100) NOT NULL, - `version_count` int(11) NOT NULL, - PRIMARY KEY (`protocol`,`identifier`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- --- Copy data into new schema --- - -insert into store - ( - protocol, identifier, root_node_id - ) - select - protocol, identifier, root_node_id - from - T_store; - -insert into node - ( - id, protocol, identifier, uuid, type_qname, acl_id - ) - select - id, protocol, identifier, uuid, type_qname, acl_id - from - T_node; - -insert into version_count - ( - protocol, identifier, version_count - ) - select - protocol, identifier, version_count - from - T_version_count; - -insert into node_status - ( - protocol, identifier, guid, node_id, change_txn_id - ) - select - protocol, identifier, guid, node_id, change_txn_id - from - T_node_status; - -insert into node_properties - ( - node_id, actual_type, multi_valued, persisted_type, - boolean_value, long_value, float_value, double_value, string_value, serializable_value, qname - ) - select - node_id, actual_type, multi_valued, persisted_type, - boolean_value, long_value, float_value, double_value, string_value, serializable_value, qname - from - T_node_properties; - -insert into node_aspects - ( - node_id, qname - ) - select - node_id, qname - from - T_node_aspects; - -insert into child_assoc - ( - id, parent_node_id, child_node_id, type_qname, qname, is_primary, assoc_index - ) - select - id, parent_node_id, child_node_id, type_qname, qname, is_primary, assoc_index - from - T_child_assoc; - -insert into node_assoc - ( - id, source_node_id, target_node_id, type_qname - ) - select - id, source_node_id, target_node_id, type_qname - from - T_node_assoc; - -insert into permission - ( - id, type_qname, name - ) - select - id, type_qname, name - from - T_permission; - -insert into access_control_list - ( - id, inherits - ) - select - id, inherits - from - T_access_control_list; - -insert into auth_ext_keys - ( - id, externalKey - ) - select - id, externalKey - from - T_auth_ext_keys; - -insert into authority - ( - recipient - ) - select - recipient - from - T_authority; - -insert into access_control_entry - ( - id, acl_id, permission_id, authority_id, allowed - ) - select - id, acl_id, permission_id, authority_id, allowed - from - T_access_control_entry; - -SET FOREIGN_KEY_CHECKS = 1; - - --- Allow longer patch identifiers - -ALTER TABLE applied_patch MODIFY id varchar(64) not null; \ No newline at end of file diff --git a/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.Dialect/AlfrescoSchemaUpdate-1.4-TxnCommitTimeIndex.sql b/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.Dialect/AlfrescoSchemaUpdate-1.4-TxnCommitTimeIndex.sql deleted file mode 100644 index a8f88e73a6..0000000000 --- a/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.Dialect/AlfrescoSchemaUpdate-1.4-TxnCommitTimeIndex.sql +++ /dev/null @@ -1,17 +0,0 @@ --- --- Explicit index for alf_transaction.commit_time_ms (Generic Schema 1.4) --- - -UPDATE alf_transaction SET commit_time_ms = id WHERE commit_time_ms IS NULL; - --- --- Record script finish --- -delete from alf_applied_patch where id = 'patch.db-V1.4-TxnCommitTimeIndex'; -insert into alf_applied_patch - (id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report) - values - ( - 'patch.db-V1.4-TxnCommitTimeIndex', 'Executed script AlfrescoSchemaUpdate-1.4-TxnCommitTimeIndex.sql', - 0, 75, -1, 76, null, 'UNKOWN', ${TRUE}, ${TRUE}, 'Script completed' - ); \ No newline at end of file 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 deleted file mode 100644 index 350604fc57..0000000000 --- a/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-1.4-1.sql +++ /dev/null @@ -1,130 +0,0 @@ --- ------------------------------------------------------ --- Alfresco Schema conversion V1.3 to V1.4 Part 1 (MySQL) --- --- Adds the columns required to enforce the duplicate name detection --- --- Author: Derek Hulley --- ------------------------------------------------------ - --- --- Delete intermediate tables from previous upgrades --- - -DROP TABLE IF EXISTS T_access_control_entry; -DROP TABLE IF EXISTS T_access_control_list; -DROP TABLE IF EXISTS T_applied_patch; -DROP TABLE IF EXISTS T_auth_ext_keys; -DROP TABLE IF EXISTS T_authority; -DROP TABLE IF EXISTS T_child_assoc; -DROP TABLE IF EXISTS T_node; -DROP TABLE IF EXISTS T_node_aspects; -DROP TABLE IF EXISTS T_node_assoc; -DROP TABLE IF EXISTS T_node_properties; -DROP TABLE IF EXISTS T_node_status; -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 --- - --- Apply new schema changes to child assoc table -ALTER TABLE child_assoc - ADD COLUMN child_node_name VARCHAR(50) NOT NULL DEFAULT 'V1.4 upgrade' AFTER type_qname, - ADD COLUMN child_node_name_crc bigint(20) NOT NULL DEFAULT -1 AFTER child_node_name; - -UPDATE child_assoc - SET child_node_name_crc = id * -1; - -ALTER TABLE child_assoc - ADD UNIQUE INDEX IDX_CHILD_NAMECRC(parent_node_id, type_qname, child_node_name, child_node_name_crc); - --- Apply unique index for node associations -ALTER TABLE node_assoc - ADD UNIQUE INDEX IDX_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. --- 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 --- -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, now(), 'UNKOWN', 1, 1, 'Script completed' - ); \ No newline at end of file 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 deleted file mode 100644 index aeebaced5e..0000000000 --- a/config/alfresco/dbscripts/upgrade/1.4/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-1.4-2.sql +++ /dev/null @@ -1,66 +0,0 @@ --- ------------------------------------------------------ --- 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. --- --- Author: Derek Hulley --- ------------------------------------------------------ - --- --- Create server and transaction tables --- - -CREATE TABLE alf_server ( - id bigint(20) NOT NULL auto_increment, - ip_address varchar(15) NOT NULL, - PRIMARY KEY (id), - UNIQUE KEY ip_address (ip_address) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; -insert into alf_server (id, ip_address) values (0, '0.0.0.0'); - -CREATE TABLE alf_transaction ( - id bigint(20) NOT NULL auto_increment, - server_id bigint(20) default NULL, - change_txn_id varchar(56) NOT NULL, - PRIMARY KEY (id), - KEY FKB8761A3A9AE340B7 (server_id), - CONSTRAINT FKB8761A3A9AE340B7 FOREIGN KEY (server_id) REFERENCES alf_server (id) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; --- add index for perfromance -create index ug_index_142_1 on alf_transaction (change_txn_id); -insert into alf_transaction - ( - server_id, change_txn_id - ) - select (select max(id) from alf_server), change_txn_id from alf_node_status group by change_txn_id; - --- Alter node status -ALTER TABLE alf_node_status - ADD COLUMN transaction_id bigint(20) NOT NULL DEFAULT 0 AFTER node_id; --- 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 - ); --- remove index added for performance - -ALTER TABLE alf_node_status - DROP COLUMN change_txn_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) -drop index ug_index_142_1 on alf_transaction; --- --- 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, now(), 'UNKOWN', 1, 1, 'Script completed' - ); \ No newline at end of file diff --git a/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-2.2-MappedFKIndexes.sql b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.Dialect/AddFKIndexes.sql similarity index 100% rename from config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.Dialect/AlfrescoPostCreate-2.2-MappedFKIndexes.sql rename to config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.Dialect/AddFKIndexes.sql diff --git a/config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-2.2-MappedFKIndexes.sql b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AddFKIndexes.sql similarity index 100% rename from config/alfresco/dbscripts/create/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoPostCreate-2.2-MappedFKIndexes.sql rename to config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AddFKIndexes.sql diff --git a/config/alfresco/dbscripts/create/3.0/org.hibernate.dialect.Dialect/create-activities-extras.sql b/config/alfresco/dbscripts/upgrade/3.0/org.hibernate.dialect.Dialect/create-activities-extras.sql similarity index 97% rename from config/alfresco/dbscripts/create/3.0/org.hibernate.dialect.Dialect/create-activities-extras.sql rename to config/alfresco/dbscripts/upgrade/3.0/org.hibernate.dialect.Dialect/create-activities-extras.sql index f19f1332f6..6b9af46b1d 100644 --- a/config/alfresco/dbscripts/create/3.0/org.hibernate.dialect.Dialect/create-activities-extras.sql +++ b/config/alfresco/dbscripts/upgrade/3.0/org.hibernate.dialect.Dialect/create-activities-extras.sql @@ -3,7 +3,7 @@ -- Database: Generic -- Since: V3.0.0 Schema -- - + CREATE INDEX post_jobtasknode_idx ON alf_activity_post(job_task_node); CREATE INDEX post_status_idx ON alf_activity_post(status); diff --git a/config/alfresco/dbscripts/create/3.0/org.hibernate.dialect.PostgreSQLDialect/create-activities-extras.sql b/config/alfresco/dbscripts/upgrade/3.0/org.hibernate.dialect.PostgreSQLDialect/create-activities-extras.sql old mode 100644 new mode 100755 similarity index 100% rename from config/alfresco/dbscripts/create/3.0/org.hibernate.dialect.PostgreSQLDialect/create-activities-extras.sql rename to config/alfresco/dbscripts/upgrade/3.0/org.hibernate.dialect.PostgreSQLDialect/create-activities-extras.sql diff --git a/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.Dialect/fix-AVM-seqs.sql b/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.Dialect/fix-AVM-seqs.sql new file mode 100755 index 0000000000..9a066a9442 --- /dev/null +++ b/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.Dialect/fix-AVM-seqs.sql @@ -0,0 +1,23 @@ +-- +-- Title: Upgrade to V3.4 - Create AVM sequences +-- Database: Generic +-- Since: V3.4 schema 4105 +-- Author: unknown +-- +-- creates sequences for AVM tables +-- +-- Please contact support@alfresco.com if you need assistance with the upgrade. +-- + + +-- +-- Record script finish +-- +DELETE FROM alf_applied_patch WHERE id = 'patch.db-V3.3-Fix-AVM-Seqs'; +INSERT INTO alf_applied_patch + (id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report) + VALUES + ( + 'patch.db-V3.3-Fix-AVM-Seqs', 'Manually executed script upgrade V3.3 to create AVM sequences', + 0, 4104, -1, 4105, null, 'UNKOWN', ${TRUE}, ${TRUE}, 'Script completed' + ); diff --git a/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.Dialect/fix-Repo-seqs_1.sql b/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.Dialect/fix-Repo-seqs.sql old mode 100644 new mode 100755 similarity index 70% rename from config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.Dialect/fix-Repo-seqs_1.sql rename to config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.Dialect/fix-Repo-seqs.sql index 6dd87f3f17..73f1107eb0 --- a/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.Dialect/fix-Repo-seqs_1.sql +++ b/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.Dialect/fix-Repo-seqs.sql @@ -1,7 +1,7 @@ -- -- Title: Upgrade to V3.3 - Create repo sequences -- Database: Generic --- Since: V3.3 schema 4008 +-- Since: V3.4 schema 4105 -- Author: unknown -- -- creates sequences for repo tables @@ -13,11 +13,11 @@ -- -- Record script finish -- -DELETE FROM alf_applied_patch WHERE id = 'patch.db-V3.3-Fix-Repo-Seqs_1'; +DELETE FROM alf_applied_patch WHERE id = 'patch.db-V3.3-Fix-Repo-Seqs'; INSERT INTO alf_applied_patch (id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report) VALUES ( - 'patch.db-V3.3-Fix-Repo-Seqs_1', 'Manually executed script upgrade V3.3 to create repo sequences', - 0, 4007, -1, 4008, null, 'UNKOWN', ${TRUE}, ${TRUE}, 'Script completed' + 'patch.db-V3.3-Fix-Repo-Seqs', 'Manually executed script upgrade V3.3 to create repo sequences', + 0, 4104, -1, 4105, null, 'UNKOWN', ${TRUE}, ${TRUE}, 'Script completed' ); diff --git a/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.MySQLInnoDBDialect/property-unique-ctx-value.sql b/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.MySQLInnoDBDialect/property-unique-ctx-value.sql new file mode 100755 index 0000000000..e3c0903aad --- /dev/null +++ b/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.MySQLInnoDBDialect/property-unique-ctx-value.sql @@ -0,0 +1,25 @@ +-- +-- Title: Upgrade to V3.4 - Add alf_prop_unique_ctx.prop1_id column +-- Database: MySQL +-- Since: V3.4 schema 4105 +-- Author: Derek Hulley +-- +-- Please contact support@alfresco.com if you need assistance with the upgrade. +-- + +ALTER TABLE alf_prop_unique_ctx + ADD COLUMN prop1_id BIGINT NULL AFTER value3_prop_id, + ADD CONSTRAINT fk_alf_propuctx_p1 FOREIGN KEY (prop1_id) REFERENCES alf_prop_root (id) +; + +-- +-- Record script finish +-- +DELETE FROM alf_applied_patch WHERE id = 'patch.db-V3.3-property-unique-ctx-value'; +INSERT INTO alf_applied_patch + (id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report) + VALUES + ( + 'patch.db-V3.3-property-unique-ctx-value', 'Manually executed script upgrade V3.3', + 0, 4104, -1, 4105, null, 'UNKOWN', ${TRUE}, ${TRUE}, 'Script completed' + ); diff --git a/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/fix-AVM-seqs.sql b/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/fix-AVM-seqs.sql new file mode 100755 index 0000000000..b674b6f4ee --- /dev/null +++ b/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/fix-AVM-seqs.sql @@ -0,0 +1,33 @@ +-- +-- Title: Upgrade to V3.4 - Create AVM sequences +-- Database: PostgreSQL +-- Since: V3.4 schema 4105 +-- Author: unknown +-- +-- creates sequences for AVM tables +-- +-- Please contact support@alfresco.com if you need assistance with the upgrade. +-- + +--ASSIGN:hibernate_seq_next_value=value +SELECT NEXTVAL(hibernate_sequence) AS value; + +CREATE SEQUENCE avm_stores_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE avm_store_properties_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE avm_nodes_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE avm_version_roots_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +-- +-- Record script finish +-- +DELETE FROM alf_applied_patch WHERE id = 'patch.db-V3.3-Fix-AVM-Seqs'; +INSERT INTO alf_applied_patch + (id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report) + VALUES + ( + 'patch.db-V3.3-Fix-AVM-Seqs', 'Manually executed script upgrade V3.3 to create AVM sequences', + 0, 4104, -1, 4105, null, 'UNKOWN', ${TRUE}, ${TRUE}, 'Script completed' + ); diff --git a/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/fix-Repo-seqs.sql b/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/fix-Repo-seqs.sql index e0f7672fa5..4c9e935cc4 100755 --- a/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/fix-Repo-seqs.sql +++ b/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/fix-Repo-seqs.sql @@ -1,7 +1,7 @@ -- -- Title: Upgrade to V3.3 - Create repo sequences -- Database: PostgreSQL --- Since: V3.3 schema 4005 +-- Since: V3.4 schema 4105 -- Author: unknown -- -- creates sequences for repo tables @@ -9,11 +9,54 @@ -- Please contact support@alfresco.com if you need assistance with the upgrade. -- -CREATE SEQUENCE alf_namespace_seq START WITH 1 INCREMENT BY 1; -SELECT SETVAL('alf_namespace_seq', NEXTVAL('hibernate_sequence')); +--ASSIGN:hibernate_seq_next_value=value +SELECT NEXTVAL(hibernate_sequence) AS value; -CREATE SEQUENCE alf_qname_seq START WITH 1 INCREMENT BY 1; -SELECT SETVAL('alf_qname_seq', CURRVAL('hibernate_sequence')); +CREATE SEQUENCE alf_namespace_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; -- (optional) + +CREATE SEQUENCE alf_qname_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; -- (optional) + +CREATE SEQUENCE alf_permission_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_ace_context_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_authority_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_access_control_entry_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_acl_change_set_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_access_control_list_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_acl_member_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_authority_alias_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_audit_config_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_audit_date_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_audit_source_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_audit_fact_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_server_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_transaction_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_store_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_node_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_child_assoc_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_locale_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_attributes_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_node_assoc_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; + +CREATE SEQUENCE alf_usage_delta_seq START WITH ${hibernate_seq_next_value} INCREMENT BY 1; -- -- Record script finish @@ -24,5 +67,5 @@ INSERT INTO alf_applied_patch VALUES ( 'patch.db-V3.3-Fix-Repo-Seqs', 'Manually executed script upgrade V3.3 to create repo sequences', - 0, 4004, -1, 4005, null, 'UNKOWN', ${TRUE}, ${TRUE}, 'Script completed' + 0, 4104, -1, 4105, null, 'UNKOWN', ${TRUE}, ${TRUE}, 'Script completed' ); diff --git a/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/fix-Repo-seqs_1.sql b/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/fix-Repo-seqs_1.sql deleted file mode 100644 index b1e8e84d6e..0000000000 --- a/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/fix-Repo-seqs_1.sql +++ /dev/null @@ -1,28 +0,0 @@ --- --- Title: Upgrade to V3.3 - Create repo sequences --- Database: PostgreSQL --- Since: V3.3 schema 4008 --- Author: unknown --- --- creates sequences for repo tables --- --- Please contact support@alfresco.com if you need assistance with the upgrade. --- - -CREATE SEQUENCE alf_namespace_seq START WITH 1 INCREMENT BY 1; -SELECT SETVAL('alf_namespace_seq', NEXTVAL('hibernate_sequence')); - -CREATE SEQUENCE alf_qname_seq START WITH 1 INCREMENT BY 1; -SELECT SETVAL('alf_qname_seq', CURRVAL('hibernate_sequence')); - --- --- Record script finish --- -DELETE FROM alf_applied_patch WHERE id = 'patch.db-V3.3-Fix-Repo-Seqs_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.db-V3.3-Fix-Repo-Seqs_1', 'Manually executed script upgrade V3.3 to create repo sequences', - 0, 4007, -1, 4008, null, 'UNKOWN', ${TRUE}, ${TRUE}, 'Script completed' - ); diff --git a/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/property-unique-ctx-value.sql b/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/property-unique-ctx-value.sql new file mode 100755 index 0000000000..0b3bd97ecb --- /dev/null +++ b/config/alfresco/dbscripts/upgrade/3.3/org.hibernate.dialect.PostgreSQLDialect/property-unique-ctx-value.sql @@ -0,0 +1,25 @@ +-- +-- Title: Upgrade to V3.4 - Add alf_prop_unique_ctx.prop1_id column +-- Database: PostgreSQL +-- Since: V3.4 schema 4105 +-- Author: Derek Hulley +-- +-- Please contact support@alfresco.com if you need assistance with the upgrade. +-- + +ALTER TABLE alf_prop_unique_ctx + ADD COLUMN prop1_id INT8, + ADD CONSTRAINT fk_alf_propuctx_p1 FOREIGN KEY (prop1_id) REFERENCES alf_prop_root (id) +; + +-- +-- Record script finish +-- +DELETE FROM alf_applied_patch WHERE id = 'patch.db-V3.3-property-unique-ctx-value'; +INSERT INTO alf_applied_patch + (id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report) + VALUES + ( + 'patch.db-V3.3-property-unique-ctx-value', 'Manually executed script upgrade V3.3', + 0, 4104, -1, 4105, null, 'UNKOWN', ${TRUE}, ${TRUE}, 'Script completed' + ); diff --git a/config/alfresco/ehcache-default.xml b/config/alfresco/ehcache-default.xml index 8d8bbb4f38..187fde7e8d 100644 --- a/config/alfresco/ehcache-default.xml +++ b/config/alfresco/ehcache-default.xml @@ -39,15 +39,41 @@ overflowToDisk="false" statistics="false" /> - + + - + + - - - - - - - - - - - - - - - - - - - - - - - - - @@ -248,36 +171,8 @@ statistics="false" /> - - - - - - + + + + + + + + + - - - - \ No newline at end of file diff --git a/config/alfresco/extension/ehcache-custom.xml.sample.cluster b/config/alfresco/extension/ehcache-custom.xml.sample.cluster index 61ef2eeb9d..e8ba537c27 100644 --- a/config/alfresco/extension/ehcache-custom.xml.sample.cluster +++ b/config/alfresco/extension/ehcache-custom.xml.sample.cluster @@ -90,8 +90,8 @@ + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - + - + + + + + + - - - org.alfresco.tenantsTransactionalCache diff --git a/config/alfresco/hibernate-context.xml b/config/alfresco/hibernate-context.xml index 1293fe8ac1..ca4971330d 100644 --- a/config/alfresco/hibernate-context.xml +++ b/config/alfresco/hibernate-context.xml @@ -56,13 +56,8 @@ - org/alfresco/repo/domain/hibernate/Locale.hbm.xml org/alfresco/repo/domain/hibernate/Node.hbm.xml org/alfresco/repo/domain/hibernate/Transaction.hbm.xml - org/alfresco/repo/domain/hibernate/Permission.hbm.xml - org/alfresco/repo/attributes/hibernate/Attributes.hbm.xml - org/alfresco/repo/domain/hibernate/UsageDelta.hbm.xml - org/alfresco/repo/activities/hibernate/Activities.hbm.xml @@ -167,20 +162,9 @@ ${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} @@ -189,7 +173,6 @@ ${cache.strategy} - ${cache.strategy} @@ -203,126 +186,6 @@ - - - - org.alfresco.repo.security.permissions.impl.PermissionsDaoComponent - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - daoServiceDirtySessionInterceptor - - - - - - - - - - - - - - - - - - - - - - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -342,48 +205,6 @@ - - - ${system.enableTimestampPropagation} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -412,47 +233,8 @@ - - - - - - - - - - - - - sessionSizeResourceInterceptor - daoServiceDirtySessionInterceptor - dbNodeDaoServiceTxnRegistration - - - - - - - - - - - - - - - - - - - - daoServiceDirtySessionInterceptor - - - - diff --git a/config/alfresco/ibatis/alfresco-SqlMapConfig.xml b/config/alfresco/ibatis/alfresco-SqlMapConfig.xml index bb727c18c7..3be7e9183a 100644 --- a/config/alfresco/ibatis/alfresco-SqlMapConfig.xml +++ b/config/alfresco/ibatis/alfresco-SqlMapConfig.xml @@ -14,6 +14,11 @@ + + + + + @@ -24,5 +29,9 @@ + + + + - + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/activities-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/activities-common-SqlMap.xml index c1bb816998..7c8a036e76 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/activities-common-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/activities-common-SqlMap.xml @@ -6,10 +6,18 @@ + + + + + + + + @@ -44,6 +52,48 @@ + + + + + + insert into alf_activity_feed_control (feed_user_id, site_network, app_tool, last_modified) + values (#feedUserId#, #siteNetwork#, #appTool#, #lastModified#) + + + + insert into alf_activity_feed_control (id, feed_user_id, site_network, app_tool, last_modified) + values (#id#, #feedUserId#, #siteNetwork#, #appTool#, #lastModified#) + + + + insert into alf_activity_feed (activity_type, activity_summary, activity_format, feed_user_id, post_user_id, post_date, post_id, site_network, app_tool, feed_date) + values (#activityType#, #activitySummary#, #activitySummaryFormat#, #feedUserId#, #postUserId#, #postDate#, #postId#, #siteNetwork#, #appTool#, #feedDate#) + + + + insert into alf_activity_feed (id, activity_type, activity_summary, activity_format, feed_user_id, post_user_id, post_date, post_id, site_network, app_tool, feed_date) + values (#id#, #activityType#, #activitySummary#, #activitySummaryFormat#, #feedUserId#, #postUserId#, #postDate#, #postId#, #siteNetwork#, #appTool#, #feedDate#) + + + + insert into alf_activity_post (status, activity_data, post_user_id, post_date, activity_type, site_network, app_tool, job_task_node, last_modified) + values (#status#, #activityData#, #userId#, #postDate#, #activityType#, #siteNetwork#, #appTool#, #jobTaskNode#, #lastModified#) + + + + insert into alf_activity_post (sequence_id, status, activity_data, post_user_id, post_date, activity_type, site_network, app_tool, job_task_node, last_modified) + values (#id#, #status#, #activityData#, #userId#, #postDate#, #activityType#, #siteNetwork#, #appTool#, #jobTaskNode#, #lastModified#) + + + + + + + + + + + + + + + #status# + ]]> + #status# + ]]> \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/appliedpatch-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/appliedpatch-common-SqlMap.xml index c6a90bbe4f..b1ca96f5e1 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/appliedpatch-common-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/appliedpatch-common-SqlMap.xml @@ -11,11 +11,11 @@ - + - + @@ -29,26 +29,10 @@ - - - - - - - - - - + + + insert into alf_applied_patch @@ -94,14 +78,14 @@ - - - select content_url from @@ -615,6 +628,29 @@ + + + update + avm_nodes set acl_id = null + where + acl_id is not null + and id in + + #[]# + + + + + + update + avm_nodes set acl_id = #id# + where + id in + + #listOfIds[]# + + + delete from diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/content-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/content-common-SqlMap.xml index 14d84b508b..0393da16d4 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/content-common-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/content-common-SqlMap.xml @@ -78,8 +78,8 @@ - - + + diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/locale-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/locale-common-SqlMap.xml new file mode 100644 index 0000000000..3def672a03 --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/locale-common-SqlMap.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + insert into alf_locale (version, locale_str) + values (#version#, #localeStr#) + + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-common-SqlMap.xml new file mode 100644 index 0000000000..2c93ebaee2 --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-common-SqlMap.xml @@ -0,0 +1,864 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + insert into alf_server (version, ip_address) + values (#version#, #ipAddress#) + + + insert into alf_server (id, version, ip_address) + values (#id#, #version#, #ipAddress#) + + + + insert into alf_transaction (version, server_id, change_txn_id, commit_time_ms) + values (#version#, #server.id#, #changeTxnId#, #commitTimeMs#) + + + insert into alf_transaction (id, version, server_id, change_txn_id, commit_time_ms) + values (#id#, #version#, #server.id#, #changeTxnId#, #commitTimeMs#) + + + + insert into alf_store (version, protocol, identifier, root_node_id) + values (#version#, #protocol#, #identifier#, #rootNode.id#) + + + insert into alf_store (id, version, protocol, identifier, root_node_id) + values (#id#, #version#, #protocol#, #identifier#, #rootNode.id#) + + + + insert into alf_node + ( + version, store_id, uuid, type_qname_id, acl_id, node_deleted, transaction_id + + audit_creator, audit_created, + audit_modifier, audit_modified, + audit_accessed + + ) + values + ( + #version#, #store.id#, #uuid#, #typeQNameId#, #aclId#, #deleted#, #transaction.id# + + #auditableProperties.auditCreator#, #auditableProperties.auditCreated#, + #auditableProperties.auditModifier#, #auditableProperties.auditModified#, + #auditableProperties.auditAccessed# + + ) + + + insert into alf_node + ( + id, version, store_id, uuid, type_qname_id, acl_id, node_deleted, transaction_id + + audit_creator, audit_created, + audit_modifier, audit_modified, + audit_accessed + + ) + values + ( + #id#, #version#, #store.id#, #uuid#, #typeQNameId#, #aclId#, #deleted#, #transaction.id# + + #auditableProperties.auditCreator#, #auditableProperties.auditCreated#, + #auditableProperties.auditModifier#, #auditableProperties.auditModified#, + #auditableProperties.auditAccessed# + + ) + + + + insert into alf_child_assoc + ( + version, parent_node_id, child_node_id, type_qname_id, + child_node_name_crc, child_node_name, + qname_ns_id, qname_localname, qname_crc, + is_primary, assoc_index + ) + values + ( + #version#, #parentNode.id#, #childNode.id#, #typeQNameId#, + #childNodeNameCrc#, #childNodeName#, + #qnameNamespaceId#, #qnameLocalName#, #qnameCrc#, + #isPrimary#, #assocIndex# + ) + + + insert into alf_child_assoc + ( + id, version, parent_node_id, child_node_id, type_qname_id, + child_node_name_crc, child_node_name, + qname_ns_id, qname_localname, qname_crc, + is_primary, assoc_index + ) + values + ( + #id#, #version#, #parentNode.id#, #childNode.id#, #typeQNameId#, + #childNodeNameCrc#, #childNodeName#, + #qnameNamespaceId#, #qnameLocalName#, #qnameCrc#, + #isPrimary#, #assocIndex# + ) + + + + insert into alf_node_assoc (version, source_node_id, target_node_id, type_qname_id) + values (#version#, #sourceNode.id#, #targetNode.id#, #typeQNameId#) + + + insert into alf_node_assoc (id, version, source_node_id, target_node_id, type_qname_id) + values (#id#, #version#, #sourceNode.id#, #targetNode.id#, #typeQNameId#) + + + + + + + + insert into alf_node_properties + ( + node_id, qname_id, locale_id, list_index, + actual_type_n, persisted_type_n, + boolean_value, long_value, float_value, double_value, string_value, serializable_value + ) + values + ( + ?, ?, ?, ?, + ?, ?, + ?, ?, ?, ?, ?, ? + ) + + + + + insert into alf_node_aspects + (node_id, qname_id) + values + (?, ?) + + + + + + + + update alf_transaction set + commit_time_ms = #commitTimeMs# + where + id = #id# + + + + update alf_store set + root_node_id = #rootNode.id# + where + id = #id# + + + + update alf_node set + version = #version# + , store_id = #store.id# + , uuid = #uuid# + , type_qname_id = #typeQNameId# + , acl_id = #aclId# + , node_deleted = #deleted# + , transaction_id = #transaction.id# + + , audit_creator = #auditableProperties.auditCreator# + , audit_created = #auditableProperties.auditCreated# + , audit_modifier = #auditableProperties.auditModifier# + , audit_modified = #auditableProperties.auditModified# + , audit_accessed = #auditableProperties.auditAccessed# + + where + id = #id# + + and version = (#version#-1) + + + + + update alf_child_assoc set + child_node_name_crc = #childNodeNameCrc#, + child_node_name = #childNodeName# + where + child_node_id = #childNode.id# and + child_node_name_crc > 0 + + + + update alf_child_assoc set + assoc_index = #assocIndex# + where + parent_node_id = #parentNode.id# and + type_qname_id = #typeQNameId# and + qname_ns_id = #qnameNamespaceId# and + qname_localname = #qnameLocalName# + + + + update alf_child_assoc set + parent_node_id = #parentNode.id# + , type_qname_id = #typeQNameId# + , child_node_name_crc = #childNodeNameCrc# + , child_node_name = #childNodeName# + , qname_ns_id = #qnameNamespaceId# + , qname_localname = #qnameLocalName# + , qname_crc = #qnameCrc# + where + child_node_id = #childNode.id# and + is_primary = #isPrimary# + + + + + + + + delete from alf_transaction + where + id = #id# + + + + delete from alf_node + where + id = #id# + and node_deleted = #deleted# + + + + delete from alf_node_properties + where + node_id = #nodeId# + and qname_id = #key.qnameId# + and locale_id = #key.localeId# + and list_index = #key.listIndex# + + and qname_id in + #qnameIds[]# + + + + + delete from alf_node_aspects + where + node_id = #id# + + and qname_id in + #aspectQNameIds[]# + + + + + delete from alf_node_assoc + where + source_node_id = #sourceNode.id# and + target_node_id = #targetNode.id# and + type_qname_id = #typeQNameId# + + + + delete from alf_node_assoc + where + (source_node_id = #sourceNode.id# or target_node_id = #targetNode.id#) + + and type_qname_id in + #typeQNameIds[]# + + + + + delete from alf_child_assoc + where + id = #id# + + + + delete from alf_child_assoc + where + (parent_node_id = #parentNode.id# or child_node_id = #childNode.id#) + + and type_qname_id in + #typeQNameIds[]# + + + + + + + + + + + + + + + + + + select + node.id as id, + node.version as version, + store.id as store_id, + store.protocol as protocol, + store.identifier as identifier, + node.uuid as uuid, + node.type_qname_id as type_qname_id, + node.acl_id as acl_id, + node.node_deleted as node_deleted, + txn.id as txn_id, + txn.change_txn_id as txn_change_id, + node.audit_creator as audit_creator, + node.audit_created as audit_created, + node.audit_modifier as audit_modifier, + node.audit_modified as audit_modified, + node.audit_accessed as audit_accessed + + + + + + + + select + prop.node_id as node_id, + prop.qname_id as qname_id, + prop.locale_id as locale_id, + prop.list_index as list_index, + prop.actual_type_n as actual_type_n, + prop.persisted_type_n as persisted_type_n, + prop.boolean_value as boolean_value, + prop.long_value as long_value, + prop.float_value as float_value, + prop.double_value as double_value, + prop.string_value as string_value, + prop.serializable_value as serializable_value + + + + + + + + + + + select + assoc.id as id, + sourceNode.id as sourceNodeId, + sourceStore.protocol as sourceNodeProtocol, + sourceStore.identifier as sourceNodeIdentifier, + sourceNode.uuid as sourceNodeUuid, + targetNode.id as targetNodeId, + targetStore.protocol as targetNodeProtocol, + targetStore.identifier as targetNodeIdentifier, + targetNode.uuid as targetNodeUuid, + assoc.type_qname_id as type_qname_id + from + alf_node_assoc assoc + join alf_node sourceNode on (sourceNode.id = assoc.source_node_id) + join alf_store sourceStore on (sourceStore.id = sourceNode.store_id) + join alf_node targetNode on (targetNode.id = assoc.target_node_id) + join alf_store targetStore on (targetStore.id = targetNode.store_id) + + + + + + + + + select + assoc.id as id, + parentNode.id as parentNodeId, + parentStore.protocol as parentNodeProtocol, + parentStore.identifier as parentNodeIdentifier, + parentNode.uuid as parentNodeUuid, + childNode.id as childNodeId, + childStore.protocol as childNodeProtocol, + childStore.identifier as childNodeIdentifier, + childNode.uuid as childNodeUuid, + assoc.type_qname_id as type_qname_id, + assoc.child_node_name_crc as child_node_name_crc, + assoc.child_node_name as child_node_name, + assoc.qname_ns_id as qname_ns_id, + assoc.qname_localname as qname_localname, + assoc.is_primary as is_primary, + assoc.assoc_index as assoc_index + + + from + alf_child_assoc assoc + join alf_node parentNode on (parentNode.id = assoc.parent_node_id) + join alf_store parentStore on (parentStore.id = parentNode.store_id) + join alf_node childNode on (childNode.id = assoc.child_node_id) + join alf_store childStore on (childStore.id = childNode.store_id) + + + order by + assoc.assoc_index ASC, + assoc.id ASC + + + + + + + + + + + + + + select + txn.id as id, + txn.version as version, + txn.change_txn_id as change_txn_id, + txn.commit_time_ms as commit_time_ms + + + order by txn.commit_time ASC + order by txn.commit_time DESC + + + + + + txn.id = #id# + store.id = #storeId# + #excludeServerId#]]> + = #minCommitTime#]]> + + + txn.id in #includeTxnIds[]# + + + txn.id NOT in #excludeTxnIds[]# + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-update-acl-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-update-acl-SqlMap.xml new file mode 100644 index 0000000000..0e73152fc6 --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/node-update-acl-SqlMap.xml @@ -0,0 +1,33 @@ + + + + + + + + + update + alf_node + set + acl_id = #newSharedAclId# + where id in + ( + select n.id + from + alf_node n + join alf_child_assoc ca on (n.id = ca.child_node_id and ca.is_primary = #isPrimary#) + where + ca.parent_node_id = #primaryParentNodeId# + and + ( + n.acl_id is null + OR n.acl_id = #optionalOldSharedAclIdInAdditionToNull# + ) + ) + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/patch-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/patch-common-SqlMap.xml index 333d7e7218..2383cd560b 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/patch-common-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/patch-common-SqlMap.xml @@ -24,6 +24,11 @@ + + + + + @@ -89,6 +94,14 @@ ]]> + + diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/permissions-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/permissions-common-SqlMap.xml new file mode 100644 index 0000000000..e1edbb93ec --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/permissions-common-SqlMap.xml @@ -0,0 +1,661 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + insert into alf_access_control_list + (version, acl_id, latest, acl_version, inherits, inherits_from, + type, inherited_acl, is_versioned, requires_version, acl_change_set) + values + (#version#, #aclId#, #latest#, #aclVersion#, #inherits#, #inheritsFrom#, + #type#, #inheritedAcl#, #isVersioned#, #requiresVersion#, #aclChangeSet#) + + + + insert into alf_access_control_list + (id, version, acl_id, latest, acl_version, inherits, inherits_from, + type, inherited_acl, is_versioned, requires_version, acl_change_set) + values + (#id#, #version#, #aclId#, #latest#, #aclVersion#, #inherits#, #inheritsFrom#, + #type#, #inheritedAcl#, #isVersioned#, #requiresVersion#, #aclChangeSet#) + + + + insert into alf_acl_member + (version, acl_id, ace_id, pos) + values + (#version#, #aclId#, #aceId#, #pos#) + + + + insert into alf_acl_member + (id, version, acl_id, ace_id, pos) + values + (#id#, #version#, #aclId#, #aceId#, #pos#) + + + + insert into alf_acl_change_set + (version) + values + (#version#) + + + + insert into alf_acl_change_set + (id, version) + values + (#id#, #version#) + + + + insert into alf_access_control_entry + (version, permission_id, authority_id, allowed, applies, context_id) + values + (#version#, #permissionId#, #authorityId#, #allowed#, #applies#, #contextId#) + + + + insert into alf_access_control_entry + (id, version, permission_id, authority_id, allowed, applies, context_id) + values + (#id#, #version#, #permissionId#, #authorityId#, #allowed#, #applies#, #contextId#) + + + + insert into alf_ace_context + (version, class_context, property_context, kvp_context) + values + (#version#, #classContext#, #propertyContext#, #kvpContext#) + + + + insert into alf_ace_context + (id, version, class_context, property_context, kvp_context) + values + (#id#, #version#, #classContext#, #propertyContext#, #kvpContext#) + + + + insert into alf_permission + (version, type_qname_id, name) + values + (#version#, #qnameId#, #name#) + + + + insert into alf_permission + (id, version, type_qname_id, name) + values + (#id#, #version#, #qnameId#, #name#) + + + + insert into alf_authority + (version, authority, crc) + values + (#version#, #authority#, #crc#) + + + + insert into alf_authority + (id, version, authority, crc) + values + (#id#, #version#, #authority#, #crc#) + + + + insert into alf_authority_alias + (version, auth_id, alias_id) + values + (#version#, #authId#, #aliasId#) + + + + insert into alf_authority_alias + (id, version, auth_id, alias_id) + values + (#id#, #version#, #authId#, #aliasId#) + + + + + + + + + + update + alf_access_control_list + set + acl_id = #aclId#, + latest = #latest#, + acl_version = #aclVersion#, + inherits = #inherits#, + inherits_from = #inheritsFrom#, + type = #type#, + inherited_acl = #inheritedAcl#, + is_versioned = #isVersioned#, + requires_version = #requiresVersion#, + acl_change_set = #aclChangeSet#, + version = #version# + where + id = #id# + + and version = (#version#-1) + + + + + + update + alf_acl_member + set + acl_id = #aclId#, + ace_id = #aceId#, + pos = #pos#, + version = #version# + where + id = #id# + + and version = (#version#-1) + + + + + + update + alf_authority + set + authority = #authority#, + crc = #crc#, + version = #version# + where + id = #id# + + and version = (#version#-1) + + + + + + update + alf_permission + set + qname_id = #qnameId#, + name = #name#, + version = #version# + where + id = #id# + + and version = (#version#-1) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + delete + from + alf_access_control_list + where + id = ? + + + + + delete + from + alf_access_control_list + where + id in + + #[]# + + + + + delete + from + alf_access_control_entry + where + id in + + #[]# + + + + + + delete + from + alf_access_control_entry + where + id not in + ( + select + distinct(m.ace_id) + from + alf_acl_member m + ) + + + + delete + from + alf_acl_member + where + id in + + #[]# + + + + + delete + from + alf_acl_member + where + acl_id = ? + + + + + delete + from + alf_acl_member + where + acl_id in + + #[]# + + + + + delete + from + alf_acl_change_set + where + id = ? + + + + delete + from + alf_ace_context + where + id = ? + + + + delete + from + alf_authority + where + id = ? + + + + delete + from + alf_authority_alias + where + id = ? + + + + delete + from + alf_permission + where + id = ? + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/propval-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/propval-common-SqlMap.xml index 08ae1ef012..928da9eae4 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/propval-common-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/propval-common-SqlMap.xml @@ -95,6 +95,7 @@ + @@ -167,14 +168,18 @@ insert into alf_prop_root (version) values (?) - + insert into alf_prop_root (id, version) values (?, ?) - insert into alf_prop_unique_ctx (version, value1_prop_id, value2_prop_id, value3_prop_id) - values (#version#, #value1PropId#, #value2PropId#, #value3PropId#) + insert into alf_prop_unique_ctx (version, value1_prop_id, value2_prop_id, value3_prop_id, prop1_id) + values (#version#, #value1PropId#, #value2PropId#, #value3PropId#, #propertyId#) + + + insert into alf_prop_unique_ctx (id, version, value1_prop_id, value2_prop_id, value3_prop_id, prop1_id) + values (#id#, #version#, #value1PropId#, #value2PropId#, #value3PropId#, #propertyId#) @@ -353,7 +358,7 @@ from alf_prop_value pv left join alf_prop_double_value dv on (dv.id = pv.long_value and pv.persisted_type = 2) - left join alf_prop_string_value sv on (sv.id = pv.long_value and (pv.persisted_type = 3 OR pv.persisted_type = 5)) + left join alf_prop_string_value sv on (sv.id = pv.long_value and (pv.persisted_type = 3 OR pv.persisted_type = 5 OR pv.persisted_type = 6)) left join alf_prop_serializable_value serv on (serv.id = pv.long_value and pv.persisted_type = 4) where pv.id = #id# @@ -377,7 +382,7 @@ alf_prop_link pl join alf_prop_value pv on (pl.value_prop_id = pv.id) left join alf_prop_double_value dv on (dv.id = pv.long_value and pv.persisted_type = 2) - left join alf_prop_string_value sv on (sv.id = pv.long_value and (pv.persisted_type = 3 OR pv.persisted_type = 5)) + left join alf_prop_string_value sv on (sv.id = pv.long_value and (pv.persisted_type = 3 OR pv.persisted_type = 5 OR pv.persisted_type = 6)) left join alf_prop_serializable_value serv on (serv.id = pv.long_value and pv.persisted_type = 4) where pl.root_prop_id = #id# @@ -402,7 +407,7 @@ alf_prop_link pl join alf_prop_value pv on (pl.value_prop_id = pv.id) left join alf_prop_double_value dv on (dv.id = pv.long_value and pv.persisted_type = 2) - left join alf_prop_string_value sv on (sv.id = pv.long_value and (pv.persisted_type = 3 OR pv.persisted_type = 5)) + left join alf_prop_string_value sv on (sv.id = pv.long_value and (pv.persisted_type = 3 OR pv.persisted_type = 5 OR pv.persisted_type = 6)) left join alf_prop_serializable_value serv on (serv.id = pv.long_value and pv.persisted_type = 4) @@ -466,7 +471,8 @@ version, value1_prop_id, value2_prop_id, - value3_prop_id + value3_prop_id, + prop1_id from alf_prop_unique_ctx where @@ -479,13 +485,18 @@ version, value1_prop_id, value2_prop_id, - value3_prop_id + value3_prop_id, + prop1_id from alf_prop_unique_ctx where - value1_prop_id = #value1PropId# and - value2_prop_id = #value2PropId# and - value3_prop_id = #value3PropId# + value1_prop_id = #value1PropId# + + and value2_prop_id = #value2PropId# + + + and value3_prop_id = #value3PropId# + @@ -495,7 +506,8 @@ version = #version#, value1_prop_id = #value1PropId#, value2_prop_id = #value2PropId#, - value3_prop_id = #value3PropId# + value3_prop_id = #value3PropId#, + prop1_id = #propertyId# where id = #id# diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/qname-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/qname-common-SqlMap.xml index 501c9dfd07..ffa7cffb67 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/qname-common-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/qname-common-SqlMap.xml @@ -54,7 +54,6 @@ insert into alf_namespace (version, uri) values (#version#, #uri#) - insert into alf_namespace (id, version, uri) values (#id#, #version#, #uri#) @@ -64,7 +63,6 @@ insert into alf_qname (version, ns_id, local_name) values (#version#, #namespaceId#, #localName#) - insert into alf_qname (id, version, ns_id, local_name) values (#id#, #version#, #namespaceId#, #localName#) diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/usage-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/usage-common-SqlMap.xml new file mode 100644 index 0000000000..470b96e33b --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/usage-common-SqlMap.xml @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + insert into alf_usage_delta + (version, node_id, delta_size) + values + (#version#, #nodeId#, #deltaSize#) + + + + insert into alf_usage_delta + (id, version, node_id, delta_size) + values + (#id#, #version#, #nodeId#, #deltaSize#) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + delete + from + alf_usage_delta + where + node_id = ? + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/activities-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/activities-insert-SqlMap.xml index 14a07b3b1e..4c52003ad4 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/activities-insert-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/activities-insert-SqlMap.xml @@ -7,36 +7,27 @@ - - insert into alf_activity_feed_control (feed_user_id, site_network, app_tool, last_modified) - values (#feedUserId#, #siteNetwork#, #appTool#, #lastModified#) - + KEY_COLUMN:GENERATED_KEY - + - - insert into alf_activity_feed (activity_type, activity_summary, activity_format, feed_user_id, post_user_id, post_date, post_id, site_network, app_tool, feed_date) - values (#activityType#, #activitySummary#, #activitySummaryFormat#, #feedUserId#, #postUserId#, #postDate#, #postId#, #siteNetwork#, #appTool#, #feedDate#) - + KEY_COLUMN:GENERATED_KEY - + - - insert into alf_activity_post (status, activity_data, post_user_id, post_date, activity_type, site_network, app_tool, job_task_node, last_modified) - values (#status#, #activityData#, #userId#, #postDate#, #activityType#, #siteNetwork#, #appTool#, #jobTaskNode#, #lastModified#) - + KEY_COLUMN:GENERATED_KEY - + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/locale-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/locale-insert-SqlMap.xml new file mode 100644 index 0000000000..df0b516cf3 --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/locale-insert-SqlMap.xml @@ -0,0 +1,16 @@ + + + + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/node-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/node-insert-SqlMap.xml new file mode 100644 index 0000000000..e209fcc8ab --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/node-insert-SqlMap.xml @@ -0,0 +1,51 @@ + + + + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/node-update-acl-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/node-update-acl-SqlMap.xml new file mode 100644 index 0000000000..f441ba13d5 --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/node-update-acl-SqlMap.xml @@ -0,0 +1,27 @@ + + + + + + + + + update + alf_child_assoc assoc + join alf_node child on (child.id = assoc.child_node_id and assoc.is_primary = #isPrimary#) + set + child.acl_id = #newSharedAclId# + where + assoc.parent_node_id = #primaryParentNodeId# + and + ( + child.acl_id is null + OR child.acl_id = #optionalOldSharedAclIdInAdditionToNull# + ) + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/permissions-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/permissions-insert-SqlMap.xml new file mode 100644 index 0000000000..766ad31ca9 --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/permissions-insert-SqlMap.xml @@ -0,0 +1,65 @@ + + + + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/usage-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/usage-insert-SqlMap.xml new file mode 100644 index 0000000000..c9b23ee8ab --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.MySQLInnoDBDialect/usage-insert-SqlMap.xml @@ -0,0 +1,16 @@ + + + + + + + + + + KEY_COLUMN:GENERATED_KEY + + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/activities-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/activities-insert-SqlMap.xml index 9e8df5f455..f7136dacba 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/activities-insert-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/activities-insert-SqlMap.xml @@ -7,36 +7,33 @@ - + select nextVal('alf_activity_feed_control_seq') - insert into alf_activity_feed_control (id, feed_user_id, site_network, app_tool, last_modified) - values (#id#, #feedUserId#, #siteNetwork#, #appTool#, #lastModified#) + - + select nextVal('alf_activity_feed_seq') - insert into alf_activity_feed (id, activity_type, activity_summary, activity_format, feed_user_id, post_user_id, post_date, post_id, site_network, app_tool, feed_date) - values (#id#, #activityType#, #activitySummary#, #activitySummaryFormat#, #feedUserId#, #postUserId#, #postDate#, #postId#, #siteNetwork#, #appTool#, #feedDate#) - + + - + select nextVal('alf_activity_post_seq') - insert into alf_activity_post (sequence_id, status, activity_data, post_user_id, post_date, activity_type, site_network, app_tool, job_task_node, last_modified) - values (#id#, #status#, #activityData#, #userId#, #postDate#, #activityType#, #siteNetwork#, #appTool#, #jobTaskNode#, #lastModified#) + - + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/avm-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/avm-insert-SqlMap.xml index 609eebedb5..90b210c2d5 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/avm-insert-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/avm-insert-SqlMap.xml @@ -4,49 +4,45 @@ PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> - - + + - select nextVal('hibernate_sequence') + select nextVal('avm_stores_seq') - insert into avm_stores (id, next_version_id, name, vers, current_root_id, acl_id) - values (#id#, #version#, #name#, 0, null, null) + - select nextVal('hibernate_sequence') + select nextVal('avm_store_properties_seq') - insert into avm_store_properties (id, actual_type_n, persisted_type_n, multi_valued, boolean_value, long_value, float_value, double_value, string_value, serializable_value, avm_store_id, qname_id) - values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + - select nextVal('hibernate_sequence') + select nextVal('avm_nodes_seq') - insert into avm_nodes (id, class_type, deletedType, version_id, vers, store_new_id, acl_id, guid, owner, creator, createDate, lastModifier, modDate, accessDate, is_root, layer_id, indirection, indirection_version, primary_indirection, opacity, content_url, mime_type, encoding, length) - values (#id#, #classType#, #deletedType#, #version#, 0, #storeNewId#, #aclId#, #guid#, #owner#, #creator#, #createdDate#, #modifier#, #modifiedDate#, #accessDate#, #isRoot#, #layerId#, #indirection#, #indirectionVersion#, #primaryIndirection#, #opacity#, #contentUrl#, #mimetype#, #encoding#, #length#) + - select nextVal('hibernate_sequence') + select nextVal('avm_version_roots_seq') - insert into avm_version_roots (id, avm_store_id, root_id, version_id, creator, create_date, tag, description) - values (#id#, #storeId#, #rootNodeId#, #version#, #creator#, #createdDate#, #tag#, #description#) + diff --git a/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/locale-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/locale-insert-SqlMap.xml new file mode 100755 index 0000000000..ca925215ee --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/locale-insert-SqlMap.xml @@ -0,0 +1,18 @@ + + + + + + + + + select nextVal('alf_locale_seq') + + + insert into alf_locale (id, version, locale_str) + values (#id#, #version#, #localeStr#) + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/node-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/node-insert-SqlMap.xml new file mode 100755 index 0000000000..4a3c7790c0 --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/node-insert-SqlMap.xml @@ -0,0 +1,58 @@ + + + + + + + + + select nextVal('alf_server_seq') + + + + + + + + select nextVal('alf_store_seq') + + + + + + + + select nextVal('alf_node_seq') + + + + + + + + select nextVal('alf_transaction_seq') + + + + + + + + select nextVal('alf_node_assoc_seq') + + + + + + + + select nextVal('alf_child_assoc_seq') + + + + + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/permissions-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/permissions-insert-SqlMap.xml new file mode 100755 index 0000000000..f4ab268866 --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/permissions-insert-SqlMap.xml @@ -0,0 +1,81 @@ + + + + + + + + + select nextVal('alf_access_control_list_seq') + + + + + + + + + select nextVal('alf_acl_member_seq') + + + + + + + + + select nextVal('alf_acl_change_set_seq') + + + + + + + + + select nextVal('alf_access_control_entry_seq') + + + + + + + + + select nextVal('alf_ace_context_seq') + + + + + + + + + select nextVal('alf_permission_seq') + + + + + + + + + select nextVal('alf_authority_seq') + + + + + + + + + select nextVal('alf_authority_alias_seq') + + + + + + + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/propval-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/propval-insert-SqlMap.xml index eda9c88559..c6ae2afa67 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/propval-insert-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/propval-insert-SqlMap.xml @@ -64,18 +64,14 @@ select nextVal('alf_prop_root_seq') - + - select nextVal('alf_prop_unique_ctx_seq') - - insert into alf_prop_unique_ctx (id, version, value1_prop_id, value2_prop_id, value3_prop_id) - values (#id#, #version#, #value1PropId#, #value2PropId#, #value3PropId#) - + \ No newline at end of file diff --git a/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/usage-insert-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/usage-insert-SqlMap.xml new file mode 100755 index 0000000000..e07a958d7e --- /dev/null +++ b/config/alfresco/ibatis/org.hibernate.dialect.PostgreSQLDialect/usage-insert-SqlMap.xml @@ -0,0 +1,17 @@ + + + + + + + + + select nextVal('alf_usage_delta_seq') + + + + + + \ No newline at end of file diff --git a/config/alfresco/index-recovery-context.xml b/config/alfresco/index-recovery-context.xml index c4053ddfc8..4f27fc81da 100644 --- a/config/alfresco/index-recovery-context.xml +++ b/config/alfresco/index-recovery-context.xml @@ -40,8 +40,8 @@ - - + + diff --git a/config/alfresco/messages/action-config.properties b/config/alfresco/messages/action-config.properties index c833551b29..45eecbcba7 100644 --- a/config/alfresco/messages/action-config.properties +++ b/config/alfresco/messages/action-config.properties @@ -220,11 +220,6 @@ start-avm-workflow.workflow-name.display-label=The name of the WCM workflow to i copy-to-web-project.title=Copy item to a folder in a web project copy-to-web-project.description=This will copy the matched item to a folder in a web project. -avm-link-validation.title=Performs a link validation check. -avm-link-validation.description=Performs a link validation check. -avm-link-validation.monitor.display-label=The status object used to determine progress -avm-link-validation.compare-to-staging.display-label=Determines whether the link check should use the corresponding staging area for comparison - create-version.title=Creates new version create-version.description=Creates a new version create-version.description.display-label=Version description diff --git a/config/alfresco/messages/avm-messages.properties b/config/alfresco/messages/avm-messages.properties index 2b9ce2d3fd..311f9966c5 100644 --- a/config/alfresco/messages/avm-messages.properties +++ b/config/alfresco/messages/avm-messages.properties @@ -1,5 +1,5 @@ # AVM related messages expiredcontent.workflow.title=Expired Content In ''{0}'' -avmlockservice.locked=You do not have access to the item at path {0} it is currently locked by another user {1}. +avmlockservice.locked=You do not have access to ''{0}''; it is currently locked by user ''{1}''. testserver.taken=The test server ''{0}'' you selected has been allocated to another user, if possible, select a different server and try again. \ No newline at end of file diff --git a/config/alfresco/messages/linkvalidation-messages.properties b/config/alfresco/messages/linkvalidation-messages.properties deleted file mode 100644 index d03600c039..0000000000 --- a/config/alfresco/messages/linkvalidation-messages.properties +++ /dev/null @@ -1,3 +0,0 @@ -# Link Validation related messages - -linkvalidation.disabled=Link validation not performed - currently disabled \ No newline at end of file diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties index 0984ad2ea2..adc93c6ca2 100644 --- a/config/alfresco/messages/patch-service.properties +++ b/config/alfresco/messages/patch-service.properties @@ -187,9 +187,6 @@ patch.genericWorkflow.result.deployed=Re-deployed {0} workflows. patch.redeploySubmitProcess.description=Re-deploy WCM Submit Process Definition. patch.deploySubmitDirectProcess.description=Deploy WCM Direct Submit Process Definition. -patch.AVMLocking.description=Adds existing web projects to locking service. -patch.AVMLocking.result=Necessary web projects added. - patch.AVMAspects.description=Changes storage of aspects on AVM Nodes. patch.AVMAspects.result=Aspects were moved. @@ -339,8 +336,8 @@ patch.convertContentUrls.store.done=This job is complete. Deactivate the schedu patch.fixAuthoritiesCrcValues.description=Fixes authority CRC32 values to match UTF-8 encoding. patch.fixAuthoritiesCrcValues.result=Fixed CRC32 values for UTF-8 encoding for {0} authorities. See file {1} for details. -patch.fixAuthoritiesCrcValues.fixed=Updated CRC32 values for authority ID {0}, authority ''{1}'': {2} -> {3}. -patch.fixAuthoritiesCrcValues.unableToChange=Failed to update the CRC32 value for authority ID {0}: \n Authority: {1} \n authority CRC old: {2} \n authority CRC new: {3} \n Error: {4} +patch.fixAuthoritiesCrcValues.fixed=Updated CRC32 values for authority '{0}'. +patch.fixAuthoritiesCrcValues.unableToChange=Failed to update the CRC32 value for authority: \n Authority: {0} \n Error: {1} patch.updateMimetypes1.description=Fix mimetypes for Excel and Powerpoint. diff --git a/config/alfresco/model/systemModel.xml b/config/alfresco/model/systemModel.xml index 75d16dd404..e19043e250 100644 --- a/config/alfresco/model/systemModel.xml +++ b/config/alfresco/model/systemModel.xml @@ -225,15 +225,6 @@ - - - Cascade Index Children - - \ No newline at end of file diff --git a/config/alfresco/node-services-context.xml b/config/alfresco/node-services-context.xml index 36c149166d..089230a65a 100644 --- a/config/alfresco/node-services-context.xml +++ b/config/alfresco/node-services-context.xml @@ -195,13 +195,10 @@ - - + + - @@ -218,8 +215,11 @@ - - + + + + + diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index 8b273996d2..1eb2039b0d 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -145,11 +145,8 @@ 2 3 - - - - - + + @@ -172,15 +169,14 @@ - + patch.fixNodeSerializableValues patch.fixNodeSerializableValues.description 0 3 4 - - - + + 3.2 @@ -190,11 +186,8 @@ 5 6 - - - - - + + @@ -261,11 +254,8 @@ 0 6 7 - - - - - + + @@ -448,14 +438,14 @@ - + patch.schemaUpdateScript-V1.4-1 patch.schemaUpgradeScript.description 0 19 20 - - classpath:alfresco/dbscripts/upgrade/1.4/${db.script.dialect}/AlfrescoSchemaUpdate-1.4-1.sql + + 3.3.x @@ -468,20 +458,14 @@ 2.1.4 - + patch.schemaUpdateScript-V1.4-2 patch.schemaUpgradeScript.description 0 20 21 - - classpath:alfresco/dbscripts/upgrade/1.4/${db.script.dialect}/AlfrescoSchemaUpdate-1.4-2.sql - - - - - - + + 3.3.x @@ -494,9 +478,6 @@ - - - patch.systemDescriptorContent @@ -553,9 +534,6 @@ - - - @@ -673,7 +651,7 @@ - + @@ -723,7 +701,7 @@ - + @@ -761,17 +739,6 @@ - - patch.AVMLocking - patch.AVMLocking.description - 0 - 58 - 59 - - - - - patch.ReadmeTemplate patch.ReadmeTemplate.description @@ -996,20 +963,14 @@ - + patch.db-V1.4-TxnCommitTimeIndex patch.schemaUpgradeScript.description 0 110 111 - - classpath:alfresco/dbscripts/upgrade/1.4/${db.script.dialect}/AlfrescoSchemaUpdate-1.4-TxnCommitTimeIndex.sql - - - - - - + + 3.3.x @@ -1148,11 +1109,8 @@ 119 120 - - - - - + + @@ -1282,10 +1240,10 @@ 125 - + - - + + @@ -1296,7 +1254,7 @@ 125 126 - classpath:alfresco/dbscripts/create/3.0/${db.script.dialect}/create-activities-extras.sql + classpath:alfresco/dbscripts/upgrade/3.0/${db.script.dialect}/create-activities-extras.sql @@ -1528,9 +1486,6 @@ 0 2001 2002 - - - @@ -1543,8 +1498,17 @@ - - + + + + + + + + + + + ContentManager @@ -1561,7 +1525,7 @@ - + patch.wcmPostPermissionSnapshotPatch3 @@ -1569,15 +1533,15 @@ 0 2001 2002 - + - - + + @@ -1785,7 +1749,7 @@ 2011 - classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-LockTables.sql + classpath:alfresco/dbscripts/create/${db.script.dialect}/AlfrescoCreate-LockTables.sql @@ -1870,7 +1834,7 @@ 2016 - classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-ContentTables.sql + classpath:alfresco/dbscripts/create/${db.script.dialect}/AlfrescoCreate-ContentTables.sql @@ -1924,7 +1888,7 @@ 3001 - classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-PropertyValueTables.sql + classpath:alfresco/dbscripts/create/${db.script.dialect}/AlfrescoCreate-PropertyValueTables.sql @@ -1936,7 +1900,7 @@ 3002 - classpath:alfresco/dbscripts/create/3.2/${db.script.dialect}/AlfrescoPostCreate-3.2-AuditTables.sql + classpath:alfresco/dbscripts/create/${db.script.dialect}/AlfrescoCreate-AuditTables.sql @@ -1959,8 +1923,8 @@ 3004 3005 - - + + ${spaces.store} @@ -1997,8 +1961,8 @@ - - + + @@ -2153,9 +2117,6 @@ - - - @@ -2179,17 +2140,6 @@ - - patch.db-V3.3-Fix-Repo-Seqs_1 - patch.schemaUpgradeScript.description - 0 - 4007 - 4008 - - classpath:alfresco/dbscripts/upgrade/3.3/${db.script.dialect}/fix-Repo-seqs_1.sql - - - patch.fixAuthoritiesCrcValues patch.fixAuthoritiesCrcValues.description @@ -2197,15 +2147,15 @@ 4100 4101 false - - + + + + + - - - @@ -2261,7 +2211,46 @@ 4103 4104 - classpath:alfresco/dbscripts/create/2.2/${db.script.dialect}/AlfrescoPostCreate-2.2-MappedFKIndexes.sql + classpath:alfresco/dbscripts/upgrade/2.2/${db.script.dialect}/AddFKIndexes.sql + + + patch.db-V3.3-Fix-Repo-Seqs + patch.schemaUpgradeScript.description + 0 + 4104 + 4105 + + classpath:alfresco/dbscripts/upgrade/3.3/${db.script.dialect}/fix-Repo-seqs.sql + + + + + patch.db-V3.3-Fix-AVM-Seqs + patch.schemaUpgradeScript.description + 0 + 4104 + 4105 + + classpath:alfresco/dbscripts/upgrade/3.3/${db.script.dialect}/fix-AVM-seqs.sql + + + + + patch.db-V3.3-property-unique-ctx-value + patch.schemaUpgradeScript.description + 0 + 4104 + 4105 + + classpath:alfresco/dbscripts/upgrade/3.3/${db.script.dialect}/property-unique-ctx-value.sql + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/public-services-context.xml b/config/alfresco/public-services-context.xml index 21390c983b..14a6c099bc 100644 --- a/config/alfresco/public-services-context.xml +++ b/config/alfresco/public-services-context.xml @@ -1097,12 +1097,9 @@ + exists getAttribute getAttributes - query - getKeys - exists - getCount @@ -1115,11 +1112,10 @@ setAttribute - setAttributes + createAttribute + updateOrCreateAttribute removeAttribute - addAttribute - addAttributes - removeEntries + removeAttributes @@ -1150,11 +1146,8 @@ - getLock - getUsersLocks - getWebProjectLocks - getWebProjects - getStoreLocks + getLockOwner + getLockState hasAccess @@ -1166,13 +1159,10 @@ - addWebProject - lockPath - removeLock - removeWebProject + lock modifyLock - removeStoreLocks - removeLocksInDirectory + removeLock + removeLocks @@ -1401,63 +1391,6 @@ - - - - - - - - - getHrefManifest - getBrokenHrefManifest - getHrefDifference - getHrefManifestBrokenByNewOrMod - getHrefsDependentUponFile - getPollInterval - isLinkValidationDisabled - - - - - - - - - - - - onBootstrap - onShutdown - setLinkValidationDisabled - updateHrefInfo - - - - - - - - org.alfresco.linkvalidation.LinkValidationService - - - - linkValidationService - - - - linkValidationServiceWriteTxnAdvisor - linkValidationServiceReadTxnAdvisor - checkTxnAdvisor - - - - - diff --git a/config/alfresco/public-services-security-context.xml b/config/alfresco/public-services-security-context.xml index 26ae0c5e69..49e73ab26f 100644 --- a/config/alfresco/public-services-security-context.xml +++ b/config/alfresco/public-services-security-context.xml @@ -80,8 +80,8 @@ - - + + diff --git a/config/alfresco/remote-services-context.xml b/config/alfresco/remote-services-context.xml index 9c79f21a09..35504e9fee 100644 --- a/config/alfresco/remote-services-context.xml +++ b/config/alfresco/remote-services-context.xml @@ -1,236 +1,204 @@ - - - - - - - - - ${avm.remote.idlestream.timeout} - - - - - - - - - - - - - - - - - - org.alfresco.service.cmr.remote.AVMRemoteTransport - - - avm - - - ${alfresco.rmi.services.port} - - - ${avm.rmi.service.port} - - - ${alfresco.rmi.services.host} - - - - - - - - - - - - - - - - - - org.alfresco.service.cmr.remote.AVMSyncServiceTransport - - - avmsync - - - ${alfresco.rmi.services.port} - - - ${alfresco.rmi.services.host} - - - ${avmsync.rmi.service.port} - - - - - - - - - - - - - - - - - - - org.alfresco.service.cmr.remote.AttributeServiceTransport - - - attributes - - - ${alfresco.rmi.services.port} - - - ${alfresco.rmi.services.host} - - - ${attribute.rmi.service.port} - - - - - - - - - - org.alfresco.service.cmr.security.AuthenticationService - - - authentication - - - ${alfresco.rmi.services.port} - - - ${alfresco.rmi.services.host} - - - ${authentication.rmi.service.port} - - - - - - - - - - - - - - - - - - - - org.alfresco.service.cmr.remote.RepoRemote - - - - - - - - - - ${server.transaction.mode.default} - ${server.transaction.mode.readOnly} - ${server.transaction.mode.readOnly} - ${server.transaction.mode.readOnly} - ${server.transaction.mode.default} - ${server.transaction.mode.default} - ${server.transaction.mode.default} - - - - - - - - - - - - - - 30000 - - - - - - - - - - org.alfresco.service.cmr.remote.RepoRemoteTransport - - - repo - - - ${alfresco.rmi.services.port} - - - ${alfresco.rmi.services.host} - - - ${repo.rmi.service.port} - - - - - - - - - - - - - - - - - - - - org.alfresco.service.cmr.action.ActionServiceTransport - - - action - - - ${alfresco.rmi.services.port} - - - ${alfresco.rmi.services.host} - - - ${action.rmi.service.port} - - + + + + + + + + + ${avm.remote.idlestream.timeout} + + + + + + + + + + + + + + + + + + org.alfresco.service.cmr.remote.AVMRemoteTransport + + + avm + + + ${alfresco.rmi.services.port} + + + ${avm.rmi.service.port} + + + ${alfresco.rmi.services.host} + + + + + + + + + + + + + + + + + + org.alfresco.service.cmr.remote.AVMSyncServiceTransport + + + avmsync + + + ${alfresco.rmi.services.port} + + + ${alfresco.rmi.services.host} + + + ${avmsync.rmi.service.port} + + + + + + + + + + org.alfresco.service.cmr.security.AuthenticationService + + + authentication + + + ${alfresco.rmi.services.port} + + + ${alfresco.rmi.services.host} + + + ${authentication.rmi.service.port} + + + + + + + + + + + + + + + + + + + + org.alfresco.service.cmr.remote.RepoRemote + + + + + + + + + + ${server.transaction.mode.default} + ${server.transaction.mode.readOnly} + ${server.transaction.mode.readOnly} + ${server.transaction.mode.readOnly} + ${server.transaction.mode.default} + ${server.transaction.mode.default} + ${server.transaction.mode.default} + + + + + + + + + + + + + + 30000 + + + + + + + + + + org.alfresco.service.cmr.remote.RepoRemoteTransport + + + repo + + + ${alfresco.rmi.services.port} + + + ${alfresco.rmi.services.host} + + + ${repo.rmi.service.port} + + + + + + + + + + + + + + + + + + + + org.alfresco.service.cmr.action.ActionServiceTransport + + + action + + + ${alfresco.rmi.services.port} + + + ${alfresco.rmi.services.host} + + + ${action.rmi.service.port} + + \ No newline at end of file diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties index 39909c0ed6..c70e28b25c 100644 --- a/config/alfresco/repository.properties +++ b/config/alfresco/repository.properties @@ -363,28 +363,9 @@ domain.separator= # AVM Specific properties. avm.remote.idlestream.timeout=30000 - #Format caption extracted from the XML Schema. xforms.formatCaption=true -# ################################## # -# WCM Link Validation Configuration # -# ################################## # -# -# Note: Link Validation is disabled by default (as per poll interval = 0) -# -# linkvalidation.pollInterval - Poll interval to check getLatestSnapshotID (in milliseconds), eg. 5000 for 5 sec interval -# If pollInterval is 0, link validation is disabled. -# -# linkvalidation.retryInterval - Retry interval (Virtualization server is not accessible or an error has occurred -# during link validation. -# -# linkvalidation.disableOnFail - If set to TRUE link validation service will be terminated if an error will be occurred. - -linkvalidation.pollInterval=0 -linkvalidation.retryInterval=120000 -linkvalidation.disableOnFail=false - # ECM content usages/quotas system.usages.enabled=true @@ -413,7 +394,6 @@ home.folder.creation.eager=true # avm.rmi.service.port=50501 avmsync.rmi.service.port=50502 -attribute.rmi.service.port=50503 authentication.rmi.service.port=50504 repo.rmi.service.port=50505 action.rmi.service.port=50506 diff --git a/config/alfresco/usage-services-context.xml b/config/alfresco/usage-services-context.xml index 632071fdf4..b4baac32e0 100644 --- a/config/alfresco/usage-services-context.xml +++ b/config/alfresco/usage-services-context.xml @@ -16,7 +16,7 @@ - + diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties index 924b776d01..920dd97f51 100644 --- a/config/alfresco/version.properties +++ b/config/alfresco/version.properties @@ -19,4 +19,4 @@ version.build=@build-number@ # Schema number -version.schema=4104 +version.schema=4105 diff --git a/config/alfresco/wcm-services-context.xml b/config/alfresco/wcm-services-context.xml index 6b4b24ebf2..74b56d21b1 100644 --- a/config/alfresco/wcm-services-context.xml +++ b/config/alfresco/wcm-services-context.xml @@ -47,7 +47,6 @@ - @@ -55,6 +54,7 @@ + @@ -217,9 +217,9 @@ - + diff --git a/config/alfresco/workflow/submit_processdefinition.xml b/config/alfresco/workflow/submit_processdefinition.xml index fefb5d1585..b02489ee46 100644 --- a/config/alfresco/workflow/submit_processdefinition.xml +++ b/config/alfresco/workflow/submit_processdefinition.xml @@ -26,31 +26,8 @@ - - #{wcmwf_validateLinks != null && wcmwf_validateLinks == true} - - - - - - - - - - - - #{wcmwf_brokenLinks == 0} - - - - - - - - - @@ -108,7 +85,7 @@ - + @@ -144,7 +121,7 @@ - + @@ -280,7 +257,7 @@ - + diff --git a/config/alfresco/workflow/wcm-workflow-messages.properties b/config/alfresco/workflow/wcm-workflow-messages.properties index c8d9a9a292..f2f6097ef1 100644 --- a/config/alfresco/workflow/wcm-workflow-messages.properties +++ b/config/alfresco/workflow/wcm-workflow-messages.properties @@ -70,8 +70,6 @@ wcmwf_workflowmodel.property.wcmwf_launchDate.title=Launch Date wcmwf_workflowmodel.property.wcmwf_launchDate.description=Date the content in the submission should be committed wcmwf_workflowmodel.property.wcmwf_autoDeploy.title=Auto Deploy wcmwf_workflowmodel.property.wcmwf_autoDeploy.description=Whether the submitted changes should be deployed upon approval -wcmwf_workflowmodel.property.wcmwf_validateLinks.title=Validate Links -wcmwf_workflowmodel.property.wcmwf_validateLinks.description=Whether links should be verified before entering the review cycle wcmwf_workflowmodel.property.wcmwf_webapp.title=Webapp wcmwf_workflowmodel.property.wcmwf_webapp.description=The webapp within the workflow store to check links for wcmwf_workflowmodel.property.wcmwf_reviewerCnt.title=Total Reviewed diff --git a/config/alfresco/workflow/wcmWorkflowModel.xml b/config/alfresco/workflow/wcmWorkflowModel.xml index fe08771e35..3c773e12fd 100644 --- a/config/alfresco/workflow/wcmWorkflowModel.xml +++ b/config/alfresco/workflow/wcmWorkflowModel.xml @@ -104,22 +104,22 @@ wcmwf:reviewType - - - wcmwf:workflowTask - - - review_wcm_package_item_actions - - - - - - bpm:assignees - wcmwf:submission - wcmwf:reviewType - - + + + wcmwf:workflowTask + + + review_wcm_package_item_actions + + + + + + bpm:assignees + wcmwf:submission + wcmwf:reviewType + + wcmwf:workflowTask @@ -281,19 +281,19 @@ - Validate Links - Determines whether links should be verified before entering the review cycle + Validate Links (Deprecated) + Deprecated d:boolean Webapp The webapp within the workflow store to check links for d:text - - - Auto Deploy - Determines whether the changes should be deployed upon submission - d:boolean + + + Auto Deploy + Determines whether the changes should be deployed upon submission + d:boolean diff --git a/source/java/org/alfresco/cmis/mapping/CMISPropertyServiceTest.java b/source/java/org/alfresco/cmis/mapping/CMISPropertyServiceTest.java index 8daa7eafc9..f1d1a874ff 100644 --- a/source/java/org/alfresco/cmis/mapping/CMISPropertyServiceTest.java +++ b/source/java/org/alfresco/cmis/mapping/CMISPropertyServiceTest.java @@ -97,7 +97,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); // we don't unnecessarily guess/store (see FileFolderService.createImpl) assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); assertNull(properties.get(CMISDictionaryModel.PROP_ALLOWED_CHILD_OBJECT_TYPE_IDS)); @@ -130,7 +130,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -181,7 +181,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -226,7 +226,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); // we don't unnecessarily guess/store (see FileFolderService.createImpl) assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -260,7 +260,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -304,7 +304,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), pwc.toString()); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent (Working Copy)"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -335,7 +335,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -379,7 +379,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), pwc.toString()); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent (Working Copy)"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -410,7 +410,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -444,7 +444,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -475,7 +475,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -519,7 +519,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), pwc.toString()); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent (Working Copy)"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -550,7 +550,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -594,7 +594,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), pwc.toString()); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent (Working Copy)"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -626,7 +626,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_BY), null); assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -669,7 +669,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), pwc.toString()); assertEquals(properties.get(CMISDictionaryModel.PROP_CHECKIN_COMMENT), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent (Working Copy)"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); @@ -701,7 +701,7 @@ public class CMISPropertyServiceTest extends BaseCMISTest assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_BY), null); assertEquals(properties.get(CMISDictionaryModel.PROP_VERSION_SERIES_CHECKED_OUT_ID), null); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_LENGTH), 0L); - assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), "application/octet-stream"); + assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_MIME_TYPE), ""); assertEquals(properties.get(CMISDictionaryModel.PROP_CONTENT_STREAM_FILENAME), "BaseContent"); assertNull(properties.get(CMISDictionaryModel.PROP_PARENT_ID)); diff --git a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java index 4f2181c836..a92db7ccd9 100644 --- a/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java +++ b/source/java/org/alfresco/filesys/repo/ContentNetworkFile.java @@ -40,6 +40,7 @@ import org.alfresco.jlan.smb.SeekType; import org.alfresco.jlan.smb.server.SMBSrvSession; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.AbstractContentReader; +import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.encoding.ContentCharsetFinder; import org.alfresco.repo.content.filestore.FileContentReader; import org.alfresco.repo.security.authentication.AuthenticationUtil; @@ -411,10 +412,18 @@ public class ContentNetworkFile extends NodeRefNetworkFile if (modified) { + NodeRef contentNodeRef = getNodeRef(); // We may be in a retry block, in which case this section will already have executed and channel will be null if (channel != null) { - // Take a guess at the mimetype + // Take a guess at the mimetype (if it has not been set by something already) + if (content.getMimetype() == null || content.getMimetype().equals(MimetypeMap.MIMETYPE_BINARY) ) + { + String filename = (String) nodeService.getProperty(contentNodeRef, ContentModel.PROP_NAME); + String mimetype = mimetypeService.guessMimetype(filename); + content.setMimetype(mimetype); + } + // Take a guess at the locale channel.position(0); InputStream is = new BufferedInputStream(Channels.newInputStream(channel)); ContentCharsetFinder charsetFinder = mimetypeService.getContentCharsetFinder(); @@ -451,7 +460,6 @@ public class ContentNetworkFile extends NodeRefNetworkFile if (contentChanged) { - NodeRef contentNodeRef = getNodeRef(); nodeService.removeAspect(contentNodeRef, ContentModel.ASPECT_NO_CONTENT); try { diff --git a/source/java/org/alfresco/linkvalidation/HrefConcordanceEntry.java b/source/java/org/alfresco/linkvalidation/HrefConcordanceEntry.java deleted file mode 100644 index bfccd60fd8..0000000000 --- a/source/java/org/alfresco/linkvalidation/HrefConcordanceEntry.java +++ /dev/null @@ -1,61 +0,0 @@ -/*----------------------------------------------------------------------------- -* Copyright 2007-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . -* -* -* Author Jon Cox -* File HrefConcordanceEntry.java -*----------------------------------------------------------------------------*/ - -package org.alfresco.linkvalidation; - -import java.io.Serializable; - -/** -* Contains every location of a given href within a webapp, -* along with its response status. -*/ -public class HrefConcordanceEntry - implements Comparable, - Serializable -{ - static final long serialVersionUID = -8102602003366089726L; - - String href_; - String [] locations_; - int response_status_; - - public HrefConcordanceEntry( String href, - String [] locations, - int responseStatus - ) - { - href_ = href; - locations_ = locations; - response_status_ = responseStatus; - } - - public String getHref() { return href_; } - public String [] getLocations() { return locations_; } - public int getResponseStatus() { return response_status_; } - - public int compareTo(HrefConcordanceEntry other) - { - return href_.compareTo( other.href_ ); - } -} - diff --git a/source/java/org/alfresco/linkvalidation/HrefDifference.java b/source/java/org/alfresco/linkvalidation/HrefDifference.java deleted file mode 100644 index 4d6ff88f16..0000000000 --- a/source/java/org/alfresco/linkvalidation/HrefDifference.java +++ /dev/null @@ -1,121 +0,0 @@ -/*----------------------------------------------------------------------------- -* Copyright 2007-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . -* -* -* Author Jon Cox -* File HrefDifference.java -*----------------------------------------------------------------------------*/ - -package org.alfresco.linkvalidation; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class HrefDifference -{ - /** - * The href_status_map_ is a map of URLs the tuple of their - * return status & list of dependencies. - */ - protected HrefStatusMap href_status_map_; // status of links/maybe dep info - - /** - * The href_manifest_ contains a List objects. - * Each HrefManifestEntry contains a file name, - * and possibly a list of hrefs within that file. - */ - protected HrefManifest href_manifest_; - - // Lazily computed values - protected HrefManifest broken_in_newmod_; // errors in new files - protected HrefManifest broken_by_deletion_; // err via new deletions - - // Only computed when merging diffs - protected List repaired_by_delmod_; // fix by removing links - protected List repaired_by_new_; // file satisfied broken dep - - // Temp values used in lazy computation - protected HashMap> broken_manifest_map_; - protected HashMap deleted_file_md5_; - - - String href_attr_; // href attribute lookup prefix - - int src_version_; - String src_store_; - - int dst_base_version_; - int dst_latest_version_; - String dst_store_; - - String src_webapp_url_base_; - String dst_webapp_url_base_; - - HrefDifference(String href_attr, - int src_version, - String src_store, - int dst_base_version, - String dst_store, - int dst_latest_version, - String src_webapp_url_base, - String dst_webapp_url_base) - { - href_attr_ = href_attr; - - src_version_ = src_version; - src_store_ = src_store; - - dst_base_version_ = dst_base_version; - dst_store_ = dst_store; - - dst_latest_version_ = dst_latest_version; - - src_webapp_url_base_ = src_webapp_url_base; - dst_webapp_url_base_ = dst_webapp_url_base; - - href_manifest_ = new HrefManifest(); - href_status_map_ = new HrefStatusMap(); - - broken_manifest_map_ = new HashMap>(); - deleted_file_md5_ = new HashMap(); - } - - - public HrefManifest getHrefManifest() { return href_manifest_; } - public HrefStatusMap getHrefStatusMap() { return href_status_map_; } - public int getSrcVersion() { return src_version_;} - public int getDstBaseVersion() { return dst_base_version_;} - public int getDstLatestVersion() { return dst_latest_version_;} - - String getHrefAttr() { return href_attr_;} - String getSrcStore() { return src_store_;} - String getDstStore() { return dst_store_;} - String getSrcWebappUrlBase() { return src_webapp_url_base_; } - String getDstWebappUrlBase() { return dst_webapp_url_base_; } - - - Map getDeletedFileMd5() { return deleted_file_md5_; } - Map> getBrokenManifestMap() - { - return broken_manifest_map_; - } -} - diff --git a/source/java/org/alfresco/linkvalidation/HrefManifest.java b/source/java/org/alfresco/linkvalidation/HrefManifest.java deleted file mode 100644 index a9364cbdac..0000000000 --- a/source/java/org/alfresco/linkvalidation/HrefManifest.java +++ /dev/null @@ -1,73 +0,0 @@ -/*----------------------------------------------------------------------------- -* Copyright 2007-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . -* -* -* Author Jon Cox -* File HrefManifestEntry.java -*----------------------------------------------------------------------------*/ - -package org.alfresco.linkvalidation; - -import java.io.Serializable; -import java.util.List; -import java.util.ArrayList; - -/** -* Contains a (possibly filtered) list of the hrefs within a file. -* Common uses of this class are to fetch the links in a web page -* or just the broken ones (i.e.: response status 400-599). -*/ -public class HrefManifest -{ - List manifest_entries_; - int base_snapshot_version_; - int latest_snapshot_version_; - int base_file_count_; - int base_link_count_; - - public HrefManifest() - { - manifest_entries_ = new ArrayList(); - } - - public HrefManifest(List entries, - int base_snapshot_version, - int latest_snapshot_version, - int base_file_count, - int base_link_count) - { - manifest_entries_ = entries; - base_snapshot_version_ = base_snapshot_version; - latest_snapshot_version_ = latest_snapshot_version; - base_file_count_ = base_file_count; - base_link_count_ = base_link_count; - } - - public int getLatestSnapshotVersion() { return latest_snapshot_version_; } - public int getBaseSnapshotVersion() { return base_snapshot_version_; } - - public int getBaseFileCount() { return base_file_count_;} - public int getBaseLinkCount() { return base_link_count_;} - - public List getManifestEntries() { return manifest_entries_;} - - synchronized void add( HrefManifestEntry entry ) - { - manifest_entries_.add( entry ); - } -} diff --git a/source/java/org/alfresco/linkvalidation/HrefManifestEntry.java b/source/java/org/alfresco/linkvalidation/HrefManifestEntry.java deleted file mode 100644 index 8a28874254..0000000000 --- a/source/java/org/alfresco/linkvalidation/HrefManifestEntry.java +++ /dev/null @@ -1,51 +0,0 @@ -/*----------------------------------------------------------------------------- -* Copyright 2007-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . -* -* -* Author Jon Cox -* File HrefManifestEntry.java -*----------------------------------------------------------------------------*/ - -package org.alfresco.linkvalidation; - -import java.io.Serializable; -import java.util.List; - -/** -* Contains a (possibly filtered) list of the hrefs within a file. -* Common uses of this class are to fetch the links in a web page -* or just the broken ones (i.e.: response status 400-599). -*/ -public class HrefManifestEntry implements Serializable -{ - static final long serialVersionUID = 6532525229716576911L; - - protected String file_; - protected List hrefs_; - - public HrefManifestEntry( String file, - List hrefs - ) - { - file_ = file; - hrefs_ = hrefs; - } - - public String getFileName() { return file_; } - public List getHrefs() { return hrefs_;} -} diff --git a/source/java/org/alfresco/linkvalidation/HrefStatusMap.java b/source/java/org/alfresco/linkvalidation/HrefStatusMap.java deleted file mode 100644 index 5e33e84108..0000000000 --- a/source/java/org/alfresco/linkvalidation/HrefStatusMap.java +++ /dev/null @@ -1,70 +0,0 @@ -/*----------------------------------------------------------------------------- -* Copyright 2007-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . -* -* -* Author Jon Cox -* File HrefStatusMap.java -*----------------------------------------------------------------------------*/ - -package org.alfresco.linkvalidation; - -import java.util.HashMap; -import java.util.Map; -import java.util.List; -import org.alfresco.util.Pair; - -/** -* A synchronized wrapper for the ephemeral cache of href status results. -* -* The key is the raw url that was tested (not an md5sum), -* the value is a pair consisting of the url's status code, -* and the list of files accessed when the URL is requested, -* if known. Note that all url & file data are in the namespace -* of the proposed changeset (e.g.: the workflow). -* -* This class also allows the non-synchronized map it wraps to be extracted. -*/ -public class HrefStatusMap -{ - Map< String, Pair>> status_; - - public HrefStatusMap() - { - status_ = new HashMap>>(); - } - - public HrefStatusMap( Map>> status ) - { status_ = status; } - - - /** - * Takes the url and the Pair: status code, file dependency list - */ - public synchronized void put( String url, Pair> status) - { - status_.put( url, status ); - } - - public synchronized Pair> get( String url) - { - return status_.get( url ); - } - - Map< String, Pair>> getStatusMap() { return status_;} -} - diff --git a/source/java/org/alfresco/linkvalidation/HrefValidationProgress.java b/source/java/org/alfresco/linkvalidation/HrefValidationProgress.java deleted file mode 100644 index 40cba21ca5..0000000000 --- a/source/java/org/alfresco/linkvalidation/HrefValidationProgress.java +++ /dev/null @@ -1,152 +0,0 @@ -/*----------------------------------------------------------------------------- -* Copyright 2007-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . -* -* -* Author Jon Cox -* File HrefValidationProgress.java -*----------------------------------------------------------------------------*/ - -package org.alfresco.linkvalidation; -import java.io.Serializable; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicBoolean; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** -* This class allows the progress of synchronous calls to -* updateHrefInfo to be be monitored asynchronously -* in another thread via polling. -* -* Whenever the status monitoring thread wishes to determine -* how many of the webaps, directories, files, or URLs have -* been updated sucessfully so far, it can query -* getWebappUpdateCount(), getDirUpdateCount(), -* getFileUpdateCount(), or getUrlUpdateCount(). -* The monitoring thread can determine when the -* call to updateHrefInfo() has completed by examining -* the value returned by isDone(). -*

-* Note: It is safest to instantiate a fresh HrefValidationProgress -* object for every invocation of updateHrefInfo(). -*/ -public class HrefValidationProgress implements Serializable -{ - private static final long serialVersionUID = 3031274879702889688L; - private static Log log = LogFactory.getLog(HrefValidationProgress.class ); - - AtomicInteger webapp_update_count_; - AtomicInteger dir_update_count_; - AtomicInteger file_update_count_; - AtomicInteger url_update_count_; - AtomicBoolean is_done_; - AtomicBoolean is_aborted_; - - public HrefValidationProgress() - { - webapp_update_count_ = new AtomicInteger(); - dir_update_count_ = new AtomicInteger(); - file_update_count_ = new AtomicInteger(); - url_update_count_ = new AtomicInteger(); - is_done_ = new AtomicBoolean( false ); - is_aborted_ = new AtomicBoolean( false ); - } - - /** - * Returns the number of webapps that have been completely - * URL-revalidated thus far by a call to updateHrefInfo(). - * Note that it is possible to revalidate every webapp - * in a store via updateHrefInfo(), so this value can - * be greater than 1. - */ - public int getWebappUpdateCount() { return webapp_update_count_.intValue();} - - /** - * Returns the number of directories that have been completely - * URL-revalidated thus far by a call to updateHrefInfo(). - */ - public int getDirUpdateCount() { return dir_update_count_.intValue(); } - - /** - * Tell the thread that is validating hrefs to abort its current - * operation, and cause that operation to declare it "done" and throw - * LinkValidationAbortedException. - * - * Thus, if you have an observer polling progress & checking isDone(), - * they'll also see that things are "finished", and can check to see - * whether it's because isAborted() is true. - */ - public void abort() - { - if(log.isDebugEnabled()) - { - log.debug( "Validation request aborted via: " + - "HrefValidationProgress.abort()"); - } - - is_aborted_.set( true ); - setDone( true ); - } - - /** - * Indicates whether or not the validation operation was halted by abort(). - */ - public boolean isAborted() { return is_aborted_.get(); } - - /** - * Returns the number of files that have been completely - * URL-revalidated thus far by a call to updateHrefInfo(). - */ - public int getFileUpdateCount() { return file_update_count_.intValue();} - - /** - * Returns the number of distinct URLs that have been - * URL-revalidated thus far by a call to updateHrefInfo(). - */ - public int getUrlUpdateCount() { return url_update_count_.intValue(); } - - /** - * Returns true if and only if the call to updateHrefInfo() has returned - * (whether by a normal return or via an exception). - */ - public boolean isDone() { return is_done_.get(); } - - - void init() - { - setDone( false ); - - // some defensive measures against datastructure recycling - // - webapp_update_count_.set(0); - dir_update_count_.set(0); - file_update_count_.set(0); - url_update_count_.set(0); - } - - - int incrementWebappUpdateCount() - { - return webapp_update_count_.incrementAndGet(); - } - int incrementDirUpdateCount() {return dir_update_count_.incrementAndGet(); } - int incrementFileUpdateCount(){return file_update_count_.incrementAndGet();} - int incrementUrlUpdateCount() {return url_update_count_.incrementAndGet(); } - - void setDone(Boolean tf) { is_done_.set( tf ); } -} diff --git a/source/java/org/alfresco/linkvalidation/LinkValidationAbortedException.java b/source/java/org/alfresco/linkvalidation/LinkValidationAbortedException.java deleted file mode 100644 index 098b3f720b..0000000000 --- a/source/java/org/alfresco/linkvalidation/LinkValidationAbortedException.java +++ /dev/null @@ -1,62 +0,0 @@ -/*----------------------------------------------------------------------------- -* Copyright 2007-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . -* -* -* Author Jon Cox -* File LinkValidationException.java -*----------------------------------------------------------------------------*/ - -package org.alfresco.linkvalidation; -import java.io.Serializable; - -/** - * An exception class thrown when a link validation operation is aborted. - * - * @author Jon Cox - */ -public class LinkValidationAbortedException extends LinkValidationException - implements Serializable -{ - // serialVersionUID via: - // - // CLASSPATH=$CLASSPATH:projects/repository/build/classes \ - // serialver org.alfresco.linkvalidation.LinkValidationAbortedException - // - static final long serialVersionUID = 8307355006036359098L; - - - public LinkValidationAbortedException() - { - super(); - } - - public LinkValidationAbortedException(String message) - { - super(message); - } - - public LinkValidationAbortedException(String message, Throwable cause) - { - super(message, cause); - } - - public LinkValidationAbortedException(Throwable cause) - { - super(cause); - } -} diff --git a/source/java/org/alfresco/linkvalidation/LinkValidationAction.java b/source/java/org/alfresco/linkvalidation/LinkValidationAction.java deleted file mode 100644 index 54dc5646bc..0000000000 --- a/source/java/org/alfresco/linkvalidation/LinkValidationAction.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.linkvalidation; - -import java.util.List; - -import org.alfresco.config.JNDIConstants; -import org.alfresco.error.AlfrescoRuntimeException; -import org.springframework.extensions.surf.util.I18NUtil; -import org.alfresco.repo.action.ParameterDefinitionImpl; -import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; -import org.alfresco.repo.avm.AVMNodeConverter; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.wcm.sandbox.SandboxConstants; -import org.alfresco.service.cmr.action.Action; -import org.alfresco.service.cmr.action.ParameterDefinition; -import org.alfresco.service.cmr.avm.AVMService; -import org.alfresco.service.cmr.avmsync.AVMSyncException; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.util.Pair; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Performs a link validation check. - * - * @author gavinc - */ -public class LinkValidationAction extends ActionExecuterAbstractBase -{ - private static final String MSG_DISABLED = "linkvalidation.disabled"; - - public static final String NAME = "avm-link-validation"; - - public static final String PARAM_COMPARE_TO_STAGING = "compare-to-staging"; - public static final String PARAM_MONITOR = "monitor"; - - private LinkValidationService linkValidationService; - private AVMService avmService; - private int maxNumberLinksInReport = -1; - - private static Log logger = LogFactory.getLog(LinkValidationAction.class); - - /** - * Sets the LinkValidationService instance to use - * - * @param service The LinkValidationService instance - */ - public void setLinkValidationService(LinkValidationService service) - { - this.linkValidationService = service; - } - - /** - * Sets the AVMService instance to use - * - * @param service The AVMService instance - */ - public void setAvmService(AVMService service) - { - this.avmService = service; - } - - /** - * Sets the maximum number of links to show in a report - * - * @param maxLinks The maximum number of links to store in the report, - * -1 will store all links but this must be used with - * extreme caution as the report is stored as a BLOB - * in the underlying database and these have different - * maximum sizes - */ - public void setMaxNumberLinksInReport(int maxLinks) - { - this.maxNumberLinksInReport = maxLinks; - } - - @Override - protected void addParameterDefinitions(List paramList) - { - paramList.add(new ParameterDefinitionImpl(PARAM_COMPARE_TO_STAGING, DataTypeDefinition.BOOLEAN, - false, getParamDisplayLabel(PARAM_COMPARE_TO_STAGING))); - paramList.add(new ParameterDefinitionImpl(PARAM_MONITOR, DataTypeDefinition.ANY, false, - getParamDisplayLabel(PARAM_MONITOR))); - } - - @Override - protected void executeImpl(Action action, NodeRef actionedUponNodeRef) - { - // get the webapp path to check the links for (is represented by the actioned upon node) - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(actionedUponNodeRef); - String webappPath = avmVersionPath.getSecond(); - - // get store name and path parts. - String [] webappParts = webappPath.split(":"); - if (webappParts.length != 2) - { - throw new AVMSyncException("Malformed source path: " + webappPath); - } - - // extract the store name - String storeName = actionedUponNodeRef.getStoreRef().getIdentifier(); - - // extract the webapp name - String webappName = webappPath.substring(webappPath.lastIndexOf("/")+1); - - // get the compare to staging flag - String destWebappPath = null; - Boolean compareToStaging = (Boolean)action.getParameterValue(PARAM_COMPARE_TO_STAGING); - if (compareToStaging != null) - { - if (compareToStaging.booleanValue()) - { - // get the corresponding path in the staging area for the given source - PropertyValue val = this.avmService.getStoreProperty(storeName, SandboxConstants.PROP_WEBSITE_NAME); - if (val != null) - { - String stagingStoreName = val.getStringValue(); - destWebappPath = stagingStoreName + ":/" + JNDIConstants.DIR_DEFAULT_WWW + "/" + - JNDIConstants.DIR_DEFAULT_APPBASE + "/" + webappName; - } - } - } - - // get the monitor object - HrefValidationProgress monitor = (HrefValidationProgress)action.getParameterValue(PARAM_MONITOR); - - if (logger.isDebugEnabled()) - { - if (destWebappPath == null) - { - logger.debug("Performing link validation check for webapp '" + webappPath + "', storing a maximum of " + - this.maxNumberLinksInReport + " broken links"); - } - else - { - logger.debug("Performing link validation check for webapp '" + webappPath + "', comparing against '" + - destWebappPath + "', storing a maximum of " + this.maxNumberLinksInReport + " broken links"); - } - } - - LinkValidationReport report = null; - try - { - if (this.linkValidationService.isLinkValidationDisabled()) - { - String warnMsg = I18NUtil.getMessage(MSG_DISABLED); - logger.warn(warnMsg); - throw new AlfrescoRuntimeException(warnMsg); - } - - // determine which API to call depending on whether there is a destination webapp present - if (destWebappPath != null) - { - // get the object to represent the broken files - HrefDifference hdiff = this.linkValidationService.getHrefDifference( - webappPath, destWebappPath, monitor); - - // get the broken files created due to deletions and new/modified files - HrefManifest manifest = this.linkValidationService.getBrokenHrefManifest(hdiff); - - // create the report object using the 2 sets of results - report = new LinkValidationReport(storeName, webappName, manifest, - monitor.getFileUpdateCount(), monitor.getUrlUpdateCount(), - this.maxNumberLinksInReport); - } - else - { - // retrieve the manifest of all the broken links and files for the webapp - HrefManifest manifest = this.linkValidationService.getBrokenHrefManifest(webappPath); - - // Create the report object using the link check results - report = new LinkValidationReport(storeName, webappName, manifest, - manifest.getBaseFileCount(), manifest.getBaseLinkCount(), - this.maxNumberLinksInReport); - - // the monitor object is not used here so manually set - // the done status so the client can retrieve the report. - monitor.setDone( true ); - } - } - catch (Throwable err) - { - // capture the error in the report - if (report != null) - { - report.setError(err); - } - else - { - report = new LinkValidationReport(storeName, webappName, err); - } - - // set the monitor object as completed - if (monitor != null) - { - monitor.setDone(true); - } - - logger.error("Link Validation Error: ", err); - } - - // store the report as a store property on the store we ran the link check on - this.avmService.deleteStoreProperty(storeName, SandboxConstants.PROP_LINK_VALIDATION_REPORT); - this.avmService.setStoreProperty(storeName, SandboxConstants.PROP_LINK_VALIDATION_REPORT, - new PropertyValue(DataTypeDefinition.ANY, report)); - } -} diff --git a/source/java/org/alfresco/linkvalidation/LinkValidationException.java b/source/java/org/alfresco/linkvalidation/LinkValidationException.java deleted file mode 100644 index c117adc88c..0000000000 --- a/source/java/org/alfresco/linkvalidation/LinkValidationException.java +++ /dev/null @@ -1,61 +0,0 @@ -/*----------------------------------------------------------------------------- -* Copyright 2007-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . -* -* -* Author Jon Cox -* File LinkValidationException.java -*----------------------------------------------------------------------------*/ - -package org.alfresco.linkvalidation; -import java.io.Serializable; - -/** - * Class for generic LinkValidation Exceptions. - * - * @author Jon Cox - */ -public class LinkValidationException extends Exception - implements Serializable -{ - // serialVersionUID via: - // - // CLASSPATH=$CLASSPATH:projects/repository/build/classes \ - // serialver org.alfresco.linkvalidation.LinkValidationException - // - static final long serialVersionUID = 571631235536445801L; - - public LinkValidationException() - { - super(); - } - - public LinkValidationException(String message) - { - super(message); - } - - public LinkValidationException(String message, Throwable cause) - { - super(message, cause); - } - - public LinkValidationException(Throwable cause) - { - super(cause); - } -} diff --git a/source/java/org/alfresco/linkvalidation/LinkValidationReport.java b/source/java/org/alfresco/linkvalidation/LinkValidationReport.java deleted file mode 100644 index 3f3048d1f4..0000000000 --- a/source/java/org/alfresco/linkvalidation/LinkValidationReport.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.linkvalidation; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.springframework.extensions.surf.util.ParameterCheck; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Object representing the result of a link validation action being executed. - * This object combines the results of the multiple service calls required to - * detect broken links and retrieve them. - *

- * This object is then typically added to the store being checked as a store - * property. - *

- * - * @author gavinc - */ -public class LinkValidationReport implements Serializable -{ - private String store; - private String webapp; - private int numberFilesChecked = -1; - private int numberLinksChecked = -1; - private int numberBrokenLinks = -1; - private int baseSnapshotVersion = -1; - private int latestSnapshotVersion = -1; - private int maxNumberLinksInReport = -1; - private boolean successful = true; - private boolean maxLinksReached = false; - private Date completedAt; - - private Throwable error; - private List brokenFiles; - private Map brokenLinksByFile; - - private static final long serialVersionUID = 7562964706845609991L; - private static Log logger = LogFactory.getLog(LinkValidationReport.class); - - /** - * Constructs a link validation report from the results of a check of the - * staging area. - * - * @param store The store the link check was run against - * @param webapp The webapp within the store the check was run against - * @param manifest The manifest of broken links and snapshot info - * @param noFilesChecked The number of files checked - * @param noLinksChecked The number of links checked - * @param maxNumberLinksInReport The maximum number of links to store in - * the report, -1 will store all links passed in the manifest object - */ - public LinkValidationReport(String store, String webapp, HrefManifest manifest, - int noFilesChecked, int noLinksChecked, int maxNumberLinksInReport) - { - this.store = store; - this.webapp = webapp; - this.completedAt = new Date(); - this.numberBrokenLinks = 0; - this.numberFilesChecked = noFilesChecked; - this.numberLinksChecked = noLinksChecked; - this.baseSnapshotVersion = manifest.getBaseSnapshotVersion(); - this.latestSnapshotVersion = manifest.getLatestSnapshotVersion(); - this.maxNumberLinksInReport = maxNumberLinksInReport; - - // create list and map - List manifests = manifest.getManifestEntries(); - this.brokenFiles = new ArrayList(manifests.size()); - this.brokenLinksByFile = new HashMap(manifests.size()); - - // build the required list and map - storeBrokenFiles(manifests); - } - - /** - * Constructs a link validation report from an error that occurred - * - * @param store The store the link check was run against - * @param webapp The webapp within the store the check was run against - * @param error The error that caused the link check to fail - */ - public LinkValidationReport(String store, String webapp, Throwable error) - { - this.store = store; - this.webapp = webapp; - this.completedAt = new Date(); - this.setError(error); - - this.brokenFiles = Collections.emptyList(); - this.brokenLinksByFile = Collections.emptyMap(); - } - - public String getStore() - { - return this.store; - } - - public String getWebapp() - { - return this.webapp; - } - - public Date getCheckCompletedAt() - { - return this.completedAt; - } - - public int getNumberFilesChecked() - { - return this.numberFilesChecked; - } - - public int getNumberLinksChecked() - { - return this.numberLinksChecked; - } - - public int getNumberBrokenFiles() - { - return this.brokenFiles.size(); - } - - public int getNumberBrokenLinks() - { - return this.numberBrokenLinks; - } - - public int getMaxNumberLinksInReport() - { - return this.maxNumberLinksInReport; - } - - public boolean hasMaxNumberLinksExceeded() - { - return this.maxLinksReached; - } - - public List getFilesWithBrokenLinks() - { - return this.brokenFiles; - } - - public List getBrokenLinksForFile(String file) - { - List links = null; - - HrefManifestEntry manifest = this.brokenLinksByFile.get(file); - if (manifest != null) - { - links = manifest.getHrefs(); - } - - return links; - } - - public int getBaseSnapshotVersion() - { - return this.baseSnapshotVersion; - } - - public int getLatestSnapshotVersion() - { - return this.latestSnapshotVersion; - } - - public boolean wasSuccessful() - { - return this.successful; - } - - public void setError(Throwable error) - { - this.error = error; - this.successful = false; - } - - public Throwable getError() - { - return this.error; - } - - @Override - public String toString() - { - StringBuilder buffer = new StringBuilder(super.toString()); - buffer.append(" (store=").append(this.store); - buffer.append(" webapp=").append(this.webapp); - buffer.append(" baseSnapshot=").append(this.baseSnapshotVersion); - buffer.append(" latestSnapshot=").append(this.latestSnapshotVersion); - buffer.append(" maxNumberLinksInReport=").append(this.maxNumberLinksInReport); - buffer.append(" maxLinksReached=").append(this.maxLinksReached); - buffer.append(" error=").append(this.error).append(")"); - return buffer.toString(); - } - - /** - * Stores the given list of manifest entries in the internal lists and maps - * - * @param manifests Manifest entries to store - */ - protected void storeBrokenFiles(List manifests) - { - ParameterCheck.mandatory("manifests", manifests); - - // iterate over required amount of links and store them - for (HrefManifestEntry manifest : manifests) - { - String fileName = manifest.getFileName(); - - this.brokenFiles.add(fileName); - this.brokenLinksByFile.put(fileName, manifest); - this.numberBrokenLinks = this.numberBrokenLinks + manifest.getHrefs().size(); - - // check whether we have exceeded the maximum number - // of links, if we have break out - if (this.maxNumberLinksInReport != -1 && - (this.numberBrokenLinks > this.maxNumberLinksInReport)) - { - if (logger.isWarnEnabled()) - logger.warn("Maximum number of links ("+ this.maxNumberLinksInReport + - ") for report has been exceeded at file number: " + - this.brokenFiles.size()); - - this.maxLinksReached = true; - break; - } - } - } -} - - - - - - diff --git a/source/java/org/alfresco/linkvalidation/LinkValidationService.java b/source/java/org/alfresco/linkvalidation/LinkValidationService.java deleted file mode 100644 index 5c673a4be5..0000000000 --- a/source/java/org/alfresco/linkvalidation/LinkValidationService.java +++ /dev/null @@ -1,194 +0,0 @@ -/*----------------------------------------------------------------------------- -* Copyright 2007-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . -* -* -* Author Jon Cox -* File LinkValidationService.java -*----------------------------------------------------------------------------*/ - -package org.alfresco.linkvalidation; - -import java.net.SocketException; -import java.util.List; - -import javax.net.ssl.SSLException; - -import org.alfresco.service.cmr.avm.AVMNotFoundException; - -/** - * - * @deprecated will be removed in future release - */ -public interface LinkValidationService -{ - public void onBootstrap(); - public void onShutdown(); - - /** - * Returns the poll interval (in milliseconds) used to check - * for new snapshots in staging. - */ - public int getPollInterval(); - - - //------------------------------------------------------------------------- - /** - * This function is applied to a webapp in staging, and is just a - * convenience wrapper for calling getHrefManifestEntries - * with statusGTE=400 and statusLTE=599. - *

- * Note: Files and urls within this list of manifests pertain to - * the latest validated snapshot of staging (which may be - * somewhat older than the very latest snapshot). The - * validation service attempts to keep the latest validated - * snapshot as new as possible, automatically. - */ - //------------------------------------------------------------------------- - public HrefManifest getBrokenHrefManifest( String webappPath) - throws AVMNotFoundException, - SocketException, - IllegalArgumentException; - - - //------------------------------------------------------------------------- - /** - * This function is applied to webapps in staging and returns a manifest - * consisting of just the broken hrefs within each file containing - * one or more broken href. The HrefManifestEntry list is sorted in - * increasing lexicographic order by file name. The hrefs within each - * HrefManifestEntry are also sorted in increasing lexicographic order. - */ - //------------------------------------------------------------------------- - public HrefManifest getHrefManifest( String webappPath, - int statusGTE, - int statusLTE) - throws AVMNotFoundException, - SocketException, - IllegalArgumentException; - - - //------------------------------------------------------------------------- - /** - * Fetch the difference between two areas. - * Version -1 is assumed for src; dst relies on the state of the - * link validation service updating link validity tables. - * Typically, this will be for some version close to the latest - * snapshot, but it's async, so it might be older. - */ - //------------------------------------------------------------------------- - public HrefDifference getHrefDifference( - String srcWebappPath, - String dstWebappPath, - HrefValidationProgress progress) - throws AVMNotFoundException, - SocketException, - SSLException, - LinkValidationAbortedException; - - - //------------------------------------------------------------------------- - /** - * This function is applied to difference objects created by comparing - * webapps in an author or workflow store to the staging area they - * overlay. - */ - //------------------------------------------------------------------------- - public HrefManifest getBrokenHrefManifest( HrefDifference hdiff ) - throws AVMNotFoundException, - SocketException; - - - //------------------------------------------------------------------------- - /** - * Fetches a manifest of all hyperlinks broken in new or modified files in - * an HrefDifference. The entries in this manifest are in the 'src' - * namespace of the HrefDifference operation - * (i.e.: files & urls from alice, not staging). - * - * @param hdiff The difference between two webapps obtained - * by calling getHrefDifference(). - */ - //------------------------------------------------------------------------- - public HrefManifest getHrefManifestBrokenByNewOrMod(HrefDifference hdiff); - - - - - //------------------------------------------------------------------------- - /** - * WARNING: this function won't be part of the public interface for long. - * Updates href status and href file dependencies for path. - * - * @param path - *

    - *
  • If null, do all stores & all webapps in them. - *
  • If store, do all webapps in store - *
  • If webapp, do webapp. - *
- * - * @param incremental - * If true, updates information incrementally, based on the - * files that have changed and prior calculations regarding - * url-to-file dependencies. If false, first deletes all URL - * info associated with the store/webapp (if any), then does - * a full rescan to update info. - * - * @validateExternal - * Currently does nothing. Perhaps one day you'll be able to - * turn off validation of external links. - * - * @param progress - * While updateHrefInfo() is a synchronous function, - * 'status' may be polled in a separate thread to - * observe its progress. - */ - //------------------------------------------------------------------------- - public void updateHrefInfo( String path, - boolean incremental, - boolean validateExternal, - HrefValidationProgress progress) - throws AVMNotFoundException, - SocketException, - SSLException, - LinkValidationAbortedException; - - - //------------------------------------------------------------------------- - /** - * Fetch all hyperlinks that rely upon the existence of the file specified - * by 'path', directly or indirectly. The list of hrefs returnd is - * sorted in increasing lexicographic order. For example, in - * alfresco-sample-website.war, the hrefs dependent upon - * mysite:/www/avm_webapps/ROOT/assets/footer.html are: - *
-    *     http://mysite.www--sandbox.version--v-1.127-0-0-1.ip.alfrescodemo.net:8180/
-    *     http://mysite.www--sandbox.version--v-1.127-0-0-1.ip.alfrescodemo.net:8180/assets/footer.html
-    *     http://mysite.www--sandbox.version--v-1.127-0-0-1.ip.alfrescodemo.net:8180/index.jsp
-    *     http://mysite.www--sandbox.version--v-1.127-0-0-1.ip.alfrescodemo.net:8180/media/releases/index.jsp
-    *  
- * Note that this list may contain links that are functionally equivalent - * (e.g.: the first and third links), and may also contain links that - * don't actually appear an any web page, but are implicitly present - * in the site because any asset can be "dead reckoned". - * - */ - //------------------------------------------------------------------------- - public List getHrefsDependentUponFile(String path); - - public boolean isLinkValidationDisabled(); -} diff --git a/source/java/org/alfresco/linkvalidation/LinkValidationServiceBootstrap.java b/source/java/org/alfresco/linkvalidation/LinkValidationServiceBootstrap.java deleted file mode 100644 index 6144b92946..0000000000 --- a/source/java/org/alfresco/linkvalidation/LinkValidationServiceBootstrap.java +++ /dev/null @@ -1,62 +0,0 @@ -/*----------------------------------------------------------------------------- -* Copyright 2007-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . -* -* -* Author Jon Cox -* File LinkValidationServiceBootstrap.java -*----------------------------------------------------------------------------*/ -package org.alfresco.linkvalidation; - -import org.alfresco.repo.avm.util.RawServices; -import org.springframework.extensions.surf.util.AbstractLifecycleBean; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationEvent; - -/** - * Bootstrap for LinkValidationService - */ -public class LinkValidationServiceBootstrap extends AbstractLifecycleBean -{ - private static Log logger = LogFactory.getLog(LinkValidationServiceBootstrap.class); - private LinkValidationService linkValidationService_; - - @Override - protected void onBootstrap(ApplicationEvent event) - { - ApplicationContext springContext = RawServices.Instance().getContext(); - linkValidationService_ = (LinkValidationService) - springContext.getBean("LinkValidationService"); - - linkValidationService_.onBootstrap(); - } - - @Override - protected void onShutdown(ApplicationEvent event) - { - try - { - linkValidationService_.onShutdown(); - } - catch (Throwable e) - { - logger.warn("Failed to shut down LinkValidationService", e); - } - } -} diff --git a/source/java/org/alfresco/model/ContentModel.java b/source/java/org/alfresco/model/ContentModel.java index d31499c992..1bb945ba7a 100644 --- a/source/java/org/alfresco/model/ContentModel.java +++ b/source/java/org/alfresco/model/ContentModel.java @@ -52,9 +52,6 @@ public interface ContentModel static final QName ASPECT_LOCALIZED = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "localized"); static final QName PROP_LOCALE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "locale"); - // cascade index - static final QName ASPECT_INDEX_CHILDREN = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "indexChildren"); - // 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"); diff --git a/source/java/org/alfresco/model/WCMWorkflowModel.java b/source/java/org/alfresco/model/WCMWorkflowModel.java index d54e394f2d..ea15e0e693 100644 --- a/source/java/org/alfresco/model/WCMWorkflowModel.java +++ b/source/java/org/alfresco/model/WCMWorkflowModel.java @@ -30,7 +30,6 @@ public interface WCMWorkflowModel static final QName PROP_FROM_PATH = QName.createQName(NamespaceService.WCMWF_MODEL_1_0_URI, "fromPath"); static final QName PROP_LABEL = QName.createQName(NamespaceService.WCMWF_MODEL_1_0_URI, "label"); static final QName PROP_LAUNCH_DATE = QName.createQName(NamespaceService.WCMWF_MODEL_1_0_URI, "launchDate"); - static final QName PROP_VALIDATE_LINKS = QName.createQName(NamespaceService.WCMWF_MODEL_1_0_URI, "validateLinks"); static final QName PROP_AUTO_DEPLOY = QName.createQName(NamespaceService.WCMWF_MODEL_1_0_URI, "autoDeploy"); static final QName PROP_WEBAPP = QName.createQName(NamespaceService.WCMWF_MODEL_1_0_URI, "webapp"); static final QName ASSOC_WEBPROJECT = QName.createQName(NamespaceService.WCMWF_MODEL_1_0_URI, "webproject"); diff --git a/source/java/org/alfresco/repo/activities/hibernate/Activities.hbm.xml b/source/java/org/alfresco/repo/activities/hibernate/Activities.hbm.xml deleted file mode 100644 index 9a60fcf431..0000000000 --- a/source/java/org/alfresco/repo/activities/hibernate/Activities.hbm.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/source/java/org/alfresco/repo/admin/RepoServerMgmt.java b/source/java/org/alfresco/repo/admin/RepoServerMgmt.java index d4bc78eab2..78cec92f27 100644 --- a/source/java/org/alfresco/repo/admin/RepoServerMgmt.java +++ b/source/java/org/alfresco/repo/admin/RepoServerMgmt.java @@ -22,8 +22,6 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.linkvalidation.LinkValidationService; import org.alfresco.repo.security.authentication.AbstractAuthenticationService; import org.alfresco.repo.transaction.TransactionServiceImpl; import org.apache.commons.logging.Log; @@ -37,8 +35,6 @@ public class RepoServerMgmt implements RepoServerMgmtMBean private AbstractAuthenticationService authenticationService; - private LinkValidationService linkValidationService; - public void setTransactionService(TransactionServiceImpl transactionService) { this.transactionService = transactionService; @@ -49,12 +45,6 @@ public class RepoServerMgmt implements RepoServerMgmtMBean this.authenticationService = authenticationService; } - // TODO - temporary workaround, can be removed when link validation is part of repo - public void registerLinkValidationService(LinkValidationService linkValidationService) - { - this.linkValidationService = linkValidationService; - } - public boolean isReadOnly() { return transactionService.isReadOnly(); @@ -124,15 +114,4 @@ public class RepoServerMgmt implements RepoServerMgmtMBean { return authenticationService.getMaxUsers(); } - - public boolean isLinkValidationDisabled() - { - if (linkValidationService == null) - { - log.error("LinkValidationService not registered"); - throw new AlfrescoRuntimeException("LinkValidationService not registered"); - } - - return linkValidationService.isLinkValidationDisabled(); - } } diff --git a/source/java/org/alfresco/repo/admin/RepoServerMgmtMBean.java b/source/java/org/alfresco/repo/admin/RepoServerMgmtMBean.java index 62362b1c2d..000d1713a0 100644 --- a/source/java/org/alfresco/repo/admin/RepoServerMgmtMBean.java +++ b/source/java/org/alfresco/repo/admin/RepoServerMgmtMBean.java @@ -116,12 +116,4 @@ public interface RepoServerMgmtMBean * @param int maxUsers */ public int getMaxUsers(); - - - /** - * Is link validation disabled ? - * - * @param boolean true = disabled, false = enabled - */ - public boolean isLinkValidationDisabled(); } diff --git a/source/java/org/alfresco/repo/admin/patch/AppliedPatch.java b/source/java/org/alfresco/repo/admin/patch/AppliedPatch.java index eb0d9e6448..09a734f311 100644 --- a/source/java/org/alfresco/repo/admin/patch/AppliedPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/AppliedPatch.java @@ -24,7 +24,7 @@ import java.util.Date; * Applied patch bean * * @author Derek Hulley - * @since 3.3 + * @since 3.4 */ public class AppliedPatch { diff --git a/source/java/org/alfresco/repo/admin/patch/impl/AVMGuidPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/AVMGuidPatch.java index a863083eec..114501830d 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/AVMGuidPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/AVMGuidPatch.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,66 +14,66 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.admin.patch.impl; - -import java.util.List; - -import org.springframework.extensions.surf.util.I18NUtil; -import org.alfresco.repo.admin.patch.AbstractPatch; -import org.alfresco.repo.domain.avm.AVMNodeDAO; -import org.alfresco.repo.domain.avm.AVMNodeEntity; -import org.alfresco.repo.domain.patch.PatchDAO; -import org.alfresco.util.GUID; - -/** - * This makes sure that all GUIDs in AVM nodes are set. - * @author britt - */ -public class AVMGuidPatch extends AbstractPatch -{ - private AVMNodeDAO fAVMNodeDAO; - private PatchDAO patchDAO; - - private static final String MSG_SUCCESS = "patch.AVMGuidPatch.result"; - - public AVMGuidPatch() - { - } - - public void setAvmNodeDao(AVMNodeDAO dao) - { - fAVMNodeDAO = dao; - } - - public void setPatchDao(PatchDAO dao) - { - patchDAO = dao; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.admin.patch.AbstractPatch#applyInternal() - */ - @Override - protected String applyInternal() throws Exception - { - while (true) - { - List batch = patchDAO.getEmptyGUIDS(200); - for (AVMNodeEntity nodeEntity : batch) - { - nodeEntity.setGuid(GUID.generate()); - - fAVMNodeDAO.updateNode(nodeEntity); - } - if (batch.size() == 0) - { - break; - } - } - - return I18NUtil.getMessage(MSG_SUCCESS); - } -} + * along with Alfresco. If not, see . + */ + +package org.alfresco.repo.admin.patch.impl; + +import java.util.List; + +import org.springframework.extensions.surf.util.I18NUtil; +import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.domain.avm.AVMNodeDAO; +import org.alfresco.repo.domain.avm.AVMNodeEntity; +import org.alfresco.repo.domain.patch.PatchDAO; +import org.alfresco.util.GUID; + +/** + * This makes sure that all GUIDs in AVM nodes are set. + * @author britt + */ +public class AVMGuidPatch extends AbstractPatch +{ + private AVMNodeDAO fAVMNodeDAO; + private PatchDAO patchDAO; + + private static final String MSG_SUCCESS = "patch.AVMGuidPatch.result"; + + public AVMGuidPatch() + { + } + + public void setAvmNodeDao(AVMNodeDAO dao) + { + fAVMNodeDAO = dao; + } + + public void setPatchDAO(PatchDAO dao) + { + patchDAO = dao; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.admin.patch.AbstractPatch#applyInternal() + */ + @Override + protected String applyInternal() throws Exception + { + while (true) + { + List batch = patchDAO.getEmptyGUIDS(200); + for (AVMNodeEntity nodeEntity : batch) + { + nodeEntity.setGuid(GUID.generate()); + + fAVMNodeDAO.updateNode(nodeEntity); + } + if (batch.size() == 0) + { + break; + } + } + + return I18NUtil.getMessage(MSG_SUCCESS); + } +} diff --git a/source/java/org/alfresco/repo/admin/patch/impl/AVMLayeredSnapshotPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/AVMLayeredSnapshotPatch.java index 16703bb137..5255ac06ff 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/AVMLayeredSnapshotPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/AVMLayeredSnapshotPatch.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,78 +14,78 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.admin.patch.impl; - -import java.util.List; - -import org.springframework.extensions.surf.util.I18NUtil; -import org.alfresco.repo.admin.patch.AbstractPatch; -import org.alfresco.repo.domain.avm.AVMNodeDAO; -import org.alfresco.repo.domain.avm.AVMNodeEntity; -import org.alfresco.repo.domain.patch.PatchDAO; - -/** - * Patch for changes to Layered Node path traversal. - * @author britt - */ -public class AVMLayeredSnapshotPatch extends AbstractPatch -{ - private AVMNodeDAO fAVMNodeDAO; - private PatchDAO patchDAO; - - private static final String MSG_SUCCESS = "patch.AVMLayeredSnapshot.result"; - - public AVMLayeredSnapshotPatch() - { - } - - public void setAvmNodeDao(AVMNodeDAO dao) - { - fAVMNodeDAO = dao; - } - - public void setPatchDao(PatchDAO dao) - { - patchDAO = dao; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.admin.patch.AbstractPatch#applyInternal() - */ - @Override - protected String applyInternal() throws Exception - { - while (true) - { - List batch = patchDAO.getNullVersionLayeredDirectories(200); - for (AVMNodeEntity nodeEntity : batch) - { - nodeEntity.setIndirectionVersion(-1); - - fAVMNodeDAO.updateNode(nodeEntity); - } - if (batch.size() == 0) - { - break; - } - } - while (true) - { - List batch = patchDAO.getNullVersionLayeredFiles(200); - for (AVMNodeEntity nodeEntity : batch) - { - nodeEntity.setIndirectionVersion(-1); - - fAVMNodeDAO.updateNode(nodeEntity); - } - if (batch.size() == 0) - { - break; - } - } - return I18NUtil.getMessage(MSG_SUCCESS); - } -} + * along with Alfresco. If not, see . + */ + +package org.alfresco.repo.admin.patch.impl; + +import java.util.List; + +import org.springframework.extensions.surf.util.I18NUtil; +import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.domain.avm.AVMNodeDAO; +import org.alfresco.repo.domain.avm.AVMNodeEntity; +import org.alfresco.repo.domain.patch.PatchDAO; + +/** + * Patch for changes to Layered Node path traversal. + * @author britt + */ +public class AVMLayeredSnapshotPatch extends AbstractPatch +{ + private AVMNodeDAO fAVMNodeDAO; + private PatchDAO patchDAO; + + private static final String MSG_SUCCESS = "patch.AVMLayeredSnapshot.result"; + + public AVMLayeredSnapshotPatch() + { + } + + public void setAvmNodeDao(AVMNodeDAO dao) + { + fAVMNodeDAO = dao; + } + + public void setPatchDAO(PatchDAO dao) + { + patchDAO = dao; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.admin.patch.AbstractPatch#applyInternal() + */ + @Override + protected String applyInternal() throws Exception + { + while (true) + { + List batch = patchDAO.getNullVersionLayeredDirectories(200); + for (AVMNodeEntity nodeEntity : batch) + { + nodeEntity.setIndirectionVersion(-1); + + fAVMNodeDAO.updateNode(nodeEntity); + } + if (batch.size() == 0) + { + break; + } + } + while (true) + { + List batch = patchDAO.getNullVersionLayeredFiles(200); + for (AVMNodeEntity nodeEntity : batch) + { + nodeEntity.setIndirectionVersion(-1); + + fAVMNodeDAO.updateNode(nodeEntity); + } + if (batch.size() == 0) + { + break; + } + } + return I18NUtil.getMessage(MSG_SUCCESS); + } +} diff --git a/source/java/org/alfresco/repo/admin/patch/impl/AVMLockingPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/AVMLockingPatch.java deleted file mode 100644 index 39243ed52f..0000000000 --- a/source/java/org/alfresco/repo/admin/patch/impl/AVMLockingPatch.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.admin.patch.impl; - -import org.springframework.extensions.surf.util.I18NUtil; -import org.alfresco.model.WCMAppModel; -import org.alfresco.repo.admin.patch.AbstractPatch; -import org.alfresco.service.cmr.avm.locking.AVMLockingService; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.search.ResultSet; - -/** - * This creates web project tables for AVMLockingService as needed. - * @author britt - */ -public class AVMLockingPatch extends AbstractPatch -{ - private static final String STORE = "workspace://SpacesStore"; - private static final String MSG_SUCCESS = "patch.AVMLocking.result"; - - private AVMLockingService fLockingService; - - public void setAvmLockingService(AVMLockingService service) - { - fLockingService = service; - } - - /* - * (non-Javadoc) - * @see org.alfresco.repo.admin.patch.AbstractPatch#applyInternal() - */ - @Override - protected String applyInternal() throws Exception - { - ResultSet results = - searchService.query(new StoreRef(STORE), "lucene", "TYPE:\"wca:webfolder\""); - try - { - for (NodeRef nodeRef : results.getNodeRefs()) - { - String webProject = (String)nodeService.getProperty(nodeRef, WCMAppModel.PROP_AVMSTORE); - fLockingService.addWebProject(webProject); - } - } - finally - { - results.close(); - } - return I18NUtil.getMessage(MSG_SUCCESS); - } -} diff --git a/source/java/org/alfresco/repo/admin/patch/impl/AbstractPermissionChangePatch.java b/source/java/org/alfresco/repo/admin/patch/impl/AbstractPermissionChangePatch.java index 4107d80fd8..1605511a06 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/AbstractPermissionChangePatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/AbstractPermissionChangePatch.java @@ -19,15 +19,10 @@ package org.alfresco.repo.admin.patch.impl; import org.alfresco.repo.admin.patch.AbstractPatch; -import org.alfresco.repo.domain.DbPermission; -import org.alfresco.repo.domain.hibernate.DbPermissionImpl; -import org.alfresco.repo.domain.qname.QNameDAO; +import org.alfresco.repo.domain.permissions.AclCrudDAO; +import org.alfresco.repo.domain.permissions.Permission; +import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; 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. @@ -36,23 +31,13 @@ import org.springframework.orm.hibernate3.support.HibernateDaoSupport; */ public abstract class AbstractPermissionChangePatch extends AbstractPatch { - private HibernateHelper helper; + private AclCrudDAO aclCrudDAO; - public AbstractPermissionChangePatch() + public void setAclCrudDAO(AclCrudDAO aclCrudDAO) { - helper = new HibernateHelper(); + this.aclCrudDAO = aclCrudDAO; } - public void setSessionFactory(SessionFactory sessionFactory) - { - this.helper.setSessionFactory(sessionFactory); - } - - public void setQnameDAO(QNameDAO qnameDAO) - { - helper.setQnameDAO(qnameDAO); - } - /** * 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. @@ -65,75 +50,25 @@ public abstract class AbstractPermissionChangePatch extends AbstractPatch */ 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 Long typeQNameId; - private String name; - public GetPermissionCallback(Long typeQNameId, String name) + if (oldTypeQName.equals(newTypeQName) && oldName.equals(newName)) { - this.typeQNameId = typeQNameId; - this.name = name; + throw new IllegalArgumentException("Cannot move permission to itself: " + oldTypeQName + "-" + oldName); } - public Object doInHibernate(Session session) - { - // flush any outstanding entities - session.flush(); - - Query query = session.getNamedQuery(HibernateHelper.QUERY_GET_PERMISSION); - query.setLong("permissionTypeQNameId", typeQNameId) - .setString("permissionName", name); - return query.uniqueResult(); - } - } - - private static class HibernateHelper extends HibernateDaoSupport - { - private static final String QUERY_GET_PERMISSION = "permission.GetPermission"; - private QNameDAO qnameDAO; - - public void setQnameDAO(QNameDAO qnameDAO) + SimplePermissionReference oldPermRef = SimplePermissionReference.getPermissionReference(oldTypeQName, oldName); + Permission permission = aclCrudDAO.getPermission(oldPermRef); + if (permission == null) { - this.qnameDAO = qnameDAO; + // create the permission + SimplePermissionReference newPermRef = SimplePermissionReference.getPermissionReference(newTypeQName, newName); + aclCrudDAO.createPermission(newPermRef); } - - public int createAndUpdatePermission( - final QName oldTypeQName, - final String oldName, - final QName newTypeQName, - final String newName) + else { - if (oldTypeQName.equals(newTypeQName) && oldName.equals(newName)) - { - throw new IllegalArgumentException("Cannot move permission to itself: " + oldTypeQName + "-" + oldName); - } - - // Get the QName entities - Long oldTypeQNameId = qnameDAO.getOrCreateQName(oldTypeQName).getFirst(); - Long newTypeQNameId = qnameDAO.getOrCreateQName(newTypeQName).getFirst(); - - HibernateCallback getNewPermissionCallback = new GetPermissionCallback(oldTypeQNameId, oldName); - DbPermission permission = (DbPermission) getHibernateTemplate().execute(getNewPermissionCallback); - if (permission == null) - { - // create the permission - permission = new DbPermissionImpl(); - permission.setTypeQNameId(newTypeQNameId); - permission.setName(newName); - // save - getHibernateTemplate().save(permission); - } - else - { - permission.setTypeQNameId(newTypeQNameId); - permission.setName(newName); - } - // done - return 1; + // rename the permission + aclCrudDAO.renamePermission(oldTypeQName, oldName, newTypeQName, newName); } + // done + return 1; } } diff --git a/source/java/org/alfresco/repo/admin/patch/impl/ContentUrlConverterPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/ContentUrlConverterPatch.java index de26a2a6a4..6044ab22fc 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/ContentUrlConverterPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/ContentUrlConverterPatch.java @@ -39,7 +39,6 @@ import org.alfresco.repo.domain.control.ControlDAO; import org.alfresco.repo.domain.patch.PatchDAO; import org.alfresco.repo.lock.JobLockService; import org.alfresco.repo.lock.LockAcquisitionException; -import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState; @@ -106,7 +105,6 @@ public class ContentUrlConverterPatch extends AbstractPatch private RegistryService registryService; private JobLockService jobLockService; - private NodeDaoService nodeDaoService; private PatchDAO patchDAO; private ControlDAO controlDAO; private ContentStore contentStore; @@ -143,14 +141,6 @@ public class ContentUrlConverterPatch extends AbstractPatch this.jobLockService = jobLockService; } - /** - * Provides low-level access to do the property transformation - */ - public void setNodeDaoService(NodeDaoService nodeDaoService) - { - this.nodeDaoService = nodeDaoService; - } - /** * Component that provides low-level queries and updates to support this patch */ @@ -226,7 +216,6 @@ public class ContentUrlConverterPatch extends AbstractPatch { PropertyCheck.mandatory(this, "registryService", registryService); PropertyCheck.mandatory(this, "jobLockService", jobLockService); - PropertyCheck.mandatory(this, "nodeDaoService", nodeDaoService); PropertyCheck.mandatory(this, "patchDAO", patchDAO); super.checkProperties(); } diff --git a/source/java/org/alfresco/repo/admin/patch/impl/DmPermissionsPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/DmPermissionsPatch.java index c5c0bed397..9e134b1869 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/DmPermissionsPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/DmPermissionsPatch.java @@ -20,14 +20,13 @@ package org.alfresco.repo.admin.patch.impl; import java.util.Map; -import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.repo.admin.patch.AbstractPatch; import org.alfresco.repo.domain.AccessControlListDAO; -import org.alfresco.repo.domain.hibernate.AclDaoComponentImpl; +import org.alfresco.repo.domain.patch.PatchDAO; import org.alfresco.repo.security.permissions.ACLType; -import org.alfresco.repo.security.permissions.impl.AclDaoComponent; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.springframework.extensions.surf.util.I18NUtil; /** * Migrate permissions from the OLD format to defining, shared and layered @@ -36,16 +35,16 @@ public class DmPermissionsPatch extends AbstractPatch { private static final String MSG_SUCCESS = "patch.updateDmPermissions.result"; - + private AccessControlListDAO accessControlListDao; - - private AclDaoComponent aclDaoComponent; - + + private PatchDAO patchDAO; + @Override protected String applyInternal() throws Exception { Thread progressThread = null; - if (this.aclDaoComponent.supportsProgressTracking()) + if (this.patchDAO.supportsProgressTracking()) { progressThread = new Thread(new ProgressWatcher(), "DMPatchProgressWatcher"); progressThread.start(); @@ -74,15 +73,15 @@ public class DmPermissionsPatch extends AbstractPatch { this.accessControlListDao = accessControlListDao; } - + /** - * Set the acl dao component + * Set the patch dao * - * @param aclDaoComponent + * @param patchDAO */ - public void setAclDaoComponent(AclDaoComponent aclDaoComponent) + public void setPatchDAO(PatchDAO patchDAO) { - this.aclDaoComponent = aclDaoComponent; + this.patchDAO = patchDAO; } private class ProgressWatcher implements Runnable @@ -118,12 +117,12 @@ public class DmPermissionsPatch extends AbstractPatch { if (ProgressWatcher.this.toDo == null) { - ProgressWatcher.this.toDo = DmPermissionsPatch.this.aclDaoComponent + ProgressWatcher.this.toDo = DmPermissionsPatch.this.patchDAO .getDmNodeCount(); - ProgressWatcher.this.max = DmPermissionsPatch.this.aclDaoComponent.getMaxAclId(); + ProgressWatcher.this.max = DmPermissionsPatch.this.patchDAO.getMaxAclId(); } - return DmPermissionsPatch.this.aclDaoComponent - .getDmNodeCountWithNewACLS(ProgressWatcher.this.max); + return DmPermissionsPatch.this.patchDAO + .getDmNodeCountWithNewACLs(ProgressWatcher.this.max); } }, true, true); diff --git a/source/java/org/alfresco/repo/admin/patch/impl/FixAuthoritiesCrcValuesPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/FixAuthoritiesCrcValuesPatch.java index c025366855..8642d5f8b4 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/FixAuthoritiesCrcValuesPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/FixAuthoritiesCrcValuesPatch.java @@ -21,38 +21,23 @@ package org.alfresco.repo.admin.patch.impl; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; -import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.sql.Savepoint; -import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.zip.CRC32; import org.alfresco.repo.admin.patch.AbstractPatch; -import org.alfresco.repo.admin.patch.PatchExecuter; import org.alfresco.repo.batch.BatchProcessor; import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker; -import org.alfresco.repo.domain.DbAuthority; import org.alfresco.repo.domain.control.ControlDAO; -import org.alfresco.repo.domain.hibernate.DbAuthorityImpl; +import org.alfresco.repo.domain.patch.PatchDAO; +import org.alfresco.repo.domain.permissions.AclCrudDAO; import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.service.cmr.admin.PatchException; -import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.util.TempFileProvider; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.hibernate.SQLQuery; -import org.hibernate.ScrollMode; -import org.hibernate.ScrollableResults; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.type.LongType; -import org.hibernate.type.StringType; import org.springframework.extensions.surf.util.I18NUtil; -import org.springframework.orm.hibernate3.HibernateCallback; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; /** * Fixes ALF-478. @@ -66,18 +51,31 @@ public class FixAuthoritiesCrcValuesPatch extends AbstractPatch private static final String MSG_SUCCESS = "patch.fixAuthoritiesCrcValues.result"; private static final String MSG_REWRITTEN = "patch.fixAuthoritiesCrcValues.fixed"; private static final String MSG_UNABLE_TO_CHANGE = "patch.fixAuthoritiesCrcValues.unableToChange"; + + private final Log logger = LogFactory.getLog(getClass()); - private SessionFactory sessionFactory; + private PatchDAO patchDAO; + private AclCrudDAO aclCrudDAO; private ControlDAO controlDAO; - private RuleService ruleService; public FixAuthoritiesCrcValuesPatch() { } - - public void setSessionFactory(SessionFactory sessionFactory) + + /** + * @param patchDAO finds incorrect authorities + */ + public void setPatchDAO(PatchDAO patchDAO) { - this.sessionFactory = sessionFactory; + this.patchDAO = patchDAO; + } + + /** + * @param aclCrudDAO does the actual fixing + */ + public void setAclCrudDAO(AclCrudDAO aclCrudDAO) + { + this.aclCrudDAO = aclCrudDAO; } /** @@ -88,28 +86,20 @@ public class FixAuthoritiesCrcValuesPatch extends AbstractPatch this.controlDAO = controlDAO; } - /** - * @param ruleService the rule service - */ - public void setRuleService(RuleService ruleService) - { - this.ruleService = ruleService; - } - @Override protected void checkProperties() { super.checkProperties(); - checkPropertyNotNull(sessionFactory, "sessionFactory"); - checkPropertyNotNull(applicationEventPublisher, "applicationEventPublisher"); + checkPropertyNotNull(patchDAO, "patchDAO"); + checkPropertyNotNull(aclCrudDAO, "aclCrudDAO"); + checkPropertyNotNull(controlDAO, "controlDAO"); } @Override protected String applyInternal() throws Exception { // initialise the helper - HibernateHelper helper = new HibernateHelper(); - helper.setSessionFactory(sessionFactory); + FixAuthoritiesCrcValuesPatchHelper helper = new FixAuthoritiesCrcValuesPatchHelper(); try { @@ -123,12 +113,12 @@ public class FixAuthoritiesCrcValuesPatch extends AbstractPatch } } - private class HibernateHelper extends HibernateDaoSupport + private class FixAuthoritiesCrcValuesPatchHelper { private File logFile; private FileChannel channel; - private HibernateHelper() throws IOException + private FixAuthoritiesCrcValuesPatchHelper() throws IOException { // put the log file into a long life temp directory File tempDir = TempFileProvider.getLongLifeTempDir("patches"); @@ -144,12 +134,12 @@ public class FixAuthoritiesCrcValuesPatch extends AbstractPatch writeLine("FixAuthorityCrcValuesPatch executing on " + new Date()); } - private HibernateHelper write(Object obj) throws IOException + private FixAuthoritiesCrcValuesPatchHelper write(Object obj) throws IOException { channel.write(ByteBuffer.wrap(obj.toString().getBytes("UTF-8"))); return this; } - private HibernateHelper writeLine(Object obj) throws IOException + private FixAuthoritiesCrcValuesPatchHelper writeLine(Object obj) throws IOException { write(obj); write("\n"); @@ -162,64 +152,44 @@ public class FixAuthoritiesCrcValuesPatch extends AbstractPatch public String fixCrcValues() throws Exception { + List mismatchedAuthorities = patchDAO.getAuthoritiesWithNonUtf8Crcs(); // get the association types to check - BatchProcessor batchProcessor = new BatchProcessor( + BatchProcessor batchProcessor = new BatchProcessor( "FixAuthorityCrcValuesPatch", transactionService.getRetryingTransactionHelper(), - findMismatchedCrcs(), + mismatchedAuthorities, 2, 20, applicationEventPublisher, logger, 1000); - // Precautionary flush and clear so that we have an empty session - getSession().flush(); - getSession().clear(); - - int updated = batchProcessor.process(new BatchProcessWorker() + int updated = batchProcessor.process(new BatchProcessWorker() { - public String getIdentifier(Long entry) + public String getIdentifier(String entry) { - return entry.toString(); + return entry; } public void beforeProcess() throws Throwable { - // Switch rules off - ruleService.disableRules(); // Authenticate as system String systemUsername = AuthenticationUtil.getSystemUserName(); AuthenticationUtil.setFullyAuthenticatedUser(systemUsername); } - public void process(Long authorityId) throws Throwable + public void process(String authority) throws Throwable { - DbAuthority authority = (DbAuthority) getHibernateTemplate().get(DbAuthorityImpl.class, authorityId); - if (authority == null) - { - // Missing now ... - return; - } - // Get the old CRCs - Long oldCrc = authority.getCrc(); - String authorityName = authority.getAuthority(); - - // Update the CRCs - long updatedCrc = getCrc(authorityName); - authority.setCrc(updatedCrc); - // Persist Savepoint savepoint = controlDAO.createSavepoint("FixAuthorityCrcValuesPatch"); try { - getSession().flush(); + aclCrudDAO.renameAuthority(authority, authority); controlDAO.releaseSavepoint(savepoint); } catch (Throwable e) { controlDAO.rollbackToSavepoint(savepoint); - String msg = I18NUtil.getMessage(MSG_UNABLE_TO_CHANGE, authority.getId(), authority.getAuthority(), oldCrc, - updatedCrc, e.getMessage()); + String msg = I18NUtil.getMessage(MSG_UNABLE_TO_CHANGE, authority, e.getMessage()); // We just log this and add details to the message file if (logger.isDebugEnabled()) { @@ -231,15 +201,12 @@ public class FixAuthoritiesCrcValuesPatch extends AbstractPatch } writeLine(msg); } - getSession().clear(); // Record - writeLine(I18NUtil.getMessage(MSG_REWRITTEN,authority.getId(), authority.getAuthority(), oldCrc, - updatedCrc)); + writeLine(I18NUtil.getMessage(MSG_REWRITTEN, authority)); } public void afterProcess() throws Throwable { - ruleService.enableRules(); } }, true); @@ -247,85 +214,27 @@ public class FixAuthoritiesCrcValuesPatch extends AbstractPatch String msg = I18NUtil.getMessage(MSG_SUCCESS, updated, logFile); return msg; } - - private List findMismatchedCrcs() throws Exception - { - final List authorityIds = new ArrayList(1000); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - SQLQuery query = session - .createSQLQuery( - " SELECT " + - " au.id AS authority_id," + - " au.authority AS authority," + - " au.crc as crc" + - " FROM" + - " alf_authority au"); - query.addScalar("authority_id", new LongType()); - query.addScalar("authority", new StringType()); - query.addScalar("crc", new LongType()); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults rs = null; - try - { - rs = (ScrollableResults) getHibernateTemplate().execute(callback); - while (rs.next()) - { - // Compute child name crc - Long authorityId = (Long) rs.get(0); - String authority = (String) rs.get(1); - Long crc = (Long) rs.get(2); - long calculatedCrc = 0; - if (authority != null) - { - calculatedCrc = getCrc(authority); - } - - // Check - if (crc != null && crc.equals(calculatedCrc)) - { - // It is a match, so ignore - continue; - } - authorityIds.add(authorityId); - } - } - catch (Throwable e) - { - logger.error("Failed to query for authority CRCs", e); - writeLine("Failed to query for authority CRCs: " + e.getMessage()); - throw new PatchException("Failed to query for authority CRCs", e); - } - finally - { - if (rs != null) - { - try { rs.close(); } catch (Throwable e) { writeLine("Failed to close resultset: " + e.getMessage()); } - } - } - return authorityIds; - } - - /** - * @param str the name that will be kept as is - * @return the CRC32 calculated on the exact case sensitive version of the string - */ - private long getCrc(String str) - { - CRC32 crc = new CRC32(); - try - { - crc.update(str.getBytes("UTF-8")); // https://issues.alfresco.com/jira/browse/ALFCOM-1335 - } - catch (UnsupportedEncodingException e) - { - throw new RuntimeException("UTF-8 encoding is not supported"); - } - return crc.getValue(); - } +// Keeping this for reference. Actually, the query need only pull back the authority and crc +// private List findMismatchedCrcs() throws Exception +// { +// final List authorityIds = new ArrayList(1000); +// HibernateCallback callback = new HibernateCallback() +// { +// public Object doInHibernate(Session session) +// { +// SQLQuery query = session +// .createSQLQuery( +// " SELECT " + +// " au.id AS authority_id," + +// " au.authority AS authority," + +// " au.crc as crc" + +// " FROM" + +// " alf_authority au"); +// query.addScalar("authority_id", new LongType()); +// query.addScalar("authority", new StringType()); +// query.addScalar("crc", new LongType()); +// return query.scroll(ScrollMode.FORWARD_ONLY); +// } +// }; } } diff --git a/source/java/org/alfresco/repo/admin/patch/impl/FixNameCrcValuesPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/FixNameCrcValuesPatch.java index a3b35358ba..12dfddda01 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/FixNameCrcValuesPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/FixNameCrcValuesPatch.java @@ -40,8 +40,8 @@ import org.alfresco.repo.domain.ChildAssoc; import org.alfresco.repo.domain.Node; import org.alfresco.repo.domain.control.ControlDAO; import org.alfresco.repo.domain.hibernate.ChildAssocImpl; +import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.domain.qname.QNameDAO; -import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.cmr.admin.PatchException; import org.alfresco.service.cmr.rule.RuleService; @@ -75,7 +75,7 @@ public class FixNameCrcValuesPatch extends AbstractPatch private static final String MSG_UNABLE_TO_CHANGE = "patch.fixNameCrcValues.unableToChange"; private SessionFactory sessionFactory; - private NodeDaoService nodeDaoService; + private NodeDAO nodeDAO; private QNameDAO qnameDAO; private ControlDAO controlDAO; private RuleService ruleService; @@ -92,12 +92,9 @@ public class FixNameCrcValuesPatch extends AbstractPatch this.sessionFactory = sessionFactory; } - /** - * @param nodeDaoService The service that generates the CRC values - */ - public void setNodeDaoService(NodeDaoService nodeDaoService) + public void setNodeDAO(NodeDAO nodeDAO) { - this.nodeDaoService = nodeDaoService; + this.nodeDAO = nodeDAO; } /** @@ -134,7 +131,7 @@ public class FixNameCrcValuesPatch extends AbstractPatch { super.checkProperties(); checkPropertyNotNull(sessionFactory, "sessionFactory"); - checkPropertyNotNull(nodeDaoService, "nodeDaoService"); + checkPropertyNotNull(nodeDAO, "nodeDAO"); checkPropertyNotNull(qnameDAO, "qnameDAO"); checkPropertyNotNull(applicationEventPublisher, "applicationEventPublisher"); } @@ -241,7 +238,7 @@ public class FixNameCrcValuesPatch extends AbstractPatch // Get the child node Node childNode = assoc.getChild(); // Get the name - String childName = (String) nodeDaoService.getNodeProperty(childNode.getId(), ContentModel.PROP_NAME); + String childName = (String) nodeDAO.getNodeProperty(childNode.getId(), ContentModel.PROP_NAME); if (childName == null) { childName = childNode.getUuid(); diff --git a/source/java/org/alfresco/repo/admin/patch/impl/InvalidNameEndingPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/InvalidNameEndingPatch.java index d0dd3a1320..a31d7f29bd 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/InvalidNameEndingPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/InvalidNameEndingPatch.java @@ -26,11 +26,9 @@ import java.nio.channels.FileChannel; import java.util.Date; import java.util.List; -import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.model.ContentModel; import org.alfresco.repo.admin.patch.AbstractPatch; 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.repository.DuplicateChildNodeNameException; import org.alfresco.service.cmr.repository.NodeRef; @@ -38,6 +36,7 @@ import org.alfresco.util.TempFileProvider; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; +import org.springframework.extensions.surf.util.I18NUtil; import org.springframework.orm.hibernate3.HibernateCallback; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; @@ -53,8 +52,6 @@ public class InvalidNameEndingPatch extends AbstractPatch private static final String ERR_UNABLE_TO_FIX = "patch.invalidNameEnding.err.unable_to_fix"; private SessionFactory sessionFactory; - private NodeDaoService nodeDaoService; - public static void main(String[] args) { @@ -80,20 +77,11 @@ public class InvalidNameEndingPatch extends AbstractPatch this.sessionFactory = sessionFactory; } - /** - * @param nodeDaoService The service that generates the CRC values - */ - public void setNodeDaoService(NodeDaoService nodeDaoService) - { - this.nodeDaoService = nodeDaoService; - } - @Override protected void checkProperties() { super.checkProperties(); checkPropertyNotNull(sessionFactory, "sessionFactory"); - checkPropertyNotNull(nodeDaoService, "nodeDaoService"); } @Override @@ -154,7 +142,6 @@ public class InvalidNameEndingPatch extends AbstractPatch public String fixNames() throws Exception { // get the association types to check - @SuppressWarnings("unused") List nodes = getInvalidNames(); int updated = 0; diff --git a/source/java/org/alfresco/repo/admin/patch/impl/LinkNodeFileExtensionPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/LinkNodeFileExtensionPatch.java index 6c5d0e068b..a3a9f62dab 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/LinkNodeFileExtensionPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/LinkNodeFileExtensionPatch.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,213 +14,201 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . */ -package org.alfresco.repo.admin.patch.impl; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.util.Date; -import java.util.List; - -import org.springframework.extensions.surf.util.I18NUtil; -import org.alfresco.model.ContentModel; -import org.alfresco.repo.admin.patch.AbstractPatch; -import org.alfresco.repo.domain.hibernate.NodeImpl; -import org.alfresco.repo.node.db.NodeDaoService; -import org.alfresco.service.cmr.admin.PatchException; -import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.util.TempFileProvider; -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; - -/** - * Checks that all names do not end with ' ' or '.' - * - * @author David Caruana - */ -public class LinkNodeFileExtensionPatch extends AbstractPatch -{ - private static final String MSG_SUCCESS = "patch.linkNodeExtension.result"; - private static final String MSG_REWRITTEN = "patch.linkNodeExtension.rewritten"; - private static final String ERR_UNABLE_TO_FIX = "patch.linkNodeExtension.err.unable_to_fix"; - - private SessionFactory sessionFactory; - private NodeDaoService nodeDaoService; - - /** - * Default constructor - * - */ - public LinkNodeFileExtensionPatch() - { - } - - /** - * Set the session factory - * - * @param sessionFactory SessionFactory - */ - public void setSessionFactory(SessionFactory sessionFactory) - { - this.sessionFactory = sessionFactory; - } - - /** - * @param nodeDaoService The service that generates the CRC values - */ - public void setNodeDaoService(NodeDaoService nodeDaoService) - { - this.nodeDaoService = nodeDaoService; - } - - @Override - protected void checkProperties() - { - super.checkProperties(); - checkPropertyNotNull(sessionFactory, "sessionFactory"); - checkPropertyNotNull(nodeDaoService, "nodeDaoService"); - } - - @Override - protected String applyInternal() throws Exception - { - // Initialise the helper - - HibernateHelper helper = new HibernateHelper(); - helper.setSessionFactory(sessionFactory); - - try - { - // Fix the link node file names - - return helper.fixNames(); - } - finally - { - helper.closeWriter(); - } - } - - private class HibernateHelper extends HibernateDaoSupport - { - private File logFile; - private FileChannel channel; - - private HibernateHelper() throws IOException - { - // Open a log file - File tempDir = TempFileProvider.getLongLifeTempDir("patches"); - logFile = new File(tempDir, "LinkNodeExtensionPatch.log"); - - RandomAccessFile outputFile = new RandomAccessFile(logFile, "rw"); - channel = outputFile.getChannel(); - - // Append to the end of the file - - channel.position(channel.size()); - - writeLine("").writeLine(""); - writeLine("LinkNodeExtensionPatch executing on " + new Date()); - } - - private HibernateHelper write(Object obj) throws IOException - { - channel.write(ByteBuffer.wrap(obj.toString().getBytes())); - return this; - } - private HibernateHelper writeLine(Object obj) throws IOException - { - write(obj); - write("\n"); - return this; - } - private void closeWriter() - { - try { channel.close(); } catch (Throwable e) {} - } - - public String fixNames() throws Exception - { - // Get the list of nodes to be updated - - @SuppressWarnings("unused") - List nodes = getInvalidNames(); - - int updated = 0; - for (NodeImpl node : nodes) - { - // Check that the node is a link node - - NodeRef nodeRef = node.getNodeRef(); - - if ( nodeService.getProperty(nodeRef, ContentModel.PROP_LINK_DESTINATION) != null) - { - // Get the current file name - - String name = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); - if (name != null && name.length() >= 4 && name.endsWith(".lnk")) - { - // Update the name string, replace '.lnk' with '.url' - - String updatedName = name.substring(0, name.length() - 4) + ".url"; - - int idx = 0; - boolean applied = false; - while (!applied) - { - try - { - nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, updatedName); - applied = true; - } - catch(DuplicateChildNodeNameException e) - { - idx++; - if (idx > 10) - { - writeLine(I18NUtil.getMessage(ERR_UNABLE_TO_FIX, name, updatedName)); - throw new PatchException(ERR_UNABLE_TO_FIX, logFile); - } - updatedName += "_" + idx; - } - } - writeLine(I18NUtil.getMessage(MSG_REWRITTEN, name ,updatedName)); - updated++; - getSession().flush(); - getSession().clear(); - } - } - } - - String msg = I18NUtil.getMessage(MSG_SUCCESS, updated, logFile); - return msg; - } - - @SuppressWarnings("unchecked") - private List getInvalidNames() - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .createQuery( - "select node from org.alfresco.repo.domain.hibernate.NodeImpl as node " + - "join node.properties prop where " + - " prop.stringValue like '%.lnk' "); - return query.list(); - } - }; - List results = (List) getHibernateTemplate().execute(callback); - return results; - } - - } -} + * along with Alfresco. If not, see . */ +package org.alfresco.repo.admin.patch.impl; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.Date; +import java.util.List; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.domain.hibernate.NodeImpl; +import org.alfresco.service.cmr.admin.PatchException; +import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.TempFileProvider; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.springframework.extensions.surf.util.I18NUtil; +import org.springframework.orm.hibernate3.HibernateCallback; +import org.springframework.orm.hibernate3.support.HibernateDaoSupport; + +/** + * Checks that all names do not end with ' ' or '.' + * + * @author David Caruana + */ +public class LinkNodeFileExtensionPatch extends AbstractPatch +{ + private static final String MSG_SUCCESS = "patch.linkNodeExtension.result"; + private static final String MSG_REWRITTEN = "patch.linkNodeExtension.rewritten"; + private static final String ERR_UNABLE_TO_FIX = "patch.linkNodeExtension.err.unable_to_fix"; + + private SessionFactory sessionFactory; + + /** + * Default constructor + * + */ + public LinkNodeFileExtensionPatch() + { + } + + /** + * Set the session factory + * + * @param sessionFactory SessionFactory + */ + public void setSessionFactory(SessionFactory sessionFactory) + { + this.sessionFactory = sessionFactory; + } + + @Override + protected void checkProperties() + { + super.checkProperties(); + checkPropertyNotNull(sessionFactory, "sessionFactory"); + } + + @Override + protected String applyInternal() throws Exception + { + // Initialise the helper + + HibernateHelper helper = new HibernateHelper(); + helper.setSessionFactory(sessionFactory); + + try + { + // Fix the link node file names + + return helper.fixNames(); + } + finally + { + helper.closeWriter(); + } + } + + private class HibernateHelper extends HibernateDaoSupport + { + private File logFile; + private FileChannel channel; + + private HibernateHelper() throws IOException + { + // Open a log file + File tempDir = TempFileProvider.getLongLifeTempDir("patches"); + logFile = new File(tempDir, "LinkNodeExtensionPatch.log"); + + RandomAccessFile outputFile = new RandomAccessFile(logFile, "rw"); + channel = outputFile.getChannel(); + + // Append to the end of the file + + channel.position(channel.size()); + + writeLine("").writeLine(""); + writeLine("LinkNodeExtensionPatch executing on " + new Date()); + } + + private HibernateHelper write(Object obj) throws IOException + { + channel.write(ByteBuffer.wrap(obj.toString().getBytes())); + return this; + } + private HibernateHelper writeLine(Object obj) throws IOException + { + write(obj); + write("\n"); + return this; + } + private void closeWriter() + { + try { channel.close(); } catch (Throwable e) {} + } + + public String fixNames() throws Exception + { + // Get the list of nodes to be updated + + List nodes = getInvalidNames(); + + int updated = 0; + for (NodeImpl node : nodes) + { + // Check that the node is a link node + + NodeRef nodeRef = node.getNodeRef(); + + if ( nodeService.getProperty(nodeRef, ContentModel.PROP_LINK_DESTINATION) != null) + { + // Get the current file name + + String name = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); + if (name != null && name.length() >= 4 && name.endsWith(".lnk")) + { + // Update the name string, replace '.lnk' with '.url' + + String updatedName = name.substring(0, name.length() - 4) + ".url"; + + int idx = 0; + boolean applied = false; + while (!applied) + { + try + { + nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, updatedName); + applied = true; + } + catch(DuplicateChildNodeNameException e) + { + idx++; + if (idx > 10) + { + writeLine(I18NUtil.getMessage(ERR_UNABLE_TO_FIX, name, updatedName)); + throw new PatchException(ERR_UNABLE_TO_FIX, logFile); + } + updatedName += "_" + idx; + } + } + writeLine(I18NUtil.getMessage(MSG_REWRITTEN, name ,updatedName)); + updated++; + getSession().flush(); + getSession().clear(); + } + } + } + + String msg = I18NUtil.getMessage(MSG_SUCCESS, updated, logFile); + return msg; + } + + @SuppressWarnings("unchecked") + private List getInvalidNames() + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session + .createQuery( + "select node from org.alfresco.repo.domain.hibernate.NodeImpl as node " + + "join node.properties prop where " + + " prop.stringValue like '%.lnk' "); + return query.list(); + } + }; + List results = (List) getHibernateTemplate().execute(callback); + return results; + } + + } +} diff --git a/source/java/org/alfresco/repo/admin/patch/impl/MoveWCMToGroupBasedPermissionsPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/MoveWCMToGroupBasedPermissionsPatch.java index d1620ff4af..a7cdd1d25c 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/MoveWCMToGroupBasedPermissionsPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/MoveWCMToGroupBasedPermissionsPatch.java @@ -22,16 +22,12 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.model.WCMAppModel; import org.alfresco.repo.admin.patch.AbstractPatch; import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.hibernate.AclDaoComponentImpl; import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor; import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor.StoreType; -import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.AVMStoreDescriptor; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; @@ -44,6 +40,7 @@ import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; +import org.springframework.extensions.surf.util.I18NUtil; /** * Remove ACLs on all but staging area stores On staging area stores, set ACls according to the users and roles as set @@ -69,8 +66,6 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch PermissionService permissionService; - AclDaoComponentImpl aclDaoComponent; - AuthorityService authorityService; String replaceAllWith = PermissionService.WCM_CONTENT_MANAGER; @@ -91,11 +86,6 @@ public class MoveWCMToGroupBasedPermissionsPatch extends AbstractPatch this.permissionService = permissionService; } - public void setAclDaoComponent(AclDaoComponentImpl aclDaoComponent) - { - this.aclDaoComponent = aclDaoComponent; - } - public void setAuthorityService(AuthorityService authorityService) { this.authorityService = authorityService; diff --git a/source/java/org/alfresco/repo/admin/patch/impl/NodePropertySerializablePatch.java b/source/java/org/alfresco/repo/admin/patch/impl/NodePropertySerializablePatch.java deleted file mode 100644 index f9188232de..0000000000 --- a/source/java/org/alfresco/repo/admin/patch/impl/NodePropertySerializablePatch.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.admin.patch.impl; - -import java.io.Serializable; -import java.util.Iterator; -import java.util.Map; - -import org.springframework.extensions.surf.util.I18NUtil; -import org.alfresco.repo.admin.patch.AbstractPatch; -import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.NodePropertyValue; -import org.alfresco.repo.domain.PropertyMapKey; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -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; - -/** - * Certain content models make extensive use of the d:any datatype, which has led - * to storage of simple types as serialized instances. - * This patch ensures that all previously serializable values are stored in their - * more native form in the database.
- * e.g. If a property was d:any and a string was written ("ABC"), - * then the value was stored in serializable_value. Instead, the newer code stores - * the value in string_value. None of the retrieval code is affected, but the values - * are made visible to queries, in addition to reducing the size of the node_properties - * table. This patch ensures that previously-stored values are changed to conform - * to the new storage mechanism. - *

- * JIRA: {@link http://www.alfresco.org/jira/browse/AR-359 AR-359} - * - * @see org.alfresco.repo.domain.PropertyValue - * - * @author Derek Hulley - */ -public class NodePropertySerializablePatch extends AbstractPatch -{ - private static final String MSG_SUCCESS = "patch.fixNodeSerializableValues.result"; - - private HibernateHelper helper; - - public NodePropertySerializablePatch() - { - helper = new HibernateHelper(); - } - - public void setSessionFactory(SessionFactory sessionFactory) - { - this.helper.setSessionFactory(sessionFactory); - } - - @Override - protected String applyInternal() throws Exception - { - int updatedEntries = helper.fixSerializableProperties(); - - // build the result message - String msg = I18NUtil.getMessage(MSG_SUCCESS, updatedEntries); - // done - return msg; - } - - private static class HibernateHelper extends HibernateDaoSupport - { - private static final String QUERY_GET_NODES = "node.patch.GetNodesWithPersistedSerializableProperties"; - - public int fixSerializableProperties() - { - HibernateCallback callback = new HibernateCallback() - { - @SuppressWarnings("unchecked") - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(HibernateHelper.QUERY_GET_NODES); - Iterator iterator = query.iterate(); - // iterate over the nodes - int count = 0; - while (iterator.hasNext()) - { - Node node = iterator.next(); - // retrieve the node properties - Map properties = node.getProperties(); - // check each property - for (Map.Entry entry : properties.entrySet()) - { - NodePropertyValue propertyValue = entry.getValue(); - if (propertyValue.getSerializableValue() == null) - { - // the property was not persisted as a serializable - nothing to do - continue; - } - else if (!"SERIALIZABLE".equals(propertyValue.getActualTypeString())) - { - // only handle actual types that were pushed in as any old type - continue; - } - // make sure that this value is persisted correctly - Serializable value = propertyValue.getSerializableValue(); - // put it back - NodePropertyValue newPropertyValue = new NodePropertyValue(DataTypeDefinition.ANY, value); - entry.setValue(newPropertyValue); - count++; - } - } - return new Integer(count); - } - }; - Integer updateCount = (Integer) getHibernateTemplate().execute(callback); - // done - return updateCount.intValue(); - } - } -} diff --git a/source/java/org/alfresco/repo/admin/patch/impl/PersonUsagePatch.java b/source/java/org/alfresco/repo/admin/patch/impl/PersonUsagePatch.java index 06864b4a9f..685ef15dc0 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/PersonUsagePatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/PersonUsagePatch.java @@ -18,16 +18,16 @@ */ package org.alfresco.repo.admin.patch.impl; -import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.model.ContentModel; import org.alfresco.repo.admin.patch.AbstractPatch; -import org.alfresco.repo.node.db.NodeDaoService; -import org.alfresco.repo.node.db.NodeDaoService.ObjectArrayQueryCallback; +import org.alfresco.repo.domain.patch.PatchDAO; +import org.alfresco.repo.domain.patch.PatchDAO.StringHandler; import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.I18NUtil; /** * Patch to add person usage ('cm:sizeCurrent') property to person (if missing) @@ -42,16 +42,15 @@ public class PersonUsagePatch extends AbstractPatch private static final String MSG_SUCCESS1 = "patch.personUsagePatch.result1"; private static final String MSG_SUCCESS2 = "patch.personUsagePatch.result2"; - private NodeDaoService nodeDaoService; + private PatchDAO patchDAO; private StoreRef personStoreRef; private TenantService tenantService; - - public void setNodeDaoService(NodeDaoService nodeDaoService) + public void setPatchDAO(PatchDAO patchDAO) { - this.nodeDaoService = nodeDaoService; + this.patchDAO = patchDAO; } - + public void setPersonStoreUrl(String storeUrl) { this.personStoreRef = new StoreRef(storeUrl); @@ -89,31 +88,27 @@ public class PersonUsagePatch extends AbstractPatch { // get people (users) with missing 'cm:sizeCurrent' property - CountObjectArrayQueryCallback userHandler = new CountObjectArrayQueryCallback(); + CountQueryCallback userHandler = new CountQueryCallback(); - nodeDaoService.getUsersWithoutUsageProp(tenantService.getName(personStoreRef), userHandler); + patchDAO.getUsersWithoutUsageProp(tenantService.getName(personStoreRef), userHandler); return userHandler.getCount(); } - private class CountObjectArrayQueryCallback implements ObjectArrayQueryCallback + private class CountQueryCallback implements StringHandler { private int count; - public CountObjectArrayQueryCallback() + public CountQueryCallback() { count = 0; } - public boolean handle(Object[] arr) + public void handle(String uuid) { - String uuid = (String)arr[0]; - nodeService.setProperty(new NodeRef(personStoreRef, uuid), ContentModel.PROP_SIZE_CURRENT, null); count++; - - return true; // continue to next node (more required) } public int getCount() diff --git a/source/java/org/alfresco/repo/admin/patch/impl/ResetWCMToGroupBasedPermissionsPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/ResetWCMToGroupBasedPermissionsPatch.java index 45ead05f20..330df372c9 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/ResetWCMToGroupBasedPermissionsPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/ResetWCMToGroupBasedPermissionsPatch.java @@ -20,38 +20,33 @@ package org.alfresco.repo.admin.patch.impl; import java.util.ArrayList; 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.zip.CRC32; import org.alfresco.config.JNDIConstants; import org.alfresco.error.AlfrescoRuntimeException; -import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.model.WCMAppModel; -import org.alfresco.repo.domain.DbAccessControlEntry; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.DbAccessControlListChangeSet; -import org.alfresco.repo.domain.DbAuthority; -import org.alfresco.repo.domain.DbPermission; import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.qname.QNameDAO; -import org.alfresco.repo.domain.hibernate.DbAccessControlEntryImpl; -import org.alfresco.repo.domain.hibernate.DbAccessControlListChangeSetImpl; -import org.alfresco.repo.domain.hibernate.DbAccessControlListImpl; -import org.alfresco.repo.domain.hibernate.DbAccessControlListMemberImpl; -import org.alfresco.repo.domain.hibernate.DbAuthorityImpl; -import org.alfresco.repo.domain.hibernate.DbPermissionImpl; +import org.alfresco.repo.domain.avm.AVMChildEntryEntity; +import org.alfresco.repo.domain.avm.AVMNodeLinksDAO; +import org.alfresco.repo.domain.avm.AVMStoreDAO; +import org.alfresco.repo.domain.patch.PatchDAO; +import org.alfresco.repo.domain.permissions.AclCrudDAO; +import org.alfresco.repo.domain.permissions.AclEntity; +import org.alfresco.repo.domain.permissions.Authority; +import org.alfresco.repo.domain.permissions.Permission; import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor.StoreType; import org.alfresco.repo.security.permissions.ACEType; import org.alfresco.repo.security.permissions.ACLType; +import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; import org.alfresco.service.cmr.admin.PatchException; import org.alfresco.service.cmr.avm.AVMStoreDescriptor; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; +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.cmr.security.PersonService; @@ -62,16 +57,7 @@ import org.alfresco.util.GUID; import org.alfresco.util.Pair; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.hibernate.Query; -import org.hibernate.SQLQuery; -import org.hibernate.ScrollMode; -import org.hibernate.ScrollableResults; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.type.LongType; -import org.hibernate.type.StringType; -import org.springframework.orm.hibernate3.HibernateCallback; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; +import org.springframework.extensions.surf.util.I18NUtil; /** * Alternative patch to remove ACLs from all WCM stores, and replace with WCM group-based ACLs. @@ -80,34 +66,49 @@ import org.springframework.orm.hibernate3.support.HibernateDaoSupport; */ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPermissionsPatch { - private static Log logger = LogFactory.getLog(ResetWCMToGroupBasedPermissionsPatch.class); - + private static Log logger = LogFactory.getLog(ResetWCMToGroupBasedPermissionsPatch.class); + private static final String MSG_SUCCESS = "patch.resetWCMToGroupBasedPermissionsPatch.result"; - private HibernateHelper helper; + private AclCrudDAO aclCrudDAO; + private AVMStoreDAO avmStoreDAO; + private AVMNodeLinksDAO avmNodeLinksDAO; + private PatchDAO patchDAO; + + private HelperDAO helper; // local helper class private PersonService personService; private static int batchSize = 500; // cache staging store acl change set and shared acl id - private Map> stagingData = new HashMap>(10); - - public void setSessionFactory(SessionFactory sessionFactory) - { - helper.setSessionFactory(sessionFactory); - } - - public void setQnameDAO(QNameDAO qnameDAO) - { - helper.setQnameDAO(qnameDAO); - } + private Map> stagingData = new HashMap>(10); public void setPersonService(PersonService personService) { this.personService = personService; } + public void setAvmStoreDAO(AVMStoreDAO avmStoreDAO) + { + this.avmStoreDAO = avmStoreDAO; + } + + public void setAvmNodeLinksDAO(AVMNodeLinksDAO avmNodeLinksDAO) + { + this.avmNodeLinksDAO = avmNodeLinksDAO; + } + + public void setAclCrudDAO(AclCrudDAO aclCrudDAO) + { + this.aclCrudDAO = aclCrudDAO; + } + + public void setPatchDAO(PatchDAO patchDAO) + { + this.patchDAO = patchDAO; + } + public void setBatchSize(int batchSizeOverride) { batchSize = batchSizeOverride; @@ -115,7 +116,7 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer public ResetWCMToGroupBasedPermissionsPatch() { - helper = new HibernateHelper(); + helper = new HelperDAO(); } @Override @@ -177,9 +178,6 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer setStagingAreaPermissions(store); - // flush any outstanding entities - helper.getSessionFactory().getCurrentSession().flush(); - setStagingAreaMasks(store); break; @@ -282,9 +280,6 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer setSandboxPermissions(store); - // flush any outstanding entities - helper.getSessionFactory().getCurrentSession().flush(); - setSandBoxMasks(store); break; @@ -310,9 +305,6 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer setSandboxPermissions(store); - // flush any outstanding entities - helper.getSessionFactory().getCurrentSession().flush(); - setStagingAreaMasks(store); break; @@ -359,9 +351,6 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer setSandboxPermissions(store); - // flush any outstanding entities - helper.getSessionFactory().getCurrentSession().flush(); - setSandBoxMasks(store); break; @@ -406,9 +395,6 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer setSandboxPermissions(store); - // flush any outstanding entities - helper.getSessionFactory().getCurrentSession().flush(); - setSandBoxMasks(store); break; @@ -508,12 +494,12 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer logger.debug("Start deleting dangling acls/aces (across all stores)"); } - helper.deleteDanglingAcls(); - helper.deleteDanglingAces(); + int aclsDeletedCount = helper.deleteDanglingAcls(); + int acesDeletedCount = patchDAO.deleteDanglingAces(); if (logger.isDebugEnabled()) { - logger.debug("Finish deleting dangling acls/aces (across all stores) in "+(System.currentTimeMillis()-startTime)/1000+" secs"); + logger.debug("Finish deleting dangling acls/aces ["+aclsDeletedCount+"/"+acesDeletedCount+"] (across all stores) in "+(System.currentTimeMillis()-startTime)/1000+" secs"); } } catch (Throwable e) @@ -537,15 +523,12 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer } // create acl change set, defining acl and shared acl - DbAccessControlListChangeSet aclChangeSet = helper.createAclChangeSet(); + long aclChangeSet = aclCrudDAO.createAclChangeSet(); long definingAclId = helper.createWCMGroupBasedAcl(stagingStoreName, aclChangeSet, ACLType.DEFINING, false); long sharedAclId = helper.createWCMGroupBasedAcl(stagingStoreName, aclChangeSet, ACLType.SHARED, false); - stagingData.put(stagingStoreName, new Pair(aclChangeSet, sharedAclId)); - - // flush any outstanding entities - helper.getSessionFactory().getCurrentSession().flush(); + stagingData.put(stagingStoreName, new Pair(aclChangeSet, sharedAclId)); helper.updateAclInherited(definingAclId, sharedAclId); @@ -575,9 +558,9 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer logger.debug("Start set sandbox permissions: "+sandboxStoreName); } - Pair aclData = stagingData.get(extractBaseStore(sandboxStoreName)); + Pair aclData = stagingData.get(extractBaseStore(sandboxStoreName)); - DbAccessControlListChangeSet aclChangeSet = aclData.getFirst(); + long aclChangeSet = aclData.getFirst(); long baseSharedAclId = aclData.getSecond(); String stagingStoreName = extractStagingAreaName(sandboxStoreName); @@ -586,10 +569,7 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer long layeredAclId = helper.createWCMGroupBasedAcl(stagingStoreName, aclChangeSet, ACLType.LAYERED, true); long sharedAclId = helper.createWCMGroupBasedAcl(stagingStoreName, aclChangeSet, ACLType.SHARED, false); - stagingData.put(sandboxStoreName, new Pair(aclChangeSet, sharedAclId)); - - // flush any outstanding entities - helper.getSessionFactory().getCurrentSession().flush(); + stagingData.put(sandboxStoreName, new Pair(aclChangeSet, sharedAclId)); helper.updateAclInheritsFrom(layeredAclId, baseSharedAclId); helper.updateAclInheritsFrom(sharedAclId, layeredAclId); @@ -693,21 +673,8 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer return name; } - private static class HibernateHelper extends HibernateDaoSupport + private class HelperDAO { - private static Log logger = LogFactory.getLog(ResetWCMToGroupBasedPermissionsPatch.class); - - private static final String QUERY_GET_PERMISSION = "permission.GetPermission"; - private static final String QUERY_GET_AUTHORITY = "permission.GetAuthority"; - private static final String QUERY_GET_ACE_WITH_NO_CONTEXT = "permission.GetAceWithNoContext"; - - protected QNameDAO qnameDAO; - - public void setQnameDAO(QNameDAO qnameDAO) - { - this.qnameDAO = qnameDAO; - } - private int nullifyAvmNodeAcls(final String storeName) { try @@ -738,16 +705,16 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer { long rootId = getAVMStoreCurrentRootNodeId(storeName); - List> children = getAVMChildrenWithName(rootId); + List children = getAVMChildrenEntries(rootId); int totalUpdatedCount = 0; List childIds = new ArrayList(0); - for (Pair child : children) + for (AVMChildEntryEntity child : children) { - Long childId = child.getFirst(); - String name = child.getSecond(); + Long childId = child.getChildId(); + String name = child.getName(); if (! name.equals(excludeRootChild)) { @@ -808,19 +775,10 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer if (batchChildIds.size() == batchSize || !childIdIterator.hasNext()) { - // native SQL - SQLQuery query = getSession() - .createSQLQuery( - " update avm_nodes set acl_id = null "+ - " where acl_id is not null " + - " and id in (:childIds) "+ - ""); + // execute the update + int batchUpdateCount = patchDAO.updateAVMNodesNullifyAcl(batchChildIds); - query.setParameterList("childIds", batchChildIds); - - int batchUpdateCount = (Integer)query.executeUpdate(); totalUpdateCount = totalUpdateCount + batchUpdateCount; - batchChildIds.clear(); } } @@ -843,18 +801,9 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer if (batchChildIds.size() == batchSize || !childIdIterator.hasNext()) { - // native SQL - SQLQuery query = getSession() - .createSQLQuery( - " update avm_nodes set acl_id = :aclId "+ - " where id in (:childIds) "+ - ""); + // execute the update + int batchUpdateCount = patchDAO.updateAVMNodesSetAcl(aclId, batchChildIds); - query.setParameterList("childIds", batchChildIds); - - query.setLong("aclId", aclId); - - int batchUpdateCount = (Integer)query.executeUpdate(); totalUpdateCount = totalUpdateCount + batchUpdateCount; batchChildIds.clear(); @@ -871,14 +820,14 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer { long rootId = getAVMStoreCurrentRootNodeId(storeName); - List> children = getAVMChildrenWithName(rootId); + List children = getAVMChildrenEntries(rootId); int totalUpdatedCount = 0; - for (Pair child : children) + for (AVMChildEntryEntity child : children) { - Long childId = child.getFirst(); - String name = child.getSecond(); + Long childId = child.getChildId(); + String name = child.getName(); if (name.equals(JNDIConstants.DIR_DEFAULT_WWW)) { @@ -911,14 +860,14 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer { long rootId = getAVMStoreCurrentRootNodeId(storeName); - List> children = getAVMChildrenWithName(rootId); + List children = getAVMChildrenEntries(rootId); List childIds = new ArrayList(1); - for (Pair child : children) + for (AVMChildEntryEntity child : children) { - Long childId = child.getFirst(); - String name = child.getSecond(); + Long childId = child.getChildId(); + String name = child.getName(); if (name.equals(JNDIConstants.DIR_DEFAULT_WWW)) { @@ -962,25 +911,11 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer return updatedCount; } - private int deleteDanglingAces() - { - // native SQL - SQLQuery query = getSession() - .createSQLQuery( - " delete from alf_access_control_entry "+ - " where id not in "+ - " (select distinct(m.ace_id) "+ - " from alf_acl_member m) "+ - ""); - - return (Integer)query.executeUpdate(); // return deleted count - } - // note: dangling shared acl currently possible (after creating new sandbox) private int deleteDanglingAcls() throws Exception { - Set nonDanglingAclIds = getNonDanglingAcls(); - Set aclIds = getAllAcls(); + List nonDanglingAclIds = patchDAO.selectNonDanglingAclIds(); + List aclIds = patchDAO.selectAllAclIds(); // get set of dangling acl ids aclIds.removeAll(nonDanglingAclIds); @@ -998,18 +933,10 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer if (batchAclIds.size() == batchSize || !aclIdIterator.hasNext()) { - // native SQL - SQLQuery query = getSession() - .createSQLQuery( - " delete from alf_acl_member "+ - " where acl_id in (:aclIds) "+ - ""); + // execute delete + int batchDeletedCount = patchDAO.deleteAclMembersForAcls(batchAclIds); - query.setParameterList("aclIds", batchAclIds); - - int batchDeletedCount = (Integer)query.executeUpdate(); totalDeletedCount = totalDeletedCount + batchDeletedCount; - batchAclIds.clear(); } } @@ -1032,18 +959,10 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer if (batchAclIds.size() == batchSize || !aclIdIterator.hasNext()) { - // native SQL - SQLQuery query = getSession() - .createSQLQuery( - " delete from alf_access_control_list "+ - " where id in (:aclIds) "+ - ""); + // execute delete + int batchDeletedCount = patchDAO.deleteAcls(batchAclIds); - query.setParameterList("aclIds", batchAclIds); - - int batchDeletedCount = (Integer)query.executeUpdate(); totalDeletedCount = totalDeletedCount + batchDeletedCount; - batchAclIds.clear(); } } @@ -1056,318 +975,49 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer return totalDeletedCount; } - private Set getNonDanglingAcls() - { - final Set aclIds = new HashSet(10000); - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - // native SQL - SQLQuery query = getSession().createSQLQuery( - " select acl_id from avm_nodes where acl_id is not null "+ - " union "+ - " select acl_id from avm_stores where acl_id is not null "+ - " union "+ - " select acl_id from alf_node where acl_id is not null "+ - " union "+ - " select acl_id from alf_attributes where acl_id is not null"); - - query.addScalar("acl_id", new LongType()); - - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults rs = null; - try - { - rs = (ScrollableResults) getHibernateTemplate().execute(callback); - while (rs.next()) - { - Long aclId = (Long) rs.get(0); - aclIds.add(aclId); - } - } - catch (Throwable e) - { - String msg = "Failed to query for non-dangling acls"; - logger.error(msg, e); - throw new PatchException(msg, e); - } - finally - { - if (rs != null) - { - try { rs.close(); } catch (Throwable e) { logger.error(e); } - } - } - return aclIds; - } - - private Set getAllAcls() - { - final Set aclIds = new HashSet(10000); - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - // native SQL - SQLQuery query = getSession().createSQLQuery("select id from alf_access_control_list "); - - query.addScalar("id", new LongType()); - - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults rs = null; - try - { - rs = (ScrollableResults) getHibernateTemplate().execute(callback); - while (rs.next()) - { - Long aclId = (Long) rs.get(0); - aclIds.add(aclId); - } - } - catch (Throwable e) - { - String msg = "Failed to query for all acls"; - logger.error(msg, e); - throw new PatchException(msg, e); - } - finally - { - if (rs != null) - { - try { rs.close(); } catch (Throwable e) { logger.error(e); } - } - } - return aclIds; - } - private long getAVMStoreCurrentRootNodeId(final String avmStoreName) { - // native SQL - SQLQuery query = getSession().createSQLQuery("select current_root_id as root_id from avm_stores where name = :name"); - - query.setString("name", avmStoreName); - query.addScalar("root_id", new LongType()); - - return (Long)query.uniqueResult(); + return avmStoreDAO.getStore(avmStoreName).getRootNodeId(); } private List getAVMChildren(final long parentId) { - final List childIds = new ArrayList(100); + List childEntries = getAVMChildrenEntries(parentId); + List childIds = new ArrayList(childEntries.size()); - HibernateCallback callback = new HibernateCallback() + for (AVMChildEntryEntity childEntry : childEntries) { - public Object doInHibernate(Session session) - { - // native SQL - SQLQuery query = getSession().createSQLQuery("select child_id as child_id from avm_child_entries where parent_id = :parentId"); - - query.setLong("parentId", parentId); - query.addScalar("child_id", new LongType()); - - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults rs = null; - try - { - rs = (ScrollableResults) getHibernateTemplate().execute(callback); - while (rs.next()) - { - Long childId = (Long) rs.get(0); - childIds.add(childId); - } - } - catch (Throwable e) - { - String msg = "Failed to query for child entries (parent_id = "+parentId+")"; - logger.error(msg, e); - throw new PatchException(msg, e); - } - finally - { - if (rs != null) - { - try { rs.close(); } catch (Throwable e) { logger.error(e); } - } + Long childId = (Long)childEntry.getChildId(); + childIds.add(childId); } return childIds; } - private List> getAVMChildrenWithName(final long parentId) + private List getAVMChildrenEntries(final long parentId) { - final List> children = new ArrayList>(100); - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - // native SQL - SQLQuery query = getSession().createSQLQuery("select child_id, name as name from avm_child_entries where parent_id = :parentId"); - - query.setLong("parentId", parentId); - query.addScalar("child_id", new LongType()); - query.addScalar("name", new StringType()); - - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults rs = null; - try - { - rs = (ScrollableResults) getHibernateTemplate().execute(callback); - while (rs.next()) - { - Long childId = (Long) rs.get(0); - String name = (String) rs.get(1); - children.add(new Pair(childId, name)); - } - } - catch (Throwable e) - { - String msg = "Failed to query for child entries (parent_id = "+parentId+")"; - logger.error(msg, e); - throw new PatchException(msg, e); - } - finally - { - if (rs != null) - { - try { rs.close(); } catch (Throwable e) { logger.error(e); } - } - } - return children; + return avmNodeLinksDAO.getChildEntriesByParent(parentId, null); } private long findOrCreateAce(final String authorityName, final String permissionName) throws Exception { - final DbPermission permission = findOrCreatePermission(permissionName); - final DbAuthority authority = findOrCreateAuthority(authorityName); + Authority authority = aclCrudDAO.getOrCreateAuthority(authorityName); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACE_WITH_NO_CONTEXT); - query.setParameter("permissionId", permission.getId()); - query.setParameter("authorityId", authority.getId()); - query.setParameter("allowed", true); - query.setParameter("applies", ACEType.ALL.getId()); - return query.uniqueResult(); - } - }; - DbAccessControlEntry entry = (DbAccessControlEntry) getHibernateTemplate().execute(callback); - - if (entry == null) - { - DbAccessControlEntryImpl newEntry = new DbAccessControlEntryImpl(); - - newEntry.setAceType(ACEType.ALL); - newEntry.setAllowed(true); - - newEntry.setAuthority(authority); - newEntry.setPermission(permission); - - entry = newEntry; - - // save - getHibernateTemplate().save(newEntry); - } - - return entry.getId(); - } - - private DbAuthority findOrCreateAuthority(final String authorityName) throws Exception - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_AUTHORITY); - query.setParameter("authority", authorityName); - return query.uniqueResult(); - } - }; - DbAuthority authority = (DbAuthority)getHibernateTemplate().execute(callback); - - if (authority == null) - { - DbAuthorityImpl newAuthority = new DbAuthorityImpl(); - newAuthority.setAuthority(authorityName); - newAuthority.setCrc(getCrc(authorityName)); - - authority = newAuthority; - - // save - getHibernateTemplate().save(newAuthority); - } - - return authority; - } - - private long getCrc(String str) - { - CRC32 crc = new CRC32(); - crc.update(str.getBytes()); - return crc.getValue(); - } - - private DbPermission findOrCreatePermission(final String permissionName) throws Exception - { QName permissionQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "cmobject"); - Pair permissionQNamePair = qnameDAO.getOrCreateQName(permissionQName); + SimplePermissionReference permRef = SimplePermissionReference.getPermissionReference(permissionQName, permissionName); - final Long qNameId = permissionQNamePair.getFirst(); - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_PERMISSION); - query.setParameter("permissionTypeQNameId", qNameId); - query.setParameter("permissionName", permissionName); - return query.uniqueResult(); - } - }; - DbPermission permission = (DbPermission)getHibernateTemplate().execute(callback); + Permission permission = aclCrudDAO.getOrCreatePermission(permRef); - if (permission == null) - { - DbPermissionImpl newPerm = new DbPermissionImpl(); - newPerm.setTypeQNameId(qNameId); - newPerm.setName(permissionName); - - permission = newPerm; - - // save - getHibernateTemplate().save(newPerm); - } - - return permission; + return aclCrudDAO.getOrCreateAce(permission, authority, ACEType.ALL, AccessStatus.ALLOWED).getId(); } - private DbAccessControlListChangeSet createAclChangeSet() throws Exception + private long createAcl(final long aclChangeSet, final ACLType aclType, boolean requiresVersion) throws Exception { - DbAccessControlListChangeSet changeSet = new DbAccessControlListChangeSetImpl(); - getHibernateTemplate().save(changeSet); - return changeSet; - } - - private long createAcl(final DbAccessControlListChangeSet aclChangeSet, final ACLType aclType, boolean requiresVersion) throws Exception - { - DbAccessControlListImpl acl = new DbAccessControlListImpl(); - + AclEntity acl = new AclEntity(); + acl.setAclId(GUID.generate()); acl.setAclType(aclType); acl.setAclVersion(Long.valueOf(1l)); - + switch (aclType) { case FIXED: @@ -1383,7 +1033,7 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer } acl.setLatest(Boolean.TRUE); - + switch (aclType) { case OLD: @@ -1398,67 +1048,30 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer acl.setVersioned(Boolean.TRUE); break; } - - acl.setAclChangeSet(aclChangeSet); + + acl.setAclChangeSetId(aclChangeSet); acl.setRequiresVersion(requiresVersion); // save - Long created = (Long) getHibernateTemplate().save(acl); - return created; + return aclCrudDAO.createAcl(acl).getId(); } private void updateAclInheritsFrom(final long aclId, final long inheritsFromId) throws Exception { - HibernateCallback callback = new HibernateCallback() - { - public Integer doInHibernate(Session session) - { - // native SQL - SQLQuery query = session - .createSQLQuery( - " update alf_access_control_list set inherits_from = :inheritsFromId where id = :aclId "); - - query.setLong("aclId", aclId); - query.setLong("inheritsFromId", inheritsFromId); - - return (Integer)query.executeUpdate(); - } - }; - - int updatedCount = (Integer)getHibernateTemplate().execute(callback); - if (updatedCount != 1) - { - throw new AlfrescoRuntimeException("Failed to update acl inheritsFrom"); - } + AclEntity aclEntity = aclCrudDAO.getAclForUpdate(aclId); + aclEntity.setInheritsFrom(inheritsFromId); + aclCrudDAO.updateAcl(aclEntity); } private void updateAclInherited(final long aclId, final long inheritedAclId) throws Exception { - HibernateCallback callback = new HibernateCallback() - { - public Integer doInHibernate(Session session) - { - // native SQL - SQLQuery query = session - .createSQLQuery( - " update alf_access_control_list set inherited_acl = :inheritedAclId where id = :aclId "); - - query.setLong("aclId", aclId); - query.setLong("inheritedAclId", inheritedAclId); - - return (Integer)query.executeUpdate(); - } - }; - - int updatedCount = (Integer)getHibernateTemplate().execute(callback); - if (updatedCount != 1) - { - throw new AlfrescoRuntimeException("Failed to update acl inherited"); - } + AclEntity aclEntity = aclCrudDAO.getAclForUpdate(aclId); + aclEntity.setInheritedAcl(inheritedAclId); + aclCrudDAO.updateAcl(aclEntity); } // assume groups exist, if permission does not exist then will be created - private Long createWCMGroupBasedAcl(String stagingStoreName, DbAccessControlListChangeSet aclChangeSet, ACLType aclType, boolean requiresVersion) throws Exception + private Long createWCMGroupBasedAcl(String stagingStoreName, long aclChangeSet, ACLType aclType, boolean requiresVersion) throws Exception { if (stagingStoreName.contains(WCM_STORE_SEPARATOR)) { @@ -1484,28 +1097,10 @@ public class ResetWCMToGroupBasedPermissionsPatch extends MoveWCMToGroupBasedPer aceIds.add(crAceId); aceIds.add(erAceId); - addAcesToAcl(aclId, aceIds, 0); + // create acl members + aclCrudDAO.addAclMembersToAcl(aclId, aceIds, 0); return aclId; } - - // create acl members - private void addAcesToAcl(long aclId, List aceIds, int depth) - { - DbAccessControlList acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, aclId); - - for (Long aceId : aceIds) - { - DbAccessControlEntry ace = (DbAccessControlEntry) getHibernateTemplate().get(DbAccessControlEntryImpl.class, aceId); - - DbAccessControlListMemberImpl newMember = new DbAccessControlListMemberImpl(); - newMember.setAccessControlList(acl); - newMember.setAccessControlEntry(ace); - newMember.setPosition(depth); - - // save - getHibernateTemplate().save(newMember); - } - } } } diff --git a/source/java/org/alfresco/repo/admin/patch/impl/WCMPostPermissionSnapshotPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/WCMPostPermissionSnapshotPatch.java index e6bfe19df4..e3f9491caa 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/WCMPostPermissionSnapshotPatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/WCMPostPermissionSnapshotPatch.java @@ -21,13 +21,13 @@ package org.alfresco.repo.admin.patch.impl; import java.util.ArrayList; import java.util.List; -import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.domain.patch.PatchDAO; import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor; import org.alfresco.repo.search.impl.lucene.AVMLuceneIndexer; -import org.alfresco.repo.security.permissions.impl.AclDaoComponent; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.AVMStoreDescriptor; +import org.springframework.extensions.surf.util.I18NUtil; /** * Snap shot all stores after applying the staging are permissions patch @@ -37,13 +37,13 @@ import org.alfresco.service.cmr.avm.AVMStoreDescriptor; public class WCMPostPermissionSnapshotPatch extends AbstractPatch { private static final String MSG_SUCCESS = "patch.wcmPostPermissionSnapshotPatch.result"; - - AVMSnapShotTriggeredIndexingMethodInterceptor avmSnapShotTriggeredIndexingMethodInterceptor; - - AVMService avmService; - - AclDaoComponent aclDaoComponent; - + + private AVMSnapShotTriggeredIndexingMethodInterceptor avmSnapShotTriggeredIndexingMethodInterceptor; + + private AVMService avmService; + + private PatchDAO patchDAO; + public void setAvmService(AVMService avmService) { this.avmService = avmService; @@ -54,9 +54,9 @@ public class WCMPostPermissionSnapshotPatch extends AbstractPatch this.avmSnapShotTriggeredIndexingMethodInterceptor = avmSnapShotTriggeredIndexingMethodInterceptor; } - public void setAclDaoComponent(AclDaoComponent aclDaoComponent) + public void setPatchDAO(PatchDAO patchDAO) { - this.aclDaoComponent = aclDaoComponent; + this.patchDAO = patchDAO; } @Override @@ -66,7 +66,7 @@ public class WCMPostPermissionSnapshotPatch extends AbstractPatch Thread progressThread = null; - Long toDo = aclDaoComponent.getNewInStore(); + Long toDo = patchDAO.getAVMNodesCountWhereNewInStore(); List indexers = new ArrayList(stores.size()); for (AVMStoreDescriptor storeDesc : stores) diff --git a/source/java/org/alfresco/repo/attributes/AbstractAttribute.java b/source/java/org/alfresco/repo/attributes/AbstractAttribute.java deleted file mode 100644 index 57bda11c83..0000000000 --- a/source/java/org/alfresco/repo/attributes/AbstractAttribute.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; -import java.util.Map.Entry; - -import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; -import org.alfresco.service.cmr.repository.datatype.TypeConversionException; - -/** - * Base class for handling basic type conversions. - * - * @author Derek Hulley - * @since V2.1.2 - */ -public abstract class AbstractAttribute implements Attribute -{ - public final AttributeImpl getAttributeImpl() - { - if (this instanceof AttributeImpl) - { - // No conversion necessary - return (AttributeImpl) this; - } - else - { - // Use Type's factory method - return getType().getAttributeImpl(this); - } - } - - public final AttributeValue getAttributeValue() - { - if (this instanceof AttributeValue) - { - // No conversion necessary - return (AttributeValue) this; - } - else - { - // Use Type's factory method - return getType().getAttributeValue(this); - } - } - - /** - * {@link ListAttributeValue}-specific method. - */ - public void add(Attribute attr) - { - throw new AttributeMethodNotImplemented("Not a List."); - } - - /** - * {@link ListAttributeValue}-specific method. - */ - public void add(int index, Attribute attr) - { - throw new AttributeMethodNotImplemented("Not a List."); - } - - /** - * {@link ListAttributeValue}-specific method. - */ - public Iterator iterator() - { - throw new AttributeMethodNotImplemented("Not a List."); - } - - /** - * {@link ListAttributeValue} or {@link MapAttributeValue}-specific method. - */ - public int size() - { - throw new AttributeMethodNotImplemented("Not a List or Map."); - } - - /** - * {@link ListAttributeValue}-specific method. - */ - public Attribute get(int index) - { - throw new AttributeMethodNotImplemented("Not a List."); - } - - /** - * {@link ListAttributeValue}-specific method. - */ - public void remove(int index) - { - throw new AttributeMethodNotImplemented("Not a List."); - } - - /** - * {@link ListAttributeValue}-specific method. - */ - public void set(int index, Attribute value) - { - throw new AttributeMethodNotImplemented("Not a List."); - } - - /** - * {@link MapAttributeValue}-specific method. - */ - public void clear() - { - throw new AttributeMethodNotImplemented("Not a Map."); - } - - /** - * {@link MapAttributeValue}-specific method. - */ - public Set> entrySet() - { - throw new AttributeMethodNotImplemented("Not a Map."); - } - - /** - * {@link MapAttributeValue}-specific method. - */ - public Set keySet() - { - throw new AttributeMethodNotImplemented("Not a map."); - } - - /** - * {@link MapAttributeValue}-specific method. - */ - public Collection values() - { - throw new AttributeMethodNotImplemented("Not a map."); - } - - /** - * {@link MapAttributeValue}-specific method. - */ - public void put(String key, Attribute value) - { - throw new AttributeMethodNotImplemented("Not a map."); - } - - /** - * {@link MapAttributeValue}-specific method. - */ - public void remove(String key) - { - throw new AttributeMethodNotImplemented("Not a map."); - } - - /** - * {@link MapAttributeValue}-specific method. - */ - public Attribute get(String key) - { - throw new AttributeMethodNotImplemented("Not a Map."); - } - - public byte[] getBlobValue() - { - Serializable raw = getRawValue(); - // Just serialize it - try - { - ByteArrayOutputStream bos = new ByteArrayOutputStream(1024); - ObjectOutputStream oos = new ObjectOutputStream(bos); - oos.writeObject(raw); - byte[] bytes = bos.toByteArray(); - return bytes; - } - catch (IOException e) - { - throw new TypeConversionException("Unable to get blob value: " + this); - } - } - - public boolean getBooleanValue() - { - Serializable raw = getRawValue(); - try - { - Boolean obj = DefaultTypeConverter.INSTANCE.convert(Boolean.class, raw); - return obj; - } - catch (TypeConversionException e) - { - throw new AttributeMethodNotImplemented("Unable to convert to Boolean value: " + this); - } - } - - public byte getByteValue() - { - Serializable raw = getRawValue(); - try - { - Byte obj = DefaultTypeConverter.INSTANCE.convert(Byte.class, raw); - return obj; - } - catch (TypeConversionException e) - { - throw new AttributeMethodNotImplemented("Unable to convert to Byte value: " + this); - } - } - - public short getShortValue() - { - Serializable raw = getRawValue(); - try - { - Short obj = DefaultTypeConverter.INSTANCE.convert(Short.class, raw); - return obj; - } - catch (TypeConversionException e) - { - throw new AttributeMethodNotImplemented("Unable to convert to Short value: " + this); - } - } - - public int getIntValue() - { - Serializable raw = getRawValue(); - try - { - Integer obj = DefaultTypeConverter.INSTANCE.convert(Integer.class, raw); - return obj; - } - catch (TypeConversionException e) - { - throw new AttributeMethodNotImplemented("Unable to convert to Integer value: " + this); - } - } - - public long getLongValue() - { - Serializable raw = getRawValue(); - try - { - Long obj = DefaultTypeConverter.INSTANCE.convert(Long.class, raw); - return obj; - } - catch (TypeConversionException e) - { - throw new AttributeMethodNotImplemented("Unable to convert to Long value: " + this); - } - } - - public double getDoubleValue() - { - Serializable raw = getRawValue(); - try - { - Double obj = DefaultTypeConverter.INSTANCE.convert(Double.class, raw); - return obj; - } - catch (TypeConversionException e) - { - throw new AttributeMethodNotImplemented("Unable to convert to Double value: " + this); - } - } - - public float getFloatValue() - { - Serializable raw = getRawValue(); - try - { - Float obj = DefaultTypeConverter.INSTANCE.convert(Float.class, raw); - return obj; - } - catch (TypeConversionException e) - { - throw new AttributeMethodNotImplemented("Unable to convert to Float value: " + this); - } - } - - public String getStringValue() - { - Serializable raw = getRawValue(); - try - { - String obj = DefaultTypeConverter.INSTANCE.convert(String.class, raw); - return obj; - } - catch (TypeConversionException e) - { - throw new AttributeMethodNotImplemented("Unable to convert to String value: " + this); - } - } - - public Serializable getSerializableValue() - { - // This can always be fulfilled by the raw value - return getRawValue(); - } - - public void setBlobValue(byte[] value) - { - throw new AttributeMethodNotImplemented("Not a Blob."); - } - - public void setBooleanValue(boolean value) - { - throw new AttributeMethodNotImplemented("Not a boolean."); - } - - public void setByteValue(byte value) - { - throw new AttributeMethodNotImplemented("Not a byte."); - } - - public void setShortValue(short value) - { - throw new AttributeMethodNotImplemented("Not a short."); - } - - public void setIntValue(int value) - { - throw new AttributeMethodNotImplemented("Not an int."); - } - - public void setLongValue(long value) - { - throw new AttributeMethodNotImplemented("Not a long."); - } - - public void setDoubleValue(double value) - { - throw new AttributeMethodNotImplemented("Not a double."); - } - - public void setFloatValue(float value) - { - throw new AttributeMethodNotImplemented("Not a float."); - } - - public void setStringValue(String value) - { - throw new AttributeMethodNotImplemented("Not a String."); - } - - public void setSerializableValue(Serializable value) - { - throw new AttributeMethodNotImplemented("Not a Serializable."); - } -} diff --git a/source/java/org/alfresco/repo/attributes/AtrributeMethodNotImplemented.java b/source/java/org/alfresco/repo/attributes/AtrributeMethodNotImplemented.java deleted file mode 100644 index f4d62d324e..0000000000 --- a/source/java/org/alfresco/repo/attributes/AtrributeMethodNotImplemented.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import org.alfresco.error.AlfrescoRuntimeException; - -/** - * For unimplemented attribute methods. - * @author britt - */ -public class AtrributeMethodNotImplemented extends AlfrescoRuntimeException -{ - private static final long serialVersionUID = -7167699355451456957L; - - public AtrributeMethodNotImplemented(String message) - { - super(message); - } -} diff --git a/source/java/org/alfresco/repo/attributes/AttrQueryHelperImpl.java b/source/java/org/alfresco/repo/attributes/AttrQueryHelperImpl.java deleted file mode 100644 index bf7b1fc719..0000000000 --- a/source/java/org/alfresco/repo/attributes/AttrQueryHelperImpl.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.util.HashMap; -import java.util.Map; - -import org.alfresco.service.cmr.attributes.AttrQueryHelper; - -/** - * Implementation of query helper for building predicates. - * @author britt - */ -public class AttrQueryHelperImpl implements AttrQueryHelper -{ - private int fSuffix; - - private Map fParameters; - - public AttrQueryHelperImpl() - { - fSuffix = 0; - fParameters = new HashMap(); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttrQueryHelper#getNextSuffix() - */ - public int getNextSuffix() - { - return fSuffix++; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttrQueryHelper#getParameters() - */ - public Map getParameters() - { - return fParameters; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttrQueryHelper#setParameter(java.lang.String, java.lang.String) - */ - public void setParameter(String name, String value) - { - fParameters.put(name, value); - } -} diff --git a/source/java/org/alfresco/repo/attributes/AttrQueryTest.java b/source/java/org/alfresco/repo/attributes/AttrQueryTest.java deleted file mode 100644 index 0b5f71e197..0000000000 --- a/source/java/org/alfresco/repo/attributes/AttrQueryTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import org.alfresco.service.cmr.attributes.AttrAndQuery; -import org.alfresco.service.cmr.attributes.AttrNotQuery; -import org.alfresco.service.cmr.attributes.AttrOrQuery; -import org.alfresco.service.cmr.attributes.AttrQuery; -import org.alfresco.service.cmr.attributes.AttrQueryGT; -import org.alfresco.service.cmr.attributes.AttrQueryHelper; -import org.alfresco.service.cmr.attributes.AttrQueryLT; -import org.alfresco.service.cmr.attributes.AttrQueryLike; - -import junit.framework.TestCase; - -/** - * Tests of AttrQueries. - * @author britt - */ -public class AttrQueryTest extends TestCase -{ - private AttrQueryHelper fHelper; - - /* (non-Javadoc) - * @see junit.framework.TestCase#setUp() - */ - @Override - protected void setUp() throws Exception - { - fHelper = new AttrQueryHelperImpl(); - } - - /** - * Do all the testing in one. - */ - public void testAll() - { - AttrQuery query = - new AttrOrQuery( - new AttrAndQuery(new AttrQueryGT("cat"), new AttrQueryLT("hat")), - new AttrNotQuery(new AttrQueryLike("fur%"))); - String predicate = query.getPredicate(fHelper); - System.out.println(predicate); - System.out.println(fHelper.getParameters()); - assertEquals("((me.key.key > :name0 and me.key.key < :name1) or (not me.key.key like :name2))", - predicate); - assertEquals("cat", fHelper.getParameters().get("name0")); - assertEquals("hat", fHelper.getParameters().get("name1")); - assertEquals("fur%", fHelper.getParameters().get("name2")); - } -} diff --git a/source/java/org/alfresco/repo/attributes/Attribute.java b/source/java/org/alfresco/repo/attributes/Attribute.java deleted file mode 100644 index cc72857b3d..0000000000 --- a/source/java/org/alfresco/repo/attributes/Attribute.java +++ /dev/null @@ -1,648 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.schema.SchemaBootstrap; - -/** - * Interface for polymorphic attributes. - * @author britt - */ -public interface Attribute extends Serializable, Iterable -{ - public static enum Type implements Serializable - { - BOOLEAN - { - @Override - public AttributeValue getAttributeValue(Attribute from) - { - if (from instanceof BooleanAttribute) - { - return new BooleanAttributeValue((BooleanAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - - @Override - public AttributeImpl getAttributeImpl(Attribute from) - { - if (from instanceof BooleanAttribute) - { - return new BooleanAttributeImpl((BooleanAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - }, - BYTE - { - @Override - public AttributeValue getAttributeValue(Attribute from) - { - if (from instanceof ByteAttribute) - { - return new ByteAttributeValue((ByteAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - - @Override - public AttributeImpl getAttributeImpl(Attribute from) - { - if (from instanceof ByteAttribute) - { - return new ByteAttributeImpl((ByteAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - }, - SHORT - { - @Override - public AttributeValue getAttributeValue(Attribute from) - { - if (from instanceof ShortAttribute) - { - return new ShortAttributeValue((ShortAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - - @Override - public AttributeImpl getAttributeImpl(Attribute from) - { - if (from instanceof ShortAttribute) - { - return new ShortAttributeImpl((ShortAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - }, - INT - { - @Override - public AttributeValue getAttributeValue(Attribute from) - { - if (from instanceof IntAttribute) - { - return new IntAttributeValue((IntAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - - @Override - public AttributeImpl getAttributeImpl(Attribute from) - { - if (from instanceof IntAttribute) - { - return new IntAttributeImpl((IntAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - }, - LONG - { - @Override - public AttributeValue getAttributeValue(Attribute from) - { - if (from instanceof LongAttribute) - { - return new LongAttributeValue((LongAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - - @Override - public AttributeImpl getAttributeImpl(Attribute from) - { - if (from instanceof LongAttribute) - { - return new LongAttributeImpl((LongAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - }, - FLOAT - { - @Override - public AttributeValue getAttributeValue(Attribute from) - { - if (from instanceof FloatAttribute) - { - return new FloatAttributeValue((FloatAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - - @Override - public AttributeImpl getAttributeImpl(Attribute from) - { - if (from instanceof FloatAttribute) - { - return new FloatAttributeImpl((FloatAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - }, - DOUBLE - { - @Override - public AttributeValue getAttributeValue(Attribute from) - { - if (from instanceof DoubleAttribute) - { - return new DoubleAttributeValue((DoubleAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - - @Override - public AttributeImpl getAttributeImpl(Attribute from) - { - if (from instanceof DoubleAttribute) - { - return new DoubleAttributeImpl((DoubleAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - }, - STRING - { - @Override - public AttributeValue getAttributeValue(Attribute from) - { - if (from instanceof StringAttribute) - { - return new StringAttributeValue((StringAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - - @Override - public AttributeImpl getAttributeImpl(Attribute from) - { - if (from instanceof StringAttribute) - { - // We need to check that the String will fit into the database - StringAttribute stringAttr = (StringAttribute) from; - String stringValue = stringAttr.getStringValue(); - - if (stringValue != null && stringValue.length() > SchemaBootstrap.getMaxStringLength()) - { - // Need to serialize it - return new SerializableAttributeImpl(stringValue); - } - else - { - return new StringAttributeImpl(stringValue); - } - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - }, - SERIALIZABLE - { - @Override - public AttributeValue getAttributeValue(Attribute from) - { - if (from instanceof SerializableAttribute) - { - return new SerializableAttributeValue((SerializableAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - - @Override - public AttributeImpl getAttributeImpl(Attribute from) - { - if (from instanceof SerializableAttribute) - { - return new SerializableAttributeImpl((SerializableAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - }, - MAP - { - @Override - public AttributeValue getAttributeValue(Attribute from) - { - if (from instanceof MapAttribute) - { - return new MapAttributeValue((MapAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - - @Override - public AttributeImpl getAttributeImpl(Attribute from) - { - if (from instanceof MapAttribute) - { - return new MapAttributeImpl((MapAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - }, - LIST - { - @Override - public AttributeValue getAttributeValue(Attribute from) - { - if (from instanceof ListAttribute) - { - return new ListAttributeValue((ListAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - - @Override - public AttributeImpl getAttributeImpl(Attribute from) - { - if (from instanceof ListAttribute) - { - return new ListAttributeImpl((ListAttribute)from); - } - else - { - throw new IllegalArgumentException( - "Conversion to " + this + " not supported for " + from.getType() + "(" + from + ")"); - } - } - }; - - /** - * Get the unpersisted attribute value implementation of the {@link Attribute} given an existing attribute. - * The from attribute may be a persistable entity or not but a new instance will - * be created. - *

- * No assumptions should be made about the return type. The raw type might not match the persisted type. - * - * @param from the instance supplying the data - * @return Returns a value object based on the provided data - */ - public abstract AttributeValue getAttributeValue(Attribute from); - - /** - * Get a persistable implementation of the {@link Attribute} given an existing attribute. - * The from attribute may be a persistable entity or not but a new instance will - * be created. - *

- * No assumptions should be made about the return type. It is possible that the data will - * be converted to a different persistable type. - * - * @param from the instance supplying the data - * @return Returns a persistable entity based on the provided data - */ - public abstract AttributeImpl getAttributeImpl(Attribute from); - }; - - /** - * Set the ACL on this Attribute. - * @param acl The ACL. - */ - public void setAcl(DbAccessControlList acl); - - /** - * Get the (possibly null ACL) on this Attribute. - * @return The ACL or null. - */ - public DbAccessControlList getAcl(); - - /** - * @return the enumerated type - */ - public Type getType(); - - /** - * Method to return the underlying raw data for possible conversion to the descired type. - * @return Returns a raw data value - */ - public Serializable getRawValue(); - - /** - * @see Type#getAttributeValue(Attribute) - */ - public abstract AttributeValue getAttributeValue(); - - /** - * @see Type#getAttributeImpl(Attribute) - */ - public abstract AttributeImpl getAttributeImpl(); - - /** - * Set a boolean value. - * @param value The value. - */ - public void setBooleanValue(boolean value); - - /** - * Get the value of a BooleanValue. - * @return The value. - */ - public boolean getBooleanValue(); - - /** - * Set a byte value. - * @param value The value to set. - */ - public void setByteValue(byte value); - - /** - * Get the value of a ByteValue. - * @return The value. - */ - public byte getByteValue(); - - /** - * Set a short value. - * @param value The value to set. - */ - public void setShortValue(short value); - - /** - * Get the value of a ShortValue. - * @return The value. - */ - public short getShortValue(); - - /** - * Set an integer value. - * @param value The value to set. - */ - public void setIntValue(int value); - - /** - * Get the integer value of an IntValue. - * @return The value. - */ - public int getIntValue(); - - /** - * Set a long value. - * @param value The value to set. - */ - public void setLongValue(long value); - - /** - * Get the long value of a LongValue. - * @return The value. - */ - public long getLongValue(); - - /** - * Set a float value. - * @param value The value to set. - */ - public void setFloatValue(float value); - - /** - * Get the value of a FloatValue. - * @return The value. - */ - public float getFloatValue(); - - /** - * Set a double value. - * @param value The value to set. - */ - public void setDoubleValue(double value); - - /** - * Get a double value from a DoubleValue. - * @return The value. - */ - public double getDoubleValue(); - - /** - * Set a String value. - * @param value The value to set. - */ - public void setStringValue(String value); - - /** - * Get a String value from a StringValue. - * @return The value. - */ - public String getStringValue(); - - /** - * Set a Blob value. - * @param value The value to set. - */ - public void setBlobValue(byte[] value); - - /** - * Get a Blob value from a BlobValue - * @return The value. - */ - public byte[] getBlobValue(); - - /** - * Set a Serializable value. - * @param value - */ - public void setSerializableValue(Serializable value); - - /** - * Get a Seriailizable value from a SerializableValue - * @return The value. - */ - public Serializable getSerializableValue(); - - /** - * Clear a map. - */ - public void clear(); - - /** - * Add an entry to a map. - * @param key The key to the entry. - * @param value The Value of the entry. - */ - public void put(String key, Attribute value); - - /** - * Get the Value for a key in a map. - * @param key The key. - * @return The value. - */ - public Attribute get(String key); - - /** - * Remove an entry by key from a map. - * @param key The key of the entry to remove. - */ - public void remove(String key); - - /** - * Get the entry set for a map. - * @return The entry set. - */ - public Set> entrySet(); - - /** - * Get the key set for a map. - * @return The key set. - */ - public Set keySet(); - - /** - * Get the collection of values of a map. - * @return The values. - */ - public Collection values(); - - /** - * Add an attribute to a list attribute. - * @param attr - */ - public void add(Attribute attr); - - /** - * Add an attribute to a list attribute at a given position. - * @param index The offset. - * @param attr The attribute. - */ - public void add(int index, Attribute attr); - - /** - * Get the size of a List of a Map. - * @return - */ - public int size(); - - /** - * Get an iterator over a list's entries. - * @return - */ - public Iterator iterator(); - - /** - * Get an Attribute from a List. - * @param index The offset. - * @return The Attribute or null. - */ - public Attribute get(int index); - - /** - * Remove an entry from a list. - * @param index The entry to remove. - */ - public void remove(int index); - - /** - * Set an attribute in a list. - * @param index The index to set. - * @param value The attribute to set. - */ - public void set(int index, Attribute value); -} diff --git a/source/java/org/alfresco/repo/attributes/AttributeConverter.java b/source/java/org/alfresco/repo/attributes/AttributeConverter.java deleted file mode 100644 index b131ff39d5..0000000000 --- a/source/java/org/alfresco/repo/attributes/AttributeConverter.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import org.alfresco.repo.avm.AVMDAOs; - -/** - * Handles conversions between persistent and value based Attributes. - * - * @see Attribute.Type#getAttributeImpl(Attribute) - * @see Attribute.Type#getAttributeValue(Attribute) - * - * @author britt - */ -public class AttributeConverter -{ - /** - * Convert an Attribute (recursively) to a persistent attribute. This persists - * the newly created Attribute immediately. - * @param from The Attribute to clone. - * @return The cloned persistent Attribute. - */ - public Attribute toPersistent(Attribute from) - { - AttributeImpl attributeEntity = from.getAttributeImpl(); - // Done - return attributeEntity; - } - - public Attribute toValue(Attribute from) - { - AttributeValue attributeValue = from.getAttributeValue(); - AVMDAOs.Instance().fAttributeDAO.evictFlat(from); - // Done - return attributeValue; - } -} diff --git a/source/java/org/alfresco/repo/attributes/AttributeDAO.java b/source/java/org/alfresco/repo/attributes/AttributeDAO.java deleted file mode 100644 index d7261f1a1d..0000000000 --- a/source/java/org/alfresco/repo/attributes/AttributeDAO.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.util.List; - -import org.alfresco.repo.domain.hibernate.DirtySessionAnnotation; -import org.alfresco.service.cmr.attributes.AttrQuery; -import org.alfresco.util.Pair; - -/** - * Interface for persistence operations on attributes. - * @author britt - */ -public interface AttributeDAO -{ - /** - * Save an attribute (recursively). - * @param attr The attribute to save. - */ - @DirtySessionAnnotation(markDirty=true) - public void save(Attribute attr); - - /** - * Delete an attribute (recursively). - * @param attr The attribute to delete. - */ - @DirtySessionAnnotation(markDirty=true) - public void delete(Attribute attr); - - /** - * Find all attributes that match a given path and AttrQuery. - * @param map The map within which to query. - * @param query The AttrQuery. - * @return A List of key, attribute value pairs. - */ - @DirtySessionAnnotation(markDirty=false) - public List> find(MapAttribute map, AttrQuery query); - - /** - * Delete entries from a map that match the given query. - * @param map - * @param query - */ - @DirtySessionAnnotation(markDirty=true) - public void delete(MapAttribute map, AttrQuery query); - - /** - * Evict an Attribute from the session cache. - * @param attr - */ - @DirtySessionAnnotation(markDirty=false) - public void evict(Attribute attr); - - /** - * Evict an Attribute non-recursively. - * @param attr - */ - @DirtySessionAnnotation(markDirty=false) - public void evictFlat(Attribute attr); - - /** - * Force a flush. - */ - @DirtySessionAnnotation(markDirty=false) - public void flush(); -} diff --git a/source/java/org/alfresco/repo/attributes/AttributeImpl.java b/source/java/org/alfresco/repo/attributes/AttributeImpl.java deleted file mode 100644 index 4ba679ae56..0000000000 --- a/source/java/org/alfresco/repo/attributes/AttributeImpl.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import org.alfresco.repo.domain.DbAccessControlList; - -/** - * The base class of the implementation of Values. - * @author britt - */ -public abstract class AttributeImpl extends AbstractAttribute implements Attribute -{ - /** - * The primary key. - */ - private long fID; - - /** - * The optimistic locking version. - */ - private long fVersion; - - /** - * ACL for this Attribute. - */ - private DbAccessControlList fACL; - - /** - * Base constructor. - */ - protected AttributeImpl() - { - } - - /** - * Helper constructor for copy constructors. - * @param acl The ACL. - */ - protected AttributeImpl(DbAccessControlList acl) - { - fACL = acl; - } - - public void setId(long id) - { - fID = id; - } - - public long getId() - { - return fID; - } - - public void setVersion(long version) - { - fVersion = version; - } - - public long getVersion() - { - return fVersion; - } - - public DbAccessControlList getAcl() - { - return fACL; - } - - public void setAcl(DbAccessControlList acl) - { - fACL = acl; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (!(obj instanceof AttributeImpl)) - { - return false; - } - return fID == ((AttributeImpl)obj).fID; - } - - @Override - public int hashCode() - { - return (int)fID; - } -} diff --git a/source/java/org/alfresco/repo/attributes/AttributeMethodNotImplemented.java b/source/java/org/alfresco/repo/attributes/AttributeMethodNotImplemented.java deleted file mode 100644 index 29a612a4cd..0000000000 --- a/source/java/org/alfresco/repo/attributes/AttributeMethodNotImplemented.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import org.alfresco.error.AlfrescoRuntimeException; - -/** - * For unimplemented attribute methods. - * @author britt - */ -public class AttributeMethodNotImplemented extends AlfrescoRuntimeException -{ - private static final long serialVersionUID = -7167699355451456957L; - - public AttributeMethodNotImplemented(String message) - { - super(message); - } -} diff --git a/source/java/org/alfresco/repo/attributes/AttributeServiceImpl.java b/source/java/org/alfresco/repo/attributes/AttributeServiceImpl.java index 1d999742de..59605089f8 100644 --- a/source/java/org/alfresco/repo/attributes/AttributeServiceImpl.java +++ b/source/java/org/alfresco/repo/attributes/AttributeServiceImpl.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,658 +14,272 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.alfresco.repo.attributes.Attribute.Type; -import org.alfresco.service.cmr.attributes.AttrQuery; -import org.alfresco.service.cmr.attributes.AttributeService; -import org.alfresco.service.cmr.avm.AVMBadArgumentException; -import org.alfresco.service.cmr.avm.AVMNotFoundException; -import org.alfresco.service.cmr.avm.AVMWrongTypeException; -import org.alfresco.util.Pair; - -/** - * Implementation of the AttributeService interface. - * @author britt - */ -public class AttributeServiceImpl implements AttributeService -{ - private GlobalAttributeEntryDAO fGlobalAttributeEntryDAO; - - private AttributeDAO fAttributeDAO; - - private AttributeConverter fAttributeConverter; - - public AttributeServiceImpl() - { - } - - public void setGlobalAttributeEntryDao(GlobalAttributeEntryDAO dao) - { - fGlobalAttributeEntryDAO = dao; - } - - public void setAttributeDao(AttributeDAO dao) - { - fAttributeDAO = dao; - } - - public void setAttributeConverter(AttributeConverter converter) - { - fAttributeConverter = converter; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#getAttribute(java.lang.String) - */ - public Attribute getAttribute(String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path."); - } - List keys = parsePath(path); - return getAttribute(keys); - } - - /** - * Utility to parse paths. Paths are of the form '/name/name'. '\' can - * be used to escape '/'s. - * @param path The path to parse. - * @return The components of the path. - */ - private List parsePath(String path) - { - List components = new ArrayList(); - int off = 0; - while (off < path.length()) - { - while (off < path.length() && path.charAt(off) == '/') - { - off++; - } - StringBuilder builder = new StringBuilder(); - while (off < path.length()) - { - char c = path.charAt(off); - if (c == '/') - { - break; - } - if (c == '\\') - { - off++; - if (off >= path.length()) - { - break; - } - c = path.charAt(off); - } - builder.append(c); - off++; - } - components.add(builder.toString()); - } - return components; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#query(java.lang.String, org.alfresco.service.cmr.attributes.AttrQuery) - */ - public List> query(String path, AttrQuery query) - { - if (path == null) - { - throw new AVMBadArgumentException("Null Attribute Path."); - } - List keys = parsePath(path); - return query(keys, query); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#removeAttribute(java.lang.String) - */ - public void removeAttribute(String path, String name) - { - if (path == null) - { - throw new AVMBadArgumentException("Null Attribute Path."); - } - List keys = parsePath(path); - removeAttribute(keys, name); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#setAttribute(java.lang.String, org.alfresco.repo.attributes.Attribute) - */ - public void setAttribute(String path, String name, Attribute value) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path."); - } - List keys = parsePath(path); - setAttribute(keys, name, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#getKeys(java.lang.String) - */ - public List getKeys(String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Null Attribute Path."); - } - List keys = parsePath(path); - return getKeys(keys); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#getAttribute(java.util.List) - */ - public Attribute getAttribute(List keys) - { - if (keys == null) - { - throw new AVMBadArgumentException("Null Attribute Path List."); - } - if (keys.size() < 1) - { - throw new AVMBadArgumentException("Bad Attribute Path List."); - } - Attribute found = getAttributeFromPath(keys); - if (found == null) - { - return null; - } - Attribute converted = fAttributeConverter.toValue(found); - return converted; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#getKeys(java.util.List) - */ - public List getKeys(List keys) - { - if (keys == null) - { - throw new AVMBadArgumentException("Null Keys List."); - } - if (keys.size() == 0) - { - return fGlobalAttributeEntryDAO.getKeys(); - } - Attribute found = getAttributeFromPath(keys); - if (found == null) - { - throw new AVMNotFoundException("Attribute Not Found: " + keys); - } - if (found.getType() != Type.MAP) - { - throw new AVMWrongTypeException("Not a Map: " + keys.get(keys.size() - 1)); - } - return new ArrayList(found.keySet()); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#setAttribute(java.util.List, java.lang.String, org.alfresco.repo.attributes.Attribute) - */ - public void setAttribute(List keys, String name, Attribute value) - { - if (keys == null || name == null || value == null) - { - throw new AVMBadArgumentException("Null argument."); - } - if (keys.size() == 0) - { - Attribute toSave = fAttributeConverter.toPersistent(value); - GlobalAttributeEntry found = fGlobalAttributeEntryDAO.get(name); - if (found == null) - { - found = new GlobalAttributeEntryImpl(name, toSave); - fGlobalAttributeEntryDAO.save(found); - return; - } - found.setAttribute(toSave); - return; - } - Attribute found = getAttributeFromPath(keys); - if (found == null) - { - throw new AVMNotFoundException("Attribute Not Found: " + keys); - } - if (found.getType() != Type.MAP) - { - throw new AVMWrongTypeException("Not a Map: " + keys); - } - Attribute converted = fAttributeConverter.toPersistent(value); - found.put(name, converted); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#query(java.util.List, org.alfresco.service.cmr.attributes.AttrQuery) - */ - public List> query(List keys, AttrQuery query) - { - if (keys == null || query == null) - { - throw new AVMBadArgumentException("Null argument."); - } - if (keys.size() == 0) - { - throw new AVMBadArgumentException("Cannot query top level Attributes."); - } - Attribute found = getAttributeFromPath(keys); - if (found == null) - { - throw new AVMNotFoundException("Attribute Not Found: " + keys); - } - if (found.getType() != Type.MAP) - { - throw new AVMWrongTypeException("Not a Map: " + keys); - } - List> rawResult = - fAttributeDAO.find((MapAttribute)found, query); - List> result = - new ArrayList>(); - for (Pair raw : rawResult) - { - result.add(new Pair(raw.getFirst(), - fAttributeConverter.toValue(raw.getSecond()))); - } - return result; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#removeAttribute(java.util.List, java.lang.String) - */ - public void removeAttribute(List keys, String name) - { - if (keys == null || name == null) - { - throw new AVMBadArgumentException("Null argument."); - } - if (keys.size() == 0) - { - fGlobalAttributeEntryDAO.delete(name); - return; - } - Attribute found = getAttributeFromPath(keys); - if (found == null) - { - throw new AVMNotFoundException("Attribute Not Found: " + keys); - } - if (found.getType() != Type.MAP) - { - throw new AVMWrongTypeException("Attribute Not Map: " + keys); - } - found.remove(name); - fAttributeDAO.flush(); - fAttributeDAO.evictFlat(found); - } - - private Attribute getAttributeFromPath(List keys) - { - GlobalAttributeEntry entry = fGlobalAttributeEntryDAO.get(keys.get(0)); - if (entry == null) - { - return null; - } - Attribute current = entry.getAttribute(); - for (int i = 1; i < keys.size(); i++) - { - if (current.getType() == Type.MAP) - { - Attribute newCurrent = current.get(keys.get(i)); - fAttributeDAO.evictFlat(current); - current = newCurrent; - } - else if (current.getType() == Type.LIST) - { - Attribute newCurrent = current.get(Integer.parseInt(keys.get(i))); - fAttributeDAO.evictFlat(current); - current = newCurrent; - } - else - { - throw new AVMWrongTypeException("Not a Map or List: " + keys.get(i - 1)); - } - if (current == null) - { - return null; - } - } - return current; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#addAttribute(java.util.List, org.alfresco.repo.attributes.Attribute) - */ - public void addAttribute(List keys, Attribute value) - { - if (keys == null || value == null) - { - throw new AVMBadArgumentException("Illegal Null Argument."); - } - if (keys.size() < 1) - { - throw new AVMBadArgumentException("Path too short: " + keys); - } - Attribute found = getAttributeFromPath(keys); - if (found == null) - { - throw new AVMNotFoundException("Attribute Not Found: " + keys); - } - if (found.getType() != Type.LIST) - { - throw new AVMWrongTypeException("Attribute Not List: " + keys); - } - found.add(fAttributeConverter.toPersistent(value)); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#addAttribute(java.lang.String, org.alfresco.repo.attributes.Attribute) - */ - public void addAttribute(String path, Attribute value) - { - if (path == null || value == null) - { - throw new AVMBadArgumentException("Illegal null arguments."); - } - List keys = parsePath(path); - addAttribute(keys, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#removeAttribute(java.util.List, int) - */ - public void removeAttribute(List keys, int index) - { - if (keys == null) - { - throw new AVMBadArgumentException("Illegal Null Keys."); - } - if (keys.size() < 1) - { - throw new AVMBadArgumentException("Keys too short: " + keys); - } - Attribute found = getAttributeFromPath(keys); - if (found == null) - { - throw new AVMNotFoundException("Attribute Not Found: " + keys); - } - if (found.getType() != Type.LIST) - { - throw new AVMWrongTypeException("Attribute Not List: " + keys); - } - found.remove(index); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#removeAttribute(java.lang.String, int) - */ - public void removeAttribute(String path, int index) - { - if (path == null) - { - throw new AVMBadArgumentException("Illegal null path."); - } - List keys = parsePath(path); - removeAttribute(keys, index); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#removeEntries(java.util.List, org.alfresco.service.cmr.attributes.AttrQuery) - */ - public void removeEntries(List keys, AttrQuery query) - { - if (keys == null || query == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - if (keys.size() == 0) - { - throw new AVMBadArgumentException("Illegal zero length key path."); - } - Attribute map = getAttributeFromPath(keys); - if (map == null) - { - throw new AVMNotFoundException("Could not find attribute: " + keys); - } - if (map.getType() != Attribute.Type.MAP) - { - throw new AVMWrongTypeException("Not a map: " + keys); - } - fAttributeDAO.delete((MapAttribute)map, query); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#removeEntries(java.lang.String, org.alfresco.service.cmr.attributes.AttrQuery) - */ - public void removeEntries(String path, AttrQuery query) - { - if (path == null || query == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - List keys = parsePath(path); - removeEntries(keys, query); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#setAttribute(java.util.List, int, org.alfresco.repo.attributes.Attribute) - */ - public void setAttribute(List keys, int index, Attribute value) - { - if (keys == null || value == null) - { - throw new AVMBadArgumentException("Illegal Null Argument."); - } - if (keys.size() < 1) - { - throw new AVMBadArgumentException("Keys too short."); - } - Attribute found = getAttributeFromPath(keys); - if (found == null) - { - throw new AVMNotFoundException("Attribute Not Found: " + keys); - } - if (found.getType() != Type.LIST) - { - throw new AVMWrongTypeException("Attribute Not List: " + keys); - } - Attribute converted = fAttributeConverter.toPersistent(value); - found.set(index, converted); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#setAttribute(java.lang.String, int, org.alfresco.repo.attributes.Attribute) - */ - public void setAttribute(String path, int index, Attribute value) - { - if (path == null || value == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - List keys = parsePath(path); - setAttribute(keys, index, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#exists(java.util.List) - */ - public boolean exists(List keys) - { - if (keys == null) - { - throw new AVMBadArgumentException("Null keys list."); - } - if (keys.size() == 0) - { - throw new AVMBadArgumentException("Illegal zero length keys list."); - } - Attribute attr = getAttributeFromPath(keys); - if (attr != null) - { - fAttributeDAO.evictFlat(attr); - return true; - } - return false; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#exists(java.lang.String) - */ - public boolean exists(String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Null attribute path."); - } - List keys = parsePath(path); - return exists(keys); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#getCount(java.util.List) - */ - public int getCount(List keys) - { - if (keys == null) - { - throw new AVMBadArgumentException("Null keys list."); - } - if (keys.size() == 0) - { - throw new AVMBadArgumentException("Illegal empty keys list."); - } - Attribute found = getAttributeFromPath(keys); - if (found == null) - { - throw new AVMNotFoundException("Attribute not found: " + keys); - } - if (found.getType() != Attribute.Type.LIST && - found.getType() != Attribute.Type.MAP) - { - throw new AVMWrongTypeException("Not a map or list: " + keys); - } - return found.size(); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#getCount(java.lang.String) - */ - public int getCount(String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Null attribute path."); - } - List keys = parsePath(path); - return getCount(keys); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#addAttributes(java.util.List, java.util.List) - */ - public void addAttributes(List keys, List values) - { - if (keys == null || values == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - if (keys.size() == 0) - { - throw new AVMBadArgumentException("Zero length keys."); - } - Attribute list = getAttributeFromPath(keys); - if (list.getType() != Attribute.Type.LIST) - { - throw new AVMWrongTypeException("Attribute not list: " + list.getType()); - } - for (Attribute value : values) - { - Attribute persistent = fAttributeConverter.toPersistent(value); - list.add(persistent); - } - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#addAttributes(java.lang.String, java.util.List) - */ - public void addAttributes(String path, List values) - { - if (path == null || values == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - List keys = parsePath(path); - addAttributes(keys, values); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#setAttributes(java.util.List, java.util.Map) - */ - public void setAttributes(List keys, Map entries) - { - if (keys == null || entries == null) - { - throw new AVMBadArgumentException("Null argument."); - } - if (keys.size() == 0) - { - for (Map.Entry entry : entries.entrySet()) - { - String name = entry.getKey(); - Attribute value = entry.getValue(); - Attribute toSave = fAttributeConverter.toPersistent(value); - GlobalAttributeEntry found = fGlobalAttributeEntryDAO.get(name); - if (found == null) - { - found = new GlobalAttributeEntryImpl(name, toSave); - fGlobalAttributeEntryDAO.save(found); - return; - } - found.setAttribute(toSave); - } - return; - } - Attribute found = getAttributeFromPath(keys); - if (found == null) - { - throw new AVMNotFoundException("Attribute Not Found: " + keys); - } - if (found.getType() != Type.MAP) - { - throw new AVMWrongTypeException("Not a Map: " + keys); - } - for (Map.Entry entry : entries.entrySet()) - { - String name = entry.getKey(); - Attribute value = entry.getValue(); - found.put(name, fAttributeConverter.toPersistent(value)); - } - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#setAttributes(java.lang.String, java.util.Map) - */ - public void setAttributes(String path, Map entries) - { - if (path == null || entries == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - List keys = parsePath(path); - setAttributes(keys, entries); - } -} - + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.attributes; + +import java.io.Serializable; +import java.util.Arrays; + +import org.alfresco.repo.domain.propval.PropertyUniqueConstraintViolation; +import org.alfresco.repo.domain.propval.PropertyValueDAO; +import org.alfresco.repo.domain.propval.PropertyValueDAO.PropertyUniqueContextCallback; +import org.alfresco.service.cmr.attributes.AttributeService; +import org.alfresco.service.cmr.attributes.DuplicateAttributeException; +import org.alfresco.util.Pair; +import org.alfresco.util.ParameterCheck; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Layers on the storage of property values to provide generic attribute storage + * + * @see PropertyValueDAO + * @author Derek Hulley + */ +public class AttributeServiceImpl implements AttributeService +{ + private static final Log logger = LogFactory.getLog(AttributeServiceImpl.class); + + private PropertyValueDAO propertyValueDAO; + + public AttributeServiceImpl() + { + } + + /** + * Set the DAO that handles the unique property persistence + */ + public void setPropertyValueDAO(PropertyValueDAO propertyValueDAO) + { + this.propertyValueDAO = propertyValueDAO; + } + + /** + * Formalize the shape of the variable-size array. + * + * @param keys the variable-size array of 1 to 3 keys + * @return an array of exactly 3 keys (incl. null values) + */ + private Serializable[] normalizeKeys(Serializable ... keys) + { + if (keys.length < 1 || keys.length > 3) + { + ParameterCheck.mandatory("keys", null); + } + return new Serializable[] + { + keys[0], + keys.length > 1 ? keys[1] : null, + keys.length > 2 ? keys[2] : null + }; + } + + /** + * {@inheritDoc} + */ + public boolean exists(Serializable ... keys) + { + keys = normalizeKeys(keys); + Pair pair = propertyValueDAO.getPropertyUniqueContext(keys[0], keys[1], keys[2]); + boolean exists = (pair != null); + // Done + if (logger.isDebugEnabled()) + { + logger.debug( + "Check attribute exists: \n" + + " Keys: " + Arrays.asList(keys) + "\n" + + " exists: " + exists); + } + return exists; + } + + /** + * {@inheritDoc} + */ + public Serializable getAttribute(Serializable ... keys) + { + keys = normalizeKeys(keys); + Pair pair = propertyValueDAO.getPropertyUniqueContext(keys[0], keys[1], keys[2]); + Serializable value = null; + if (pair != null && pair.getSecond() != null) + { + Long valueId = pair.getSecond(); + value = propertyValueDAO.getPropertyById(valueId); + } + // Done + if (logger.isDebugEnabled()) + { + logger.debug( + "Got attribute: \n" + + " Keys: " + Arrays.asList(keys) + "\n" + + " Value: " + value); + } + return value; + } + + /** + * {@inheritDoc} + */ + public void getAttributes(final AttributeQueryCallback callback, Serializable ... keys) + { + PropertyUniqueContextCallback propertyUniqueContextCallback = new PropertyUniqueContextCallback() + { + public void handle(Long id, Long valueId, Serializable[] resultKeyIds) + { + Serializable value = null; + if (valueId != null) + { + value = propertyValueDAO.getPropertyById(valueId); + } + + Serializable[] resultsKeyValues = new Serializable[resultKeyIds.length]; + for (int i = 0; i < resultKeyIds.length; i++) + { + if (resultKeyIds[i] != null) + { + Pair keyValuePair = propertyValueDAO.getPropertyValueById((Long)resultKeyIds[i]); + resultsKeyValues[i] = (keyValuePair != null ? keyValuePair.getSecond() : null); + } + } + + callback.handleAttribute(id, value, resultsKeyValues); + + // Done + if (logger.isTraceEnabled()) + { + logger.trace( + "Got attribute: \n" + + " Keys: " + Arrays.asList(resultsKeyValues) + "\n" + + " Value: " + value); + } + } + }; + propertyValueDAO.getPropertyUniqueContext(propertyUniqueContextCallback, keys); + // Done + } + + /** + * {@inheritDoc} + */ + public void setAttribute(Serializable value, Serializable ... keys) + { + keys = normalizeKeys(keys); + Pair pair = propertyValueDAO.getPropertyUniqueContext(keys[0], keys[1], keys[2]); + if (pair == null) + { + // We can create it. Any concurrency issue will be handled by the transaction. + propertyValueDAO.createPropertyUniqueContext(keys[0], keys[1], keys[2], value); + } + else + { + Long id = pair.getFirst(); + propertyValueDAO.updatePropertyUniqueContext(id, value); + } + // Done + if (logger.isDebugEnabled()) + { + logger.debug( + "Set attribute Value: \n" + + " Keys: " + Arrays.asList(keys) + "\n" + + " Value: " + value); + } + } + + /** + * {@inheritDoc} + */ + public void createAttribute(Serializable value, Serializable... keys) + { + keys = normalizeKeys(keys); + try + { + propertyValueDAO.createPropertyUniqueContext(keys[0], keys[1], keys[2], value); + } + catch (PropertyUniqueConstraintViolation e) + { + throw new DuplicateAttributeException(keys[0], keys[1], keys[2], e); + } + // Done + if (logger.isDebugEnabled()) + { + logger.debug( + "Created attribute: \n" + + " Keys: " + Arrays.asList(keys) + "\n" + + " Value: " + value); + } + } + + /** + * {@inheritDoc} + */ + public void updateOrCreateAttribute( + Serializable keyBefore1, + Serializable keyBefore2, + Serializable keyBefore3, + Serializable keyAfter1, + Serializable keyAfter2, + Serializable keyAfter3) + { + Pair pair = propertyValueDAO.getPropertyUniqueContext(keyBefore1, keyBefore2, keyBefore3); + try + { + if (pair == null) + { + pair = propertyValueDAO.createPropertyUniqueContext(keyAfter1, keyAfter2, keyAfter3, null); + } + else + { + Long id = pair.getFirst(); + propertyValueDAO.updatePropertyUniqueContext(id, keyAfter1, keyAfter2, keyAfter3); + } + } + catch (PropertyUniqueConstraintViolation e) + { + throw new DuplicateAttributeException(keyAfter1, keyAfter2, keyAfter3, e); + } + // Done + if (logger.isDebugEnabled()) + { + Serializable[] keysBefore = normalizeKeys(keyBefore1, keyBefore2, keyBefore3); + Serializable[] keysAfter = normalizeKeys(keyAfter1, keyAfter2, keyAfter3); + logger.debug( + "Updated attribute: \n" + + " Before: " + Arrays.asList(keysBefore) + "\n" + + " After: " + Arrays.asList(keysAfter)); + } + } + + /** + * {@inheritDoc} + */ + public void removeAttribute(Serializable ... keys) + { + keys = normalizeKeys(keys); + int deleted = propertyValueDAO.deletePropertyUniqueContext(keys[0], keys[1], keys[2]); + // Done + if (logger.isDebugEnabled()) + { + logger.debug( + "Deleted attribute: \n" + + " Keys: " + Arrays.asList(keys) + "\n" + + " Count: " + deleted); + } + } + + /** + * {@inheritDoc} + */ + public void removeAttributes(Serializable ... keys) + { + int deleted = propertyValueDAO.deletePropertyUniqueContext(keys); + // Done + if (logger.isDebugEnabled()) + { + logger.debug( + "Deleted attributes: \n" + + " Keys: " + Arrays.asList(keys) + "\n" + + " Count: " + deleted); + } + } +} diff --git a/source/java/org/alfresco/repo/attributes/AttributeServiceTest.java b/source/java/org/alfresco/repo/attributes/AttributeServiceTest.java index df2e86c6f4..f6d023bdab 100644 --- a/source/java/org/alfresco/repo/attributes/AttributeServiceTest.java +++ b/source/java/org/alfresco/repo/attributes/AttributeServiceTest.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,346 +14,71 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.rmi.server.LogStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.alfresco.service.cmr.attributes.AttrAndQuery; -import org.alfresco.service.cmr.attributes.AttrNotQuery; -import org.alfresco.service.cmr.attributes.AttrOrQuery; -import org.alfresco.service.cmr.attributes.AttrQueryEquals; -import org.alfresco.service.cmr.attributes.AttrQueryGT; -import org.alfresco.service.cmr.attributes.AttrQueryGTE; -import org.alfresco.service.cmr.attributes.AttrQueryLT; -import org.alfresco.service.cmr.attributes.AttrQueryLTE; -import org.alfresco.service.cmr.attributes.AttrQueryLike; -import org.alfresco.service.cmr.attributes.AttrQueryNE; -import org.alfresco.service.cmr.attributes.AttributeService; -import org.alfresco.util.Pair; -import org.springframework.context.support.FileSystemXmlApplicationContext; - -import junit.framework.TestCase; - -/** - * Basic tests for AttributeService. - * @author britt - */ -public class AttributeServiceTest extends TestCase -{ - private static FileSystemXmlApplicationContext fContext = null; - - private static AttributeService fService; - - /* (non-Javadoc) - * @see junit.framework.TestCase#setUp() - */ - @Override - protected void setUp() throws Exception - { - if (fContext == null) - { - fContext = new FileSystemXmlApplicationContext("config/alfresco/application-context.xml"); - fService = (AttributeService)fContext.getBean("AttributeService"); - } - } - - /* (non-Javadoc) - * @see junit.framework.TestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception - { - List globalKeys = fService.getKeys(""); - for (String key : globalKeys) - { - fService.removeAttribute("", key); - } - } - - public void testBasic() throws Exception - { - try - { - fService.setAttribute("", "boolean", new BooleanAttributeValue(true)); - fService.setAttribute("", "byte", new ByteAttributeValue((byte)0x20)); - fService.setAttribute("", "short", new ShortAttributeValue((short)42)); - fService.setAttribute("", "int", new IntAttributeValue(43)); - fService.setAttribute("", "long", new LongAttributeValue(1000000000000L)); - fService.setAttribute("", "float", new FloatAttributeValue(1.414f)); - fService.setAttribute("", "double", new DoubleAttributeValue(3.1415926)); - fService.setAttribute("", "string", new StringAttributeValue("This is a string.")); - fService.setAttribute("", "serializable", new SerializableAttributeValue(new Long(1010101L))); - MapAttribute map = new MapAttributeValue(); - map.put("foo", new StringAttributeValue("I walk.")); - map.put("bar", new StringAttributeValue("I talk.")); - map.put("baz", new StringAttributeValue("I shop.")); - map.put("funky", new StringAttributeValue("I sneeze.")); - map.put("monkey", - new StringAttributeValue("I'm going to be a fireman when the floods roll back.")); - fService.setAttribute("", "map", map); - assertNotNull(fService.getAttribute("boolean")); - assertEquals(42, (int)fService.getAttribute("short").getShortValue()); - assertEquals("I sneeze.", fService.getAttribute("map/funky").getStringValue()); - // This is 11 because of the AVMLockingService. - assertEquals(11, fService.getKeys("").size()); - assertEquals(5, fService.getKeys("map").size()); - List keys = fService.getKeys(""); - for (String key : keys) - { - System.out.println(key + " => " + fService.getAttribute(key)); - } - fService.setAttribute("", "string", new StringAttributeValue("This is another string.")); - assertEquals("This is another string.", fService.getAttribute("string").getStringValue()); - Map hmap = new HashMap(); - hmap.put("foo", new StringAttributeValue("I do walk.")); - hmap.put("pismo", new StringAttributeValue("There's trees now in the desert since you moved out, and I don't sleep on a bed of bones.")); - fService.setAttributes("map", hmap); - Attribute out = fService.getAttribute("map"); - System.out.println(out); - assertEquals(6, out.size()); - } - catch (Exception e) - { - throw e; - } - } - - public void testLongStrings() throws Exception - { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 1000; i++) - { - sb.append(i); - } - String longStr = sb.toString(); - StringAttributeValue attributeValue = new StringAttributeValue(longStr); - fService.setAttribute("", "long-string", attributeValue); - // Check that we can get it back - Attribute checkAttribute = fService.getAttribute("long-string"); - String checkStr = checkAttribute.getStringValue(); - assertEquals("Retrieved String is not the same as the persisted one", longStr, checkStr); - } - - /** - * Test the query capability. - */ - public void testQuery() throws Exception - { - try - { - // Put some attributes in place. - MapAttribute map = new MapAttributeValue(); - map.put("a", new StringAttributeValue("a")); - map.put("b", new StringAttributeValue("a")); - map.put("c", new StringAttributeValue("a")); - map.put("d", new StringAttributeValue("a")); - map.put("e", new StringAttributeValue("a")); - map.put("f", new StringAttributeValue("a")); - map.put("g", new StringAttributeValue("a")); - map.put("h", new StringAttributeValue("a")); - map.put("i", new StringAttributeValue("a")); - map.put("j", new StringAttributeValue("a")); - map.put("k", new StringAttributeValue("a")); - map.put("l", new StringAttributeValue("a")); - map.put("m", new StringAttributeValue("a")); - map.put("n", new StringAttributeValue("a")); - map.put("o", new StringAttributeValue("a")); - map.put("p", new StringAttributeValue("a")); - map.put("q", new StringAttributeValue("a")); - map.put("r", new StringAttributeValue("a")); - map.put("s", new StringAttributeValue("a")); - map.put("t", new StringAttributeValue("a")); - map.put("u", new StringAttributeValue("a")); - map.put("v", new StringAttributeValue("a")); - map.put("w", new StringAttributeValue("a")); - map.put("x", new StringAttributeValue("a")); - map.put("y", new StringAttributeValue("a")); - map.put("z", new StringAttributeValue("a")); - fService.setAttribute("", "map1", map); - fService.setAttribute("", "map2", map); - List> result = - fService.query("map1", new AttrQueryEquals("w")); - assertEquals(1, result.size()); - result = - fService.query("map1", new AttrQueryLT("d")); - assertEquals(3, result.size()); - result = - fService.query("map1", new AttrQueryLTE("d")); - assertEquals(4, result.size()); - result = - fService.query("map1", new AttrQueryGT("v")); - assertEquals(4, result.size()); - result = - fService.query("map1", new AttrQueryGTE("v")); - assertEquals(5, result.size()); - result = - fService.query("map1", new AttrQueryNE("g")); - assertEquals(25, result.size()); - result = - fService.query("map1", new AttrNotQuery(new AttrQueryGT("d"))); - assertEquals(4, result.size()); - result = - fService.query("map1", new AttrAndQuery(new AttrQueryGT("g"), - new AttrQueryLT("l"))); - assertEquals(4, result.size()); - result = - fService.query("map1", new AttrOrQuery(new AttrQueryLT("d"), - new AttrQueryGT("w"))); - assertEquals(6, result.size()); - result = - fService.query("map1", new AttrQueryLike("%")); - assertEquals(26, result.size()); - fService.setAttribute("map2", "submap", map); - result = - fService.query("map2/submap", new AttrQueryEquals("w")); - assertEquals(1, result.size()); - result = - fService.query("map2/submap", new AttrQueryLT("d")); - assertEquals(3, result.size()); - result = - fService.query("map2/submap", new AttrQueryLTE("d")); - assertEquals(4, result.size()); - result = - fService.query("map2/submap", new AttrQueryGT("v")); - assertEquals(4, result.size()); - result = - fService.query("map2/submap", new AttrQueryGTE("v")); - assertEquals(5, result.size()); - result = - fService.query("map2/submap", new AttrQueryNE("g")); - assertEquals(25, result.size()); - result = - fService.query("map2/submap", new AttrNotQuery(new AttrQueryGT("d"))); - assertEquals(4, result.size()); - result = - fService.query("map2/submap", new AttrAndQuery(new AttrQueryGT("g"), - new AttrQueryLT("l"))); - assertEquals(4, result.size()); - result = - fService.query("map2/submap", new AttrOrQuery(new AttrQueryLT("d"), - new AttrQueryGT("w"))); - assertEquals(6, result.size()); - result = - fService.query("map2/submap", new AttrQueryLike("%")); - assertEquals(26, result.size()); - } - catch (Exception e) - { - throw e; - } - } - - public void testDelete() throws Exception - { - try - { - // Put some attributes in place. - MapAttribute map = new MapAttributeValue(); - map.put("a", new StringAttributeValue("a")); - map.put("b", new StringAttributeValue("b")); - map.put("c", new StringAttributeValue("c")); - map.put("d", new StringAttributeValue("d")); - map.put("e", new StringAttributeValue("e")); - map.put("f", new StringAttributeValue("f")); - map.put("g", new StringAttributeValue("g")); - map.put("h", new StringAttributeValue("h")); - map.put("i", new StringAttributeValue("i")); - map.put("j", new StringAttributeValue("j")); - map.put("k", new StringAttributeValue("k")); - map.put("l", new StringAttributeValue("l")); - map.put("m", new StringAttributeValue("m")); - map.put("n", new StringAttributeValue("n")); - map.put("o", new StringAttributeValue("o")); - map.put("p", new StringAttributeValue("p")); - map.put("q", new StringAttributeValue("q")); - map.put("r", new StringAttributeValue("r")); - map.put("s", new StringAttributeValue("s")); - map.put("t", new StringAttributeValue("t")); - map.put("u", new StringAttributeValue("u")); - map.put("v", new StringAttributeValue("v")); - map.put("w", new StringAttributeValue("w")); - map.put("x", new StringAttributeValue("x")); - map.put("y", new StringAttributeValue("y")); - map.put("z", new StringAttributeValue("z")); - fService.setAttribute("", "map", map); - fService.setAttribute("map", "submap", map); - fService.setAttribute("map/submap", "subsubmap", map); - assertEquals(27, fService.getKeys("map").size()); - assertEquals(27, fService.getKeys("map/submap").size()); - fService.removeAttribute("map/submap/subsubmap", "b"); - assertEquals(25, fService.getKeys("map/submap/subsubmap").size()); - System.out.println("Before-------------------------------------------------------------"); - fService.removeAttribute("map/submap", "subsubmap"); - System.out.println("After--------------------------------------------------------------"); - assertEquals(26, fService.getKeys("map/submap").size()); - fService.removeEntries("map/submap", new AttrAndQuery(new AttrQueryGTE("a"), - new AttrQueryLTE("d"))); - assertEquals(22, fService.getCount("map/submap")); - } - catch (Exception e) - { - throw e; - } - } - - /** - * Test ListAttributes - */ - public void testList() throws Exception - { - try - { - ListAttribute list = new ListAttributeValue(); - list.add(new IntAttributeValue(0)); - list.add(new IntAttributeValue(1)); - list.add(new IntAttributeValue(2)); - list.add(new IntAttributeValue(3)); - list.add(new IntAttributeValue(4)); - fService.setAttribute("", "dummy", list); - Attribute found = fService.getAttribute("dummy"); - assertTrue(fService.exists("dummy")); - assertFalse(fService.exists("dimmy")); - assertEquals(5, fService.getCount("dummy")); - assertNotNull(found); - assertEquals(5, found.size()); - Attribute add = new IntAttributeValue(6); - fService.addAttribute("dummy", add); - assertEquals(6, fService.getAttribute("dummy").size()); - fService.removeAttribute("dummy", 2); - found = fService.getAttribute("dummy"); - assertEquals(5, found.size()); - assertEquals(3, found.get(2).getIntValue()); - Attribute replace = new StringAttributeValue("String"); - fService.setAttribute("dummy", 2, replace); - assertEquals("String", fService.getAttribute("dummy/2").getStringValue()); - MapAttribute map = new MapAttributeValue(); - map.put("list", list); - MapAttribute subMap = new MapAttributeValue(); - subMap.put("a", new StringAttributeValue("polyester")); - subMap.put("b", new StringAttributeValue("donuts")); - subMap.put("c", new StringAttributeValue("brutality")); - list.add(subMap); - fService.setAttribute("", "map", map); - assertEquals("donuts", fService.getAttribute("map/list/5/b").getStringValue()); - assertEquals(3, fService.getCount("map/list/5")); - List values = new ArrayList(); - values.add(new StringAttributeValue("Death is your art.")); - values.add(new StringAttributeValue("You make it with your hands, day after day.")); - fService.addAttributes("dummy", values); - found = fService.getAttribute("dummy"); - System.out.println(found); - assertEquals(7, found.size()); - } - catch (Exception e) - { - throw e; - } - } -} + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.attributes; + +import java.io.Serializable; + +import junit.framework.TestCase; + +import org.alfresco.service.cmr.attributes.AttributeService; +import org.alfresco.util.ApplicationContextHelper; +import org.springframework.context.ApplicationContext; + +/** + * {@link AttributeService} + * + * @author Derek Hulley + */ +public class AttributeServiceTest extends TestCase +{ + private static final Serializable[] KEY_AAA = new Serializable[] {"a", "a", "a"}; + private static final Serializable[] KEY_AAB = new Serializable[] {"a", "a", "b"}; + private static final Serializable[] KEY_AAC = new Serializable[] {"a", "a", "c"}; + private static final Serializable VALUE_AAA_STRING = "aaa"; + private static final Serializable VALUE_AAB_STRING = "aab"; + private static final Serializable VALUE_AAC_STRING = "aac"; + + private ApplicationContext ctx; + private AttributeService attributeService; + + @Override + protected void setUp() throws Exception + { + ctx = ApplicationContextHelper.getApplicationContext(); + attributeService = (AttributeService) ctx.getBean("AttributeService"); + } + + @Override + protected void tearDown() throws Exception + { + } + + public void testBasic() throws Exception + { + attributeService.removeAttribute(KEY_AAA); + attributeService.removeAttribute(KEY_AAB); + attributeService.removeAttribute(KEY_AAC); + + assertFalse(attributeService.exists(KEY_AAA)); + assertFalse(attributeService.exists(KEY_AAB)); + assertFalse(attributeService.exists(KEY_AAC)); + + attributeService.setAttribute(VALUE_AAA_STRING, KEY_AAA); + attributeService.setAttribute(VALUE_AAB_STRING, KEY_AAB); + attributeService.setAttribute(VALUE_AAC_STRING, KEY_AAC); + + assertTrue(attributeService.exists(KEY_AAA)); + assertTrue(attributeService.exists(KEY_AAB)); + assertTrue(attributeService.exists(KEY_AAC)); + + assertEquals(VALUE_AAA_STRING, attributeService.getAttribute(KEY_AAA)); + assertEquals(VALUE_AAB_STRING, attributeService.getAttribute(KEY_AAB)); + assertEquals(VALUE_AAC_STRING, attributeService.getAttribute(KEY_AAC)); +// +// attributeService.removeAttribute(KEY_AAA); +// attributeService.removeAttribute(KEY_AAB); +// attributeService.removeAttribute(KEY_AAC); + } +} diff --git a/source/java/org/alfresco/repo/attributes/AttributeServiceTransportService.java b/source/java/org/alfresco/repo/attributes/AttributeServiceTransportService.java deleted file mode 100644 index 33961ddc50..0000000000 --- a/source/java/org/alfresco/repo/attributes/AttributeServiceTransportService.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.util.List; -import java.util.Map; - -import org.alfresco.service.cmr.attributes.AttrQuery; -import org.alfresco.service.cmr.attributes.AttributeService; -import org.alfresco.service.cmr.remote.AttributeServiceTransport; -import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.util.Pair; - -/** - * Server side implementation of transport for AttributeService. - * @author britt - */ -public class AttributeServiceTransportService implements - AttributeServiceTransport -{ - private AttributeService fService; - - private AuthenticationService fAuthService; - - public AttributeServiceTransportService() - { - } - - public void setAttributeService(AttributeService service) - { - fService = service; - } - - public void setAuthenticationService(AuthenticationService service) - { - fAuthService = service; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#addAttribute(java.lang.String, java.lang.String, org.alfresco.repo.attributes.Attribute) - */ - public void addAttribute(String ticket, String path, Attribute value) - { - fAuthService.validate(ticket, null); - fService.addAttribute(path, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#addAttribute(java.lang.String, java.util.List, org.alfresco.repo.attributes.Attribute) - */ - public void addAttribute(String ticket, List keys, Attribute value) - { - fAuthService.validate(ticket, null); - fService.addAttribute(keys, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#getAttribute(java.lang.String, java.lang.String) - */ - public Attribute getAttribute(String ticket, String path) - { - fAuthService.validate(ticket, null); - return fService.getAttribute(path); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#getAttribute(java.lang.String, java.util.List) - */ - public Attribute getAttribute(String ticket, List keys) - { - fAuthService.validate(ticket, null); - return fService.getAttribute(keys); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#getKeys(java.lang.String, java.lang.String) - */ - public List getKeys(String ticket, String path) - { - fAuthService.validate(ticket, null); - return fService.getKeys(path); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#getKeys(java.lang.String, java.util.List) - */ - public List getKeys(String ticket, List keys) - { - fAuthService.validate(ticket, null); - return fService.getKeys(keys); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#query(java.lang.String, java.lang.String, org.alfresco.service.cmr.attributes.AttrQuery) - */ - public List> query(String ticket, String path, - AttrQuery query) - { - fAuthService.validate(ticket, null); - return fService.query(path, query); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#query(java.lang.String, java.util.List, org.alfresco.service.cmr.attributes.AttrQuery) - */ - public List> query(String ticket, - List keys, AttrQuery query) - { - fAuthService.validate(ticket, null); - return fService.query(keys, query); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#removeAttribute(java.lang.String, java.lang.String, java.lang.String) - */ - public void removeAttribute(String ticket, String path, String name) - { - fAuthService.validate(ticket, null); - fService.removeAttribute(path, name); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#removeAttribute(java.lang.String, java.util.List, java.lang.String) - */ - public void removeAttribute(String ticket, List keys, String name) - { - fAuthService.validate(ticket, null); - fService.removeAttribute(keys, name); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#removeAttribute(java.lang.String, java.lang.String, int) - */ - public void removeAttribute(String ticket, String path, int index) - { - fAuthService.validate(ticket, null); - fService.removeAttribute(path, index); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#removeAttribute(java.lang.String, java.util.List, int) - */ - public void removeAttribute(String ticket, List keys, int index) - { - fAuthService.validate(ticket, null); - fService.removeAttribute(keys, index); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#setAttribute(java.lang.String, java.lang.String, java.lang.String, org.alfresco.repo.attributes.Attribute) - */ - public void setAttribute(String ticket, String path, String name, - Attribute value) - { - fAuthService.validate(ticket, null); - fService.setAttribute(path, name, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#setAttribute(java.lang.String, java.util.List, java.lang.String, org.alfresco.repo.attributes.Attribute) - */ - public void setAttribute(String ticket, List keys, String name, - Attribute value) - { - fAuthService.validate(ticket, null); - fService.setAttribute(keys, name, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#setAttribute(java.lang.String, java.lang.String, int, org.alfresco.repo.attributes.Attribute) - */ - public void setAttribute(String ticket, String path, int index, - Attribute value) - { - fAuthService.validate(ticket, null); - fService.setAttribute(path, index, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeServiceTransport#setAttribute(java.lang.String, java.util.List, int, org.alfresco.repo.attributes.Attribute) - */ - public void setAttribute(String ticket, List keys, int index, - Attribute value) - { - fAuthService.validate(ticket, null); - fService.setAttribute(keys, index, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.remote.AttributeServiceTransport#exists(java.lang.String, java.util.List) - */ - public boolean exists(String ticket, List keys) - { - fAuthService.validate(ticket, null); - return fService.exists(keys); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.remote.AttributeServiceTransport#exists(java.lang.String, java.lang.String) - */ - public boolean exists(String ticket, String path) - { - fAuthService.validate(ticket, null); - return fService.exists(path); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.remote.AttributeServiceTransport#getCount(java.lang.String, java.util.List) - */ - public int getCount(String ticket, List keys) - { - fAuthService.validate(ticket, null); - return fService.getCount(keys); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.remote.AttributeServiceTransport#getCount(java.lang.String, java.lang.String) - */ - public int getCount(String ticket, String path) - { - fAuthService.validate(ticket, null); - return fService.getCount(path); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.remote.AttributeServiceTransport#addAttributes(java.lang.String, java.util.List, java.util.List) - */ - public void addAttributes(String ticket, List keys, List values) - { - fAuthService.validate(ticket, null); - fService.addAttributes(keys, values); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.remote.AttributeServiceTransport#addAttributes(java.lang.String, java.lang.String, java.util.List) - */ - public void addAttributes(String ticket, String path, List values) - { - fAuthService.validate(ticket, null); - fService.addAttributes(path, values); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.remote.AttributeServiceTransport#setAttributes(java.lang.String, java.util.List, java.util.Map) - */ - public void setAttributes(String ticket, List keys, Map entries) - { - fAuthService.validate(ticket, null); - fService.setAttributes(keys, entries); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.remote.AttributeServiceTransport#setAttributes(java.lang.String, java.lang.String, java.util.Map) - */ - public void setAttributes(String ticket, String path, Map entries) - { - fAuthService.validate(ticket, null); - fService.setAttributes(path, entries); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.remote.AttributeServiceTransport#removeEntries(java.lang.String, java.util.List, org.alfresco.service.cmr.attributes.AttrQuery) - */ - public void removeEntries(String ticket, List keys, AttrQuery query) - { - fAuthService.validate(ticket, null); - fService.removeEntries(keys, query); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.remote.AttributeServiceTransport#removeEntries(java.lang.String, java.lang.String, org.alfresco.service.cmr.attributes.AttrQuery) - */ - public void removeEntries(String ticket, String path, AttrQuery query) - { - fAuthService.validate(ticket, null); - fService.removeEntries(path, query); - } -} diff --git a/source/java/org/alfresco/repo/attributes/AttributeUnsupportedQueryType.java b/source/java/org/alfresco/repo/attributes/AttributeUnsupportedQueryType.java deleted file mode 100644 index fc93e5dfaa..0000000000 --- a/source/java/org/alfresco/repo/attributes/AttributeUnsupportedQueryType.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import org.alfresco.error.AlfrescoRuntimeException; - -/** - * Thrown when a query node is created with an unsupported type. - * @author britt - */ -public class AttributeUnsupportedQueryType extends AlfrescoRuntimeException -{ - private static final long serialVersionUID = 7736211710764082022L; - - public AttributeUnsupportedQueryType(String message) - { - super(message); - } -} diff --git a/source/java/org/alfresco/repo/attributes/AttributeValue.java b/source/java/org/alfresco/repo/attributes/AttributeValue.java deleted file mode 100644 index 85ab485ca6..0000000000 --- a/source/java/org/alfresco/repo/attributes/AttributeValue.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import org.alfresco.repo.domain.DbAccessControlList; - -/** - * Value based non-persistent implementation of Attribute. - * @author britt - */ -public abstract class AttributeValue extends AbstractAttribute implements Attribute -{ - /** - * ACL for this Attribute - */ - private DbAccessControlList fACL; - - public AttributeValue() - { - } - - /** - * Helper for copy constructors. - */ - public AttributeValue(DbAccessControlList acl) - { - fACL = acl; - } - - public DbAccessControlList getAcl() - { - return fACL; - } - - public void setAcl(DbAccessControlList acl) - { - fACL = acl; - } -} diff --git a/source/java/org/alfresco/repo/attributes/BooleanAttribute.java b/source/java/org/alfresco/repo/attributes/BooleanAttribute.java deleted file mode 100644 index 242c1f5e7c..0000000000 --- a/source/java/org/alfresco/repo/attributes/BooleanAttribute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * Stub interface for Booleans. - * @author britt - */ -public interface BooleanAttribute extends Attribute -{ -} diff --git a/source/java/org/alfresco/repo/attributes/BooleanAttributeImpl.java b/source/java/org/alfresco/repo/attributes/BooleanAttributeImpl.java deleted file mode 100644 index f117914397..0000000000 --- a/source/java/org/alfresco/repo/attributes/BooleanAttributeImpl.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -import org.alfresco.repo.avm.AVMDAOs; - -/** - * @author britt - * - */ -public class BooleanAttributeImpl extends AttributeImpl implements - BooleanAttribute -{ - private static final long serialVersionUID = 8483440613101900682L; - - private boolean fValue; - - public BooleanAttributeImpl() - { - } - - public BooleanAttributeImpl(boolean value) - { - fValue = value; - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public BooleanAttributeImpl(BooleanAttribute attr) - { - super(attr.getAcl()); - fValue = attr.getBooleanValue(); - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - @Override - public boolean getBooleanValue() - { - return fValue; - } - - @Override - public void setBooleanValue(boolean value) - { - fValue = value; - } - - public Type getType() - { - return Type.BOOLEAN; - } - - public Serializable getRawValue() - { - return Boolean.valueOf(fValue); - } - - @Override - public String toString() - { - return fValue ? "true" : "false"; - } -} diff --git a/source/java/org/alfresco/repo/attributes/BooleanAttributeValue.java b/source/java/org/alfresco/repo/attributes/BooleanAttributeValue.java deleted file mode 100644 index 2fa01ebb04..0000000000 --- a/source/java/org/alfresco/repo/attributes/BooleanAttributeValue.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -/** - * Value based implementation of a boolean attribute. - * @author britt - */ -public class BooleanAttributeValue extends AttributeValue implements - BooleanAttribute -{ - private static final long serialVersionUID = 4019402783943642209L; - - private boolean fData; - - public BooleanAttributeValue(boolean value) - { - fData = value; - } - - public BooleanAttributeValue(BooleanAttribute attr) - { - super(attr.getAcl()); - fData = attr.getBooleanValue(); - } - - public Type getType() - { - return Type.BOOLEAN; - } - - public Serializable getRawValue() - { - return Boolean.valueOf(fData); - } - - @Override - public boolean getBooleanValue() - { - return fData; - } - - @Override - public void setBooleanValue(boolean value) - { - fData = value; - } - - @Override - public String toString() - { - return fData ? "true" : "false"; - } -} diff --git a/source/java/org/alfresco/repo/attributes/ByteAttribute.java b/source/java/org/alfresco/repo/attributes/ByteAttribute.java deleted file mode 100644 index e2002e1d57..0000000000 --- a/source/java/org/alfresco/repo/attributes/ByteAttribute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * Stub interface for byte Attributes. - * @author britt - */ -public interface ByteAttribute extends Attribute -{ -} diff --git a/source/java/org/alfresco/repo/attributes/ByteAttributeImpl.java b/source/java/org/alfresco/repo/attributes/ByteAttributeImpl.java deleted file mode 100644 index 8d0a151369..0000000000 --- a/source/java/org/alfresco/repo/attributes/ByteAttributeImpl.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -import org.alfresco.repo.avm.AVMDAOs; - -/** - * A Byte Attribute. - * @author britt - */ -public class ByteAttributeImpl extends AttributeImpl implements ByteAttribute -{ - private static final long serialVersionUID = -8308587890270623903L; - - private byte fValue; - - public ByteAttributeImpl() - { - } - - public ByteAttributeImpl(byte value) - { - fValue = value; - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public ByteAttributeImpl(ByteAttribute attr) - { - super(attr.getAcl()); - fValue = attr.getByteValue(); - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public Type getType() - { - return Type.BYTE; - } - - public Serializable getRawValue() - { - return Byte.valueOf(fValue); - } - - @Override - public byte getByteValue() - { - return fValue; - } - - @Override - public void setByteValue(byte value) - { - fValue = value; - } - - @Override - public String toString() - { - return Byte.toString(fValue); - } -} diff --git a/source/java/org/alfresco/repo/attributes/ByteAttributeValue.java b/source/java/org/alfresco/repo/attributes/ByteAttributeValue.java deleted file mode 100644 index d0db3978e7..0000000000 --- a/source/java/org/alfresco/repo/attributes/ByteAttributeValue.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -/** - * Value based implementation of byte attribute. - * @author britt - */ -public class ByteAttributeValue extends AttributeValue implements ByteAttribute -{ - private static final long serialVersionUID = -5011945743563985072L; - - private byte fData; - - public ByteAttributeValue(byte value) - { - fData = value; - } - - public ByteAttributeValue(ByteAttribute attr) - { - super(attr.getAcl()); - fData = attr.getByteValue(); - } - - public Type getType() - { - return Type.BYTE; - } - - public Serializable getRawValue() - { - return Byte.valueOf(fData); - } - - @Override - public byte getByteValue() - { - return fData; - } - - @Override - public void setByteValue(byte value) - { - fData = value; - } - - @Override - public String toString() - { - return Byte.toString(fData); - } -} diff --git a/source/java/org/alfresco/repo/attributes/DoubleAttribute.java b/source/java/org/alfresco/repo/attributes/DoubleAttribute.java deleted file mode 100644 index e741b10fcf..0000000000 --- a/source/java/org/alfresco/repo/attributes/DoubleAttribute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * Placeholder interface or double attributes. - * @author britt - */ -public interface DoubleAttribute extends Attribute -{ -} diff --git a/source/java/org/alfresco/repo/attributes/DoubleAttributeImpl.java b/source/java/org/alfresco/repo/attributes/DoubleAttributeImpl.java deleted file mode 100644 index 8953e198ae..0000000000 --- a/source/java/org/alfresco/repo/attributes/DoubleAttributeImpl.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -import org.alfresco.repo.avm.AVMDAOs; - -/** - * Persistent double attribute implementation. - * @author britt - */ -public class DoubleAttributeImpl extends AttributeImpl implements DoubleAttribute -{ - private static final long serialVersionUID = 6615023606094278263L; - - private double fValue; - - public DoubleAttributeImpl() - { - } - - public DoubleAttributeImpl(double value) - { - fValue = value; - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public DoubleAttributeImpl(DoubleAttribute attr) - { - super(attr.getAcl()); - fValue = attr.getDoubleValue(); - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public Type getType() - { - return Type.DOUBLE; - } - - public Serializable getRawValue() - { - return Double.valueOf(fValue); - } - - @Override - public double getDoubleValue() - { - return fValue; - } - - @Override - public void setDoubleValue(double value) - { - fValue = value; - } - - @Override - public String toString() - { - return Double.toString(fValue); - } -} diff --git a/source/java/org/alfresco/repo/attributes/DoubleAttributeValue.java b/source/java/org/alfresco/repo/attributes/DoubleAttributeValue.java deleted file mode 100644 index 6cb1c15d98..0000000000 --- a/source/java/org/alfresco/repo/attributes/DoubleAttributeValue.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -/** - * Value based implementation of a double attribute. - * @author britt - */ -public class DoubleAttributeValue extends AttributeValue implements - DoubleAttribute -{ - private static final long serialVersionUID = 1710813761810342910L; - - private double fData; - - public DoubleAttributeValue(double value) - { - fData = value; - } - - public DoubleAttributeValue(DoubleAttribute attr) - { - super(attr.getAcl()); - fData = attr.getDoubleValue(); - } - - public Type getType() - { - return Type.DOUBLE; - } - - public Serializable getRawValue() - { - return Double.valueOf(fData); - } - - @Override - public double getDoubleValue() - { - return fData; - } - - @Override - public void setDoubleValue(double value) - { - fData = value; - } - - @Override - public String toString() - { - return Double.toString(fData); - } -} diff --git a/source/java/org/alfresco/repo/attributes/FloatAttribute.java b/source/java/org/alfresco/repo/attributes/FloatAttribute.java deleted file mode 100644 index 16114cc095..0000000000 --- a/source/java/org/alfresco/repo/attributes/FloatAttribute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * Stub interface for float attribute. - * @author britt - */ -public interface FloatAttribute extends Attribute -{ -} diff --git a/source/java/org/alfresco/repo/attributes/FloatAttributeImpl.java b/source/java/org/alfresco/repo/attributes/FloatAttributeImpl.java deleted file mode 100644 index 7e162e8c98..0000000000 --- a/source/java/org/alfresco/repo/attributes/FloatAttributeImpl.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -import org.alfresco.repo.avm.AVMDAOs; - -/** - * Persistent implementation of float attribute. - * @author britt - */ -public class FloatAttributeImpl extends AttributeImpl implements FloatAttribute -{ - private static final long serialVersionUID = 8173803953645298153L; - - private float fValue; - - public FloatAttributeImpl() - { - } - - public FloatAttributeImpl(float value) - { - fValue = value; - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public FloatAttributeImpl(FloatAttribute attr) - { - super(attr.getAcl()); - fValue = attr.getFloatValue(); - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public Type getType() - { - return Type.FLOAT; - } - - public Serializable getRawValue() - { - return Float.valueOf(fValue); - } - - @Override - public float getFloatValue() - { - return fValue; - } - - @Override - public void setFloatValue(float value) - { - fValue = value; - } - - @Override - public String toString() - { - return Float.toString(fValue); - } -} diff --git a/source/java/org/alfresco/repo/attributes/FloatAttributeValue.java b/source/java/org/alfresco/repo/attributes/FloatAttributeValue.java deleted file mode 100644 index 1b522c7936..0000000000 --- a/source/java/org/alfresco/repo/attributes/FloatAttributeValue.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -/** - * Value based implementation of float attribute - * @author britt - */ -public class FloatAttributeValue extends AttributeValue implements - FloatAttribute -{ - private static final long serialVersionUID = -1645099708530314562L; - - private float fData; - - public FloatAttributeValue(float value) - { - fData = value; - } - - public FloatAttributeValue(FloatAttribute attr) - { - super(attr.getAcl()); - fData = attr.getFloatValue(); - } - - public Type getType() - { - return Type.FLOAT; - } - - public Serializable getRawValue() - { - return Float.valueOf(fData); - } - - @Override - public float getFloatValue() - { - return fData; - } - - @Override - public void setFloatValue(float value) - { - fData = value; - } - - @Override - public String toString() - { - return Float.toString(fData); - } -} diff --git a/source/java/org/alfresco/repo/attributes/GlobalAttributeEntry.java b/source/java/org/alfresco/repo/attributes/GlobalAttributeEntry.java deleted file mode 100644 index 83bd4cd4d0..0000000000 --- a/source/java/org/alfresco/repo/attributes/GlobalAttributeEntry.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * Interface for the entries in the global attribute table. - * @author britt - */ -public interface GlobalAttributeEntry -{ - /** - * Get the name of the entry. - */ - public String getName(); - - /** - * Get the Attribute. - */ - public Attribute getAttribute(); - - /** - * Set the Attribute. - */ - public void setAttribute(Attribute attr); -} diff --git a/source/java/org/alfresco/repo/attributes/GlobalAttributeEntryDAO.java b/source/java/org/alfresco/repo/attributes/GlobalAttributeEntryDAO.java deleted file mode 100644 index 334756e74f..0000000000 --- a/source/java/org/alfresco/repo/attributes/GlobalAttributeEntryDAO.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.attributes; - -import java.util.List; - -import org.alfresco.repo.domain.hibernate.DirtySessionAnnotation; - -/** - * Interface for persistence of the top level attribute map. - * @author britt - */ -public interface GlobalAttributeEntryDAO -{ - /** - * Save an entry. - * @param entry To save. - */ - @DirtySessionAnnotation(markDirty=true) - public void save(GlobalAttributeEntry entry); - - /** - * Delete an entry. - * @param entry To delete. - */ - @DirtySessionAnnotation(markDirty=true) - public void delete(GlobalAttributeEntry entry); - - /** - * Delete an entry by name. - * @param name The name of the entry. - */ - @DirtySessionAnnotation(markDirty=true) - public void delete(String name); - - /** - * Get an attribute by name. - * @param name The name of the attribute. - * @return The entry or null. - */ - @DirtySessionAnnotation(markDirty=false) - public GlobalAttributeEntry get(String name); - - /** - * Get all keys for global attributes. - * @return A list of all top level keys. - */ - @DirtySessionAnnotation(markDirty=false) - public List getKeys(); -} diff --git a/source/java/org/alfresco/repo/attributes/GlobalAttributeEntryImpl.java b/source/java/org/alfresco/repo/attributes/GlobalAttributeEntryImpl.java deleted file mode 100644 index d69f416266..0000000000 --- a/source/java/org/alfresco/repo/attributes/GlobalAttributeEntryImpl.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * @author britt - * - */ -public class GlobalAttributeEntryImpl implements GlobalAttributeEntry -{ - private String fName; - - private Attribute fAttribute; - - public GlobalAttributeEntryImpl() - { - } - - public GlobalAttributeEntryImpl(String name, Attribute attr) - { - fName = name; - fAttribute = attr; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.GlobalAttributeEntry#getAttribute() - */ - public Attribute getAttribute() - { - return fAttribute; - } - - /** - * Setter. - */ - public void setAttribute(Attribute attr) - { - fAttribute = attr; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.GlobalAttributeEntry#getName() - */ - public String getName() - { - return fName; - } - - /** - * Setter. - */ - public void setName(String name) - { - fName = name; - } -} diff --git a/source/java/org/alfresco/repo/attributes/IntAttribute.java b/source/java/org/alfresco/repo/attributes/IntAttribute.java deleted file mode 100644 index cc19b98df4..0000000000 --- a/source/java/org/alfresco/repo/attributes/IntAttribute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * A stub interface for int attributes. - * @author britt - */ -public interface IntAttribute extends Attribute -{ -} diff --git a/source/java/org/alfresco/repo/attributes/IntAttributeImpl.java b/source/java/org/alfresco/repo/attributes/IntAttributeImpl.java deleted file mode 100644 index d980d37f23..0000000000 --- a/source/java/org/alfresco/repo/attributes/IntAttributeImpl.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -import org.alfresco.repo.avm.AVMDAOs; - -/** - * An integer attribute. - * @author britt - */ -public class IntAttributeImpl extends AttributeImpl implements IntAttribute -{ - private static final long serialVersionUID = -7721943599145354015L; - - private int fValue; - - public IntAttributeImpl() - { - } - - public IntAttributeImpl(int value) - { - fValue = value; - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public IntAttributeImpl(IntAttribute attr) - { - super(attr.getAcl()); - fValue = attr.getIntValue(); - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public Type getType() - { - return Type.INT; - } - - public Serializable getRawValue() - { - return Integer.valueOf(fValue); - } - - @Override - public int getIntValue() - { - return fValue; - } - - @Override - public void setIntValue(int value) - { - fValue = value; - } - - @Override - public String toString() - { - return Integer.toString(fValue); - } -} diff --git a/source/java/org/alfresco/repo/attributes/IntAttributeValue.java b/source/java/org/alfresco/repo/attributes/IntAttributeValue.java deleted file mode 100644 index 30a7180bd8..0000000000 --- a/source/java/org/alfresco/repo/attributes/IntAttributeValue.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -/** - * Value based implementation of int attribute. - * @author britt - */ -public class IntAttributeValue extends AttributeValue implements IntAttribute -{ - private static final long serialVersionUID = -7547112946658496030L; - - private int fData; - - public IntAttributeValue(int value) - { - fData = value; - } - - public IntAttributeValue(IntAttribute attr) - { - super(attr.getAcl()); - fData = attr.getIntValue(); - } - - public Type getType() - { - return Type.INT; - } - - public Serializable getRawValue() - { - return Integer.valueOf(fData); - } - - @Override - public int getIntValue() - { - return fData; - } - - @Override - public void setIntValue(int value) - { - fData = value; - } - - @Override - public String toString() - { - return Integer.toString(fData); - } -} diff --git a/source/java/org/alfresco/repo/attributes/ListAttribute.java b/source/java/org/alfresco/repo/attributes/ListAttribute.java deleted file mode 100644 index 491fb6adc9..0000000000 --- a/source/java/org/alfresco/repo/attributes/ListAttribute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * List Attribute dummy interface. - * @author britt - */ -public interface ListAttribute extends Attribute -{ -} diff --git a/source/java/org/alfresco/repo/attributes/ListAttributeImpl.java b/source/java/org/alfresco/repo/attributes/ListAttributeImpl.java deleted file mode 100644 index 0b9d18082c..0000000000 --- a/source/java/org/alfresco/repo/attributes/ListAttributeImpl.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.alfresco.repo.avm.AVMDAOs; -import org.alfresco.service.cmr.avm.AVMBadArgumentException; - -/** - * Persistent implementation of a list attribute. - * @author britt - */ -public class ListAttributeImpl extends AttributeImpl implements ListAttribute -{ - private static final long serialVersionUID = -394553378173857035L; - - public ListAttributeImpl() - { - } - - public ListAttributeImpl(ListAttribute other) - { - super(other.getAcl()); - int index = 0; - AVMDAOs.Instance().fAttributeDAO.save(this); - for (Attribute entry : other) - { - Attribute newAttr = entry.getAttributeImpl(); - ListEntryKey key = new ListEntryKey(this, index++); - ListEntry listEntry = new ListEntryImpl(key, newAttr); - AVMDAOs.Instance().fListEntryDAO.save(listEntry); - } - } - - public Type getType() - { - return Type.LIST; - } - - public Serializable getRawValue() - { - List entries = AVMDAOs.Instance().fListEntryDAO.get(this); - ArrayList ret = new ArrayList(entries.size()); - for (ListEntry listEntry : entries) - { - Serializable rawEntry = listEntry.getAttribute().getRawValue(); - ret.add(rawEntry); - } - return ret; - } - - @Override - public void add(Attribute attr) - { - int size = AVMDAOs.Instance().fListEntryDAO.size(this); - ListEntryKey key = new ListEntryKey(this, size); - ListEntry entry = new ListEntryImpl(key, attr); - AVMDAOs.Instance().fListEntryDAO.save(entry); - } - - @Override - public void add(int index, Attribute attr) - { - ListEntryDAO dao = AVMDAOs.Instance().fListEntryDAO; - int size = dao.size(this); - if (index > size || index < 0) - { - throw new AVMBadArgumentException("Index out of bounds: " + index); - } - for (int i = size; i > index; i--) - { - ListEntryKey key = new ListEntryKey(this, i - 1); - ListEntry entry = dao.get(key); - key = new ListEntryKey(this, i); - ListEntry newEntry = new ListEntryImpl(key, entry.getAttribute()); - dao.delete(entry); - dao.save(newEntry); - } - ListEntryKey key = new ListEntryKey(this, index); - ListEntry newEntry = new ListEntryImpl(key, attr); - dao.save(newEntry); - } - - @Override - public void clear() - { - AVMDAOs.Instance().fListEntryDAO.delete(this); - } - - @Override - public Attribute get(int index) - { - ListEntryKey key = new ListEntryKey(this, index); - ListEntry entry = AVMDAOs.Instance().fListEntryDAO.get(key); - if (entry == null) - { - return null; - } - return entry.getAttribute(); - } - - @Override - public Iterator iterator() - { - List entries = AVMDAOs.Instance().fListEntryDAO.get(this); - List attrList = new ArrayList(); - for (ListEntry entry : entries) - { - attrList.add(entry.getAttribute()); - } - return attrList.iterator(); - } - - @Override - public int size() - { - return AVMDAOs.Instance().fListEntryDAO.size(this); - } - - @Override - public void remove(int index) - { - ListEntryDAO dao = AVMDAOs.Instance().fListEntryDAO; - ListEntryKey key = new ListEntryKey(this, index); - ListEntry entry = dao.get(key); - if (entry == null) - { - throw new AVMBadArgumentException("Index out of bounds: " + index); - } - int size = dao.size(this); - dao.delete(entry); - AVMDAOs.Instance().fAttributeDAO.delete(entry.getAttribute()); - for (int i = index; i < size - 1; i++) - { - key = new ListEntryKey(this, i + 1); - entry = dao.get(key); - key = new ListEntryKey(this, i); - ListEntry newEntry = new ListEntryImpl(key, entry.getAttribute()); - dao.delete(entry); - dao.save(newEntry); - } - } - - @Override - public String toString() - { - StringBuilder builder = new StringBuilder(); - builder.append('['); - for (Attribute child : this) - { - builder.append(child.toString()); - builder.append(' '); - } - builder.append(']'); - return builder.toString(); - } - - @Override - public void set(int index, Attribute value) - { - ListEntryKey key = new ListEntryKey(this, index); - ListEntry entry = AVMDAOs.Instance().fListEntryDAO.get(key); - if (entry == null) - { - throw new AVMBadArgumentException("Index out of bounds: " + index); - } - Attribute oldAttr = entry.getAttribute(); - entry.setAttribute(value); - AVMDAOs.Instance().fAttributeDAO.delete(oldAttr); - } -} diff --git a/source/java/org/alfresco/repo/attributes/ListAttributeValue.java b/source/java/org/alfresco/repo/attributes/ListAttributeValue.java deleted file mode 100644 index bef3486f54..0000000000 --- a/source/java/org/alfresco/repo/attributes/ListAttributeValue.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/** - * Value based implementation of a list attribute. - * @author britt - */ -public class ListAttributeValue extends AttributeValue implements ListAttribute -{ - private static final long serialVersionUID = 791121577967727000L; - - private List fData; - - public ListAttributeValue() - { - fData = new ArrayList(); - } - - public ListAttributeValue(ListAttribute attr) - { - this(); - for (Attribute entry : attr) - { - // Use the type's factory for AttributeValue - Attribute newAttr = entry.getAttributeValue(); - fData.add(newAttr); - } - } - - public Attribute get(int index) - { - return fData.get(index); - } - - public Type getType() - { - return Type.LIST; - } - - public Serializable getRawValue() - { - return (Serializable) fData; - } - - @Override - public void add(Attribute attr) - { - fData.add(attr); - } - - @Override - public void add(int index, Attribute attr) - { - fData.add(index, attr); - } - - @Override - public Iterator iterator() - { - return fData.iterator(); - } - - @Override - public int size() - { - return fData.size(); - } - - @Override - public void remove(int index) - { - fData.remove(index); - } - - @Override - public String toString() - { - StringBuilder builder = new StringBuilder(); - builder.append('['); - for (Attribute child : fData) - { - builder.append(child.toString()); - builder.append(' '); - } - builder.append(']'); - return builder.toString(); - } - - @Override - public void set(int index, Attribute value) - { - fData.set(index, value); - } -} diff --git a/source/java/org/alfresco/repo/attributes/ListEntry.java b/source/java/org/alfresco/repo/attributes/ListEntry.java deleted file mode 100644 index 6551a0c7a3..0000000000 --- a/source/java/org/alfresco/repo/attributes/ListEntry.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -/** - * Interface for list entries. - * @author britt - */ -public interface ListEntry extends Serializable -{ - /** - * Get the key. - * @return The key. - */ - public ListEntryKey getKey(); - - /** - * Get the Attribute for this entry. - * @return The Attribute - */ - public Attribute getAttribute(); - - /** - * Set the Attribute. - * @param attr The attribute to set. - */ - public void setAttribute(Attribute attr); -} diff --git a/source/java/org/alfresco/repo/attributes/ListEntryDAO.java b/source/java/org/alfresco/repo/attributes/ListEntryDAO.java deleted file mode 100644 index f2ef72bd26..0000000000 --- a/source/java/org/alfresco/repo/attributes/ListEntryDAO.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.util.List; - -import org.alfresco.repo.domain.hibernate.DirtySessionAnnotation; - -/** - * DAO interface for ListEntries. - * @author britt - */ -public interface ListEntryDAO -{ - /** - * Save a new Entry. - * @param entry - */ - @DirtySessionAnnotation(markDirty=true) - public void save(ListEntry entry); - - /** - * Get the entry for the give list and index. - * @param list The ListAttribute. - * @param index The index. - * @return The ListEntry. - */ - @DirtySessionAnnotation(markDirty=false) - public ListEntry get(ListEntryKey key); - - /** - * Get all entries for a given list. - * @param list The ListAttribute. - * @return The entries. - */ - @DirtySessionAnnotation(markDirty=false) - public List get(ListAttribute list); - - /** - * Delete a list entry. - * @param entry - */ - @DirtySessionAnnotation(markDirty=true) - public void delete(ListEntry entry); - - /** - * Delete all entries from a list. - * @param list - */ - @DirtySessionAnnotation(markDirty=true) - public void delete(ListAttribute list); - - /** - * Get the size of the entries. - * @param list The list. - * @return The count of entries. - */ - @DirtySessionAnnotation(markDirty=false) - public int size(ListAttribute list); -} diff --git a/source/java/org/alfresco/repo/attributes/ListEntryImpl.java b/source/java/org/alfresco/repo/attributes/ListEntryImpl.java deleted file mode 100644 index d5a22110e9..0000000000 --- a/source/java/org/alfresco/repo/attributes/ListEntryImpl.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * Implementation of ListEntry - * @author britt - */ -public class ListEntryImpl implements ListEntry -{ - private static final long serialVersionUID = 1573391734169157835L; - - private ListEntryKey fKey; - - private Attribute fAttribute; - - /** - * Default constructor. - */ - public ListEntryImpl() - { - } - - public ListEntryImpl(ListEntryKey key, Attribute attr) - { - fKey = key; - fAttribute = attr; - } - - public void setKey(ListEntryKey key) - { - fKey = key; - } - - public ListEntryKey getKey() - { - return fKey; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.ListEntry#getAttribute() - */ - public Attribute getAttribute() - { - return fAttribute; - } - - public void setAttribute(Attribute attr) - { - fAttribute = attr; - } - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (!(obj instanceof ListEntry)) - { - return false; - } - return fKey.equals(((ListEntry)obj).getKey()); - } - - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() - { - return fKey.hashCode(); - } - - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - @Override - public String toString() - { - StringBuilder builder = new StringBuilder(); - builder.append("[ListEntry:"); - builder.append(fKey.toString()); - builder.append(':'); - builder.append(fAttribute.toString()); - builder.append(']'); - return builder.toString(); - } -} diff --git a/source/java/org/alfresco/repo/attributes/ListEntryKey.java b/source/java/org/alfresco/repo/attributes/ListEntryKey.java deleted file mode 100644 index e1a144c4fd..0000000000 --- a/source/java/org/alfresco/repo/attributes/ListEntryKey.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -/** - * Key class for the ListEntry entity. - * @author britt - */ -public class ListEntryKey implements Serializable -{ - private static final long serialVersionUID = 7314576560198411815L; - - private ListAttribute fList; - - private int fIndex; - - public ListEntryKey() - { - } - - public ListEntryKey(ListAttribute list, int index) - { - fList = list; - fIndex = index; - } - - /** - * @return the Index - */ - public int getIndex() - { - return fIndex; - } - - /** - * @param index the fIndex to set - */ - public void setIndex(int index) - { - fIndex = index; - } - - /** - * @return the fList - */ - public ListAttribute getList() - { - return fList; - } - - /** - * @param list the fList to set - */ - public void setList(ListAttribute list) - { - fList = list; - } - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (!(obj instanceof ListEntryKey)) - { - return false; - } - ListEntryKey other = (ListEntryKey)obj; - return fIndex == other.getIndex() && - fList.equals(other.getList()); - } - - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() - { - return fIndex + fList.hashCode(); - } - - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - @Override - public String toString() - { - return "[ListEntryKey:" + fIndex + ']'; - } -} diff --git a/source/java/org/alfresco/repo/attributes/LongAttribute.java b/source/java/org/alfresco/repo/attributes/LongAttribute.java deleted file mode 100644 index aa5cb2ffbe..0000000000 --- a/source/java/org/alfresco/repo/attributes/LongAttribute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * Stub interface for long attributes. - * @author britt - */ -public interface LongAttribute extends Attribute -{ -} diff --git a/source/java/org/alfresco/repo/attributes/LongAttributeImpl.java b/source/java/org/alfresco/repo/attributes/LongAttributeImpl.java deleted file mode 100644 index a0f54cb4d6..0000000000 --- a/source/java/org/alfresco/repo/attributes/LongAttributeImpl.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -import org.alfresco.repo.avm.AVMDAOs; - -/** - * Long valued attribute. - * @author britt - */ -public class LongAttributeImpl extends AttributeImpl implements LongAttribute -{ - private static final long serialVersionUID = 1625735137563940631L; - - private long fValue; - - public LongAttributeImpl() - { - } - - public LongAttributeImpl(long value) - { - fValue = value; - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public LongAttributeImpl(LongAttribute attr) - { - super(attr.getAcl()); - fValue = attr.getLongValue(); - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public Type getType() - { - return Type.LONG; - } - - public Serializable getRawValue() - { - return Long.valueOf(fValue); - } - - @Override - public long getLongValue() - { - return fValue; - } - - @Override - public void setLongValue(long value) - { - fValue = value; - } - - @Override - public String toString() - { - return Long.toString(fValue); - } -} diff --git a/source/java/org/alfresco/repo/attributes/LongAttributeValue.java b/source/java/org/alfresco/repo/attributes/LongAttributeValue.java deleted file mode 100644 index 7b797efe74..0000000000 --- a/source/java/org/alfresco/repo/attributes/LongAttributeValue.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -/** - * Value based implementation of a long attribute. - * @author britt - */ -public class LongAttributeValue extends AttributeValue implements LongAttribute -{ - private static final long serialVersionUID = 3978001405238962585L; - - private long fData; - - public LongAttributeValue(long value) - { - fData = value; - } - - public LongAttributeValue(LongAttribute attr) - { - super(attr.getAcl()); - fData = attr.getLongValue(); - } - - public Type getType() - { - return Type.LONG; - } - - public Serializable getRawValue() - { - return Long.valueOf(fData); - } - - @Override - public long getLongValue() - { - return fData; - } - - @Override - public void setLongValue(long value) - { - fData = value; - } - - @Override - public String toString() - { - return Long.toString(fData); - } -} diff --git a/source/java/org/alfresco/repo/attributes/MapAttribute.java b/source/java/org/alfresco/repo/attributes/MapAttribute.java deleted file mode 100644 index 98d2c75007..0000000000 --- a/source/java/org/alfresco/repo/attributes/MapAttribute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * Placeholder interface for Map attributes. - * @author britt - */ -public interface MapAttribute extends Attribute -{ -} diff --git a/source/java/org/alfresco/repo/attributes/MapAttributeImpl.java b/source/java/org/alfresco/repo/attributes/MapAttributeImpl.java deleted file mode 100644 index 7d8a1ba455..0000000000 --- a/source/java/org/alfresco/repo/attributes/MapAttributeImpl.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; - -import org.alfresco.repo.avm.AVMDAOs; -import org.alfresco.service.cmr.avm.AVMNotFoundException; - -/** - * Persistent map attribute implementation. - * @author britt - */ -public class MapAttributeImpl extends AttributeImpl implements MapAttribute -{ - private static final long serialVersionUID = -2627849542488029248L; - - public MapAttributeImpl() - { - } - - public MapAttributeImpl(MapAttribute attr) - { - super(attr.getAcl()); - AVMDAOs.Instance().fAttributeDAO.save(this); - for (Map.Entry entry : attr.entrySet()) - { - String key = entry.getKey(); - Attribute value = entry.getValue(); - // Use the object's factory for AttributeValue - Attribute newAttr = value.getAttributeImpl(); - // Persist it - MapEntryKey keyEntity = new MapEntryKey(this, key); - MapEntry mapEntry = new MapEntryImpl(keyEntity, newAttr); - AVMDAOs.Instance().fMapEntryDAO.save(mapEntry); - } - } - - public Type getType() - { - return Type.MAP; - } - - public Serializable getRawValue() - { - List entries = AVMDAOs.Instance().fMapEntryDAO.get(this); - HashMap ret = new HashMap(entries.size() * 2); - for (MapEntry entry : entries) - { - ret.put(entry.getKey().getKey(), entry.getAttribute().getSerializableValue()); - } - return ret; - } - - @Override - public void clear() - { - AVMDAOs.Instance().fMapEntryDAO.delete(this); - } - - @Override - public Set> entrySet() - { - List entries = AVMDAOs.Instance().fMapEntryDAO.get(this); - Map map = new HashMap(); - for (MapEntry entry : entries) - { - map.put(entry.getKey().getKey(), entry.getAttribute()); - } - return map.entrySet(); - } - - @Override - public Attribute get(String key) - { - MapEntryKey entryKey = new MapEntryKey(this, key); - MapEntry entry = AVMDAOs.Instance().fMapEntryDAO.get(entryKey); - if (entry == null) - { - return null; - } - Attribute attr = entry.getAttribute(); - return attr; - } - - @Override - public Set keySet() - { - List entries = AVMDAOs.Instance().fMapEntryDAO.get(this); - Set keys = new HashSet(); - for (MapEntry entry : entries) - { - keys.add(entry.getKey().getKey()); - } - return keys; - } - - @Override - public void put(String key, Attribute value) - { - MapEntryKey entryKey = new MapEntryKey(this, key); - MapEntry entry = AVMDAOs.Instance().fMapEntryDAO.get(entryKey); - if (entry != null) - { - Attribute oldAttr = entry.getAttribute(); - entry.setAttribute(value); - AVMDAOs.Instance().fAttributeDAO.delete(oldAttr); - return; - } - entry = new MapEntryImpl(entryKey, value); - AVMDAOs.Instance().fMapEntryDAO.save(entry); - } - - @Override - public void remove(String key) - { - MapEntryKey entryKey = new MapEntryKey(this, key); - MapEntry entry = AVMDAOs.Instance().fMapEntryDAO.get(entryKey); - if (entry == null) - { - throw new AVMNotFoundException("Attribute Not Found: " + key); - } - Attribute attr = entry.getAttribute(); - AVMDAOs.Instance().fMapEntryDAO.delete(entry); - AVMDAOs.Instance().fAttributeDAO.delete(attr); - } - - @Override - public Collection values() - { - List entries = AVMDAOs.Instance().fMapEntryDAO.get(this); - List attrs = new ArrayList(); - for (MapEntry entry : entries) - { - attrs.add(entry.getAttribute()); - } - return attrs; - } - - @Override - public String toString() - { - StringBuilder builder = new StringBuilder(); - builder.append('{'); - for (Map.Entry entry : entrySet()) - { - builder.append(entry.getKey()); - builder.append('='); - builder.append(entry.getValue().toString()); - builder.append(' '); - } - builder.append('}'); - return builder.toString(); - } - - @Override - public int size() - { - return AVMDAOs.Instance().fMapEntryDAO.size(this); - } -} diff --git a/source/java/org/alfresco/repo/attributes/MapAttributeValue.java b/source/java/org/alfresco/repo/attributes/MapAttributeValue.java deleted file mode 100644 index 9feee77b73..0000000000 --- a/source/java/org/alfresco/repo/attributes/MapAttributeValue.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; - -/** - * Value based implementation of a map attribute. - * @author britt - */ -public class MapAttributeValue extends AttributeValue implements MapAttribute -{ - private static final long serialVersionUID = -5090943744202078113L; - - private Map fData; - - public MapAttributeValue() - { - fData = new HashMap(); - } - - public MapAttributeValue(MapAttribute attr) - { - super(attr.getAcl()); - fData = new HashMap(); - for (Map.Entry entry : attr.entrySet()) - { - String key = entry.getKey(); - Attribute value = entry.getValue(); - // Use the object's factory for AttributeValue - Attribute newAttr = value.getAttributeValue(); - // Put it into the map - fData.put(key, newAttr); - } - } - - public Type getType() - { - return Type.MAP; - } - - public Serializable getRawValue() - { - return (Serializable) fData; - } - - @Override - public void clear() - { - fData.clear(); - } - - @Override - public Set> entrySet() - { - return fData.entrySet(); - } - - @Override - public Attribute get(String key) - { - return fData.get(key); - } - - @Override - public Set keySet() - { - return fData.keySet(); - } - - @Override - public void put(String key, Attribute value) - { - fData.put(key, value); - } - - @Override - public void remove(String key) - { - fData.remove(key); - } - - @Override - public Collection values() - { - return fData.values(); - } - - @Override - public String toString() - { - StringBuilder builder = new StringBuilder(); - builder.append('{'); - for (Map.Entry entry : fData.entrySet()) - { - builder.append(entry.getKey()); - builder.append('='); - builder.append(entry.getValue().toString()); - builder.append(' '); - } - builder.append('}'); - return builder.toString(); - } - - @Override - public int size() - { - return fData.size(); - } -} diff --git a/source/java/org/alfresco/repo/attributes/MapEntry.java b/source/java/org/alfresco/repo/attributes/MapEntry.java deleted file mode 100644 index da12a458e7..0000000000 --- a/source/java/org/alfresco/repo/attributes/MapEntry.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * Interface for map entries. - * @author britt - */ -public interface MapEntry -{ - /** - * Get the primary key. - * @return The key. - */ - public MapEntryKey getKey(); - - /** - * Get the value attribute. - * @return The value attribute. - */ - public Attribute getAttribute(); - - /** - * Set the value of this attribute. - * @param attr - */ - public void setAttribute(Attribute attr); -} diff --git a/source/java/org/alfresco/repo/attributes/MapEntryDAO.java b/source/java/org/alfresco/repo/attributes/MapEntryDAO.java deleted file mode 100644 index 4a36dfcd01..0000000000 --- a/source/java/org/alfresco/repo/attributes/MapEntryDAO.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.attributes; - -import java.util.List; - -import org.alfresco.repo.domain.hibernate.DirtySessionAnnotation; - -/** - * Interface for MapEntry persistence. - * @author britt - */ -public interface MapEntryDAO -{ - /** - * Save a MapEntry. - * @param entry To save. - */ - @DirtySessionAnnotation(markDirty=true) - public void save(MapEntry entry); - - /** - * Delete a MapEntry. - * @param entry - */ - @DirtySessionAnnotation(markDirty=true) - public void delete(MapEntry entry); - - /** - * Delete all entries for a map. - * @param mapAttr The map to purge. - */ - @DirtySessionAnnotation(markDirty=true) - public void delete(MapAttribute mapAttr); - - /** - * Get an entry by name. - * @param key The key of the entry. - * @return A MapEntry or null. - */ - @DirtySessionAnnotation(markDirty=false) - public MapEntry get(MapEntryKey key); - - /** - * Retrieve all the entries in a map. - * @param mapAttr - * @return A List of all entries in the given map. - */ - @DirtySessionAnnotation(markDirty=false) - public List get(MapAttribute mapAttr); - - /** - * Get the number of entries in a MapAttribute. - * @param mapAttr The MapAttribute/ - * @return The number of entries. - */ - @DirtySessionAnnotation(markDirty=false) - public int size(MapAttribute mapAttr); - - /** - * Evict an entry. - * @param entry - */ - @DirtySessionAnnotation(markDirty=false) - public void evict(MapEntry entry); -} diff --git a/source/java/org/alfresco/repo/attributes/MapEntryImpl.java b/source/java/org/alfresco/repo/attributes/MapEntryImpl.java deleted file mode 100644 index 33d5b2ca29..0000000000 --- a/source/java/org/alfresco/repo/attributes/MapEntryImpl.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * Implementation of map entries. - * @author britt - */ -public class MapEntryImpl implements MapEntry -{ - private MapEntryKey fKey; - - private Attribute fAttribute; - - public MapEntryImpl() - { - } - - public MapEntryImpl(MapEntryKey key, - Attribute attribute) - { - fKey = key; - fAttribute = attribute; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.MapEntry#getAttribute() - */ - public Attribute getAttribute() - { - return fAttribute; - } - - /** - * Set the attribute. - * @param attr The attribute. - */ - public void setAttribute(Attribute attr) - { - fAttribute = attr; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.MapEntry#getKey() - */ - public MapEntryKey getKey() - { - return fKey; - } - - /** - * Setter. - */ - public void setKey(MapEntryKey key) - { - fKey = key; - } - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (!(obj instanceof MapEntry)) - { - return false; - } - return fKey.equals(((MapEntry)obj).getKey()); - } - - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() - { - return fKey.hashCode(); - } - - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - @Override - public String toString() - { - StringBuilder builder = new StringBuilder(); - builder.append("[MapEntry:"); - builder.append(fKey.toString()); - builder.append(']'); - return builder.toString(); - } -} diff --git a/source/java/org/alfresco/repo/attributes/MapEntryKey.java b/source/java/org/alfresco/repo/attributes/MapEntryKey.java deleted file mode 100644 index 3a84dc1007..0000000000 --- a/source/java/org/alfresco/repo/attributes/MapEntryKey.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -/** - * Key class for MapEntries. - * @author britt - */ -public class MapEntryKey implements Serializable -{ - private static final long serialVersionUID = 1637682889407656800L; - - private MapAttribute fMap; - - private String fKey; - - public MapEntryKey() - { - } - - public MapEntryKey(MapAttribute map, String key) - { - fMap = map; - fKey = key; - } - - /** - * @return the Key - */ - public String getKey() - { - return fKey; - } - - /** - * @param key the Key to set - */ - public void setKey(String key) - { - fKey = key; - } - - /** - * @return the Map - */ - public MapAttribute getMap() - { - return fMap; - } - - /** - * @param map the Map to set - */ - public void setMap(MapAttribute map) - { - fMap = map; - } - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (!(obj instanceof MapEntryKey)) - { - return false; - } - MapEntryKey other = (MapEntryKey)obj; - return fKey.equals(other.getKey()) && - fMap.equals(other.getMap()); - } - - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() - { - return fKey.hashCode() + fMap.hashCode(); - } - - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - @Override - public String toString() - { - return "[MapEntryKey:" + fKey + ']'; - } -} diff --git a/source/java/org/alfresco/repo/attributes/SerializableAttribute.java b/source/java/org/alfresco/repo/attributes/SerializableAttribute.java deleted file mode 100644 index 08fa75c781..0000000000 --- a/source/java/org/alfresco/repo/attributes/SerializableAttribute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * Placeholder interface for a Serializable attribute. - * @author britt - */ -public interface SerializableAttribute extends Attribute -{ -} diff --git a/source/java/org/alfresco/repo/attributes/SerializableAttributeImpl.java b/source/java/org/alfresco/repo/attributes/SerializableAttributeImpl.java deleted file mode 100644 index 7e28029e2f..0000000000 --- a/source/java/org/alfresco/repo/attributes/SerializableAttributeImpl.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -import org.alfresco.repo.avm.AVMDAOs; - -/** - * Persistent implemantation of a Serializable attribute. - * @author britt - */ -public class SerializableAttributeImpl extends AttributeImpl implements - SerializableAttribute -{ - private static final long serialVersionUID = -4499585229435904817L; - - private Serializable fValue; - - public SerializableAttributeImpl() - { - } - - public SerializableAttributeImpl(Serializable value) - { - fValue = value; - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public SerializableAttributeImpl(SerializableAttribute attr) - { - super(attr.getAcl()); - fValue = attr.getSerializableValue(); - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public Type getType() - { - return Type.SERIALIZABLE; - } - - public Serializable getRawValue() - { - return fValue; - } - - @Override - public Serializable getSerializableValue() - { - return fValue; - } - - @Override - public void setSerializableValue(Serializable value) - { - fValue = value; - } - - @Override - public String toString() - { - return fValue.toString(); - } -} diff --git a/source/java/org/alfresco/repo/attributes/SerializableAttributeValue.java b/source/java/org/alfresco/repo/attributes/SerializableAttributeValue.java deleted file mode 100644 index 4c17b350e4..0000000000 --- a/source/java/org/alfresco/repo/attributes/SerializableAttributeValue.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -/** - * Value based implemenation of a Serializable attribute. - * @author britt - */ -public class SerializableAttributeValue extends AttributeValue implements - SerializableAttribute -{ - private static final long serialVersionUID = 7899458940760116171L; - - private Serializable fData; - - public SerializableAttributeValue(Serializable value) - { - fData = value; - } - - public SerializableAttributeValue(SerializableAttribute attr) - { - super(attr.getAcl()); - fData = attr.getSerializableValue(); - } - - public Type getType() - { - return Type.SERIALIZABLE; - } - - public Serializable getRawValue() - { - return fData; - } - - @Override - public Serializable getSerializableValue() - { - return fData; - } - - @Override - public void setSerializableValue(Serializable value) - { - fData = value; - } - - @Override - public String toString() - { - return fData.toString(); - } -} diff --git a/source/java/org/alfresco/repo/attributes/ShortAttribute.java b/source/java/org/alfresco/repo/attributes/ShortAttribute.java deleted file mode 100644 index 93beeeebfd..0000000000 --- a/source/java/org/alfresco/repo/attributes/ShortAttribute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * Stub interface for shorts. - * @author britt - */ -public interface ShortAttribute extends Attribute -{ -} diff --git a/source/java/org/alfresco/repo/attributes/ShortAttributeImpl.java b/source/java/org/alfresco/repo/attributes/ShortAttributeImpl.java deleted file mode 100644 index 4c1e5da5b0..0000000000 --- a/source/java/org/alfresco/repo/attributes/ShortAttributeImpl.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -import org.alfresco.repo.avm.AVMDAOs; - -/** - * A short attribute. - * @author britt - */ -public class ShortAttributeImpl extends AttributeImpl implements ShortAttribute -{ - private static final long serialVersionUID = 583269625932011762L; - - private short fValue; - - public ShortAttributeImpl() - { - } - - public ShortAttributeImpl(short value) - { - fValue = value; - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public ShortAttributeImpl(ShortAttribute attr) - { - super(attr.getAcl()); - fValue = attr.getShortValue(); - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - @Override - public short getShortValue() - { - return fValue; - } - - @Override - public void setShortValue(short value) - { - fValue = value; - } - - public Type getType() - { - return Type.SHORT; - } - - public Serializable getRawValue() - { - return Short.valueOf(fValue); - } - - @Override - public String toString() - { - return Short.toString(fValue); - } -} diff --git a/source/java/org/alfresco/repo/attributes/ShortAttributeValue.java b/source/java/org/alfresco/repo/attributes/ShortAttributeValue.java deleted file mode 100644 index e3afd1693e..0000000000 --- a/source/java/org/alfresco/repo/attributes/ShortAttributeValue.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -/** - * Value based implementation of a short attribute. - * @author britt - */ -public class ShortAttributeValue extends AttributeValue implements - ShortAttribute -{ - private static final long serialVersionUID = -2224950695651369979L; - - private short fData; - - public ShortAttributeValue(short value) - { - fData = value; - } - - public ShortAttributeValue(ShortAttribute attr) - { - super(attr.getAcl()); - fData = attr.getShortValue(); - } - - public Type getType() - { - return Type.SHORT; - } - - public Serializable getRawValue() - { - return Short.valueOf(fData); - } - - @Override - public short getShortValue() - { - return fData; - } - - @Override - public void setShortValue(short value) - { - fData = value; - } - - @Override - public String toString() - { - return Short.toString(fData); - } -} diff --git a/source/java/org/alfresco/repo/attributes/StringAttribute.java b/source/java/org/alfresco/repo/attributes/StringAttribute.java deleted file mode 100644 index 30fb3d29d0..0000000000 --- a/source/java/org/alfresco/repo/attributes/StringAttribute.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -/** - * Place holder interface for String valued attributes. - * @author britt - */ -public interface StringAttribute extends Attribute -{ -} diff --git a/source/java/org/alfresco/repo/attributes/StringAttributeImpl.java b/source/java/org/alfresco/repo/attributes/StringAttributeImpl.java deleted file mode 100644 index 10a12b4b6b..0000000000 --- a/source/java/org/alfresco/repo/attributes/StringAttributeImpl.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -import org.alfresco.repo.avm.AVMDAOs; - -/** - * Persistent implementation of String valued attribute. - * @author britt - */ -public class StringAttributeImpl extends AttributeImpl implements - StringAttribute -{ - private static final long serialVersionUID = -2877268541212029648L; - - private String fValue; - - public StringAttributeImpl() - { - } - - public StringAttributeImpl(String value) - { - fValue = value; - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public StringAttributeImpl(StringAttribute attr) - { - super(attr.getAcl()); - fValue = attr.getStringValue(); - AVMDAOs.Instance().fAttributeDAO.save(this); - } - - public Type getType() - { - return Type.STRING; - } - - public Serializable getRawValue() - { - return fValue; - } - - @Override - public String getStringValue() - { - return fValue; - } - - @Override - public void setStringValue(String value) - { - fValue = value; - } - - @Override - public String toString() - { - return fValue; - } -} diff --git a/source/java/org/alfresco/repo/attributes/StringAttributeValue.java b/source/java/org/alfresco/repo/attributes/StringAttributeValue.java deleted file mode 100644 index e77d749515..0000000000 --- a/source/java/org/alfresco/repo/attributes/StringAttributeValue.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes; - -import java.io.Serializable; - -/** - * Value based implementation of a String attribute. - * @author britt - */ -public class StringAttributeValue extends AttributeValue implements - StringAttribute -{ - private static final long serialVersionUID = -5702787670770131672L; - - private String fData; - - public StringAttributeValue(String value) - { - fData = value; - } - - public StringAttributeValue(StringAttribute attr) - { - super(attr.getAcl()); - fData = attr.getStringValue(); - } - - public Type getType() - { - return Type.STRING; - } - - public Serializable getRawValue() - { - return fData; - } - - @Override - public String getStringValue() - { - return fData; - } - - @Override - public void setStringValue(String value) - { - fData = value; - } - - @Override - public String toString() - { - return fData; - } -} diff --git a/source/java/org/alfresco/repo/attributes/hibernate/AttributeDAOHibernate.java b/source/java/org/alfresco/repo/attributes/hibernate/AttributeDAOHibernate.java deleted file mode 100644 index ffb2120d1b..0000000000 --- a/source/java/org/alfresco/repo/attributes/hibernate/AttributeDAOHibernate.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes.hibernate; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.alfresco.repo.attributes.AttrQueryHelperImpl; -import org.alfresco.repo.attributes.Attribute; -import org.alfresco.repo.attributes.AttributeDAO; -import org.alfresco.repo.attributes.ListAttribute; -import org.alfresco.repo.attributes.ListEntry; -import org.alfresco.repo.attributes.ListEntryDAO; -import org.alfresco.repo.attributes.MapAttribute; -import org.alfresco.repo.attributes.MapEntry; -import org.alfresco.repo.attributes.MapEntryDAO; -import org.alfresco.repo.attributes.Attribute.Type; -import org.alfresco.repo.domain.hibernate.DirtySessionMethodInterceptor; -import org.alfresco.service.cmr.attributes.AttrQuery; -import org.alfresco.service.cmr.attributes.AttrQueryHelper; -import org.alfresco.util.Pair; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.Query; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; - -/** - * Hibernate implementation of persistence for Attributes. - * @author britt - */ -public class AttributeDAOHibernate extends HibernateDaoSupport implements - AttributeDAO -{ - private static Log fgLogger = LogFactory.getLog(AttributeDAOHibernate.class); - - private MapEntryDAO fMapEntryDAO; - - private ListEntryDAO fListEntryDAO; - - public AttributeDAOHibernate() - { - } - - public void setMapEntryDao(MapEntryDAO dao) - { - fMapEntryDAO = dao; - } - - public void setListEntryDao(ListEntryDAO dao) - { - fListEntryDAO = dao; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.AttributeDAO#delete(org.alfresco.repo.attributes.Attribute) - */ - public void delete(Attribute attr) - { - if (attr.getType() == Type.MAP) - { - MapAttribute map = (MapAttribute)attr; - List mapEntries = fMapEntryDAO.get(map); - for (MapEntry entry : mapEntries) - { - Attribute subAttr = entry.getAttribute(); - fMapEntryDAO.delete(entry); - delete(subAttr); - } - } - if (attr.getType() == Type.LIST) - { - ListAttribute list = (ListAttribute)attr; - List listEntries = fListEntryDAO.get(list); - for (ListEntry entry : listEntries) - { - Attribute subAttr = entry.getAttribute(); - fListEntryDAO.delete(entry); - delete(subAttr); - } - } - if (fgLogger.isDebugEnabled()) - { - fgLogger.debug("Entities: " + getSession().getStatistics().getEntityCount()); - } - getSession().delete(attr); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.AttributeDAO#find(java.lang.String, org.alfresco.service.cmr.attributes.AttrQuery) - */ - @SuppressWarnings("unchecked") - public List> find(MapAttribute map, AttrQuery query) - { - AttrQueryHelper helper = new AttrQueryHelperImpl(); - String predicate = query.getPredicate(helper); - String fullQuery = "from MapEntryImpl me where me.key.map = :map and " + predicate; - Query hQuery = getSession().createQuery(fullQuery); - hQuery.setEntity("map", map); - for (Map.Entry param : helper.getParameters().entrySet()) - { - hQuery.setParameter(param.getKey(), param.getValue()); - } - DirtySessionMethodInterceptor.setQueryFlushMode(getSession(), hQuery); - List hits = (List)hQuery.list(); - List> result = new ArrayList>(); - for (MapEntry entry : hits) - { - result.add(new Pair(entry.getKey().getKey(), entry.getAttribute())); - } - return result; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.AttributeDAO#delete(org.alfresco.repo.attributes.MapAttribute, org.alfresco.service.cmr.attributes.AttrQuery) - */ - public void delete(MapAttribute map, AttrQuery query) - { - List> result = find(map, query); - for (Pair entry : result) - { - map.remove(entry.getFirst()); - } - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.AttributeDAO#save(org.alfresco.repo.attributes.Attribute) - */ - public void save(Attribute attr) - { - getSession().save(attr); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.AttributeDAO#evict(org.alfresco.repo.attributes.Attribute) - */ - public void evict(Attribute attr) - { - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.AttributeDAO#flush() - */ - public void flush() - { - getSession().flush(); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.AttributeDAO#evictFlat(org.alfresco.repo.attributes.Attribute) - */ - public void evictFlat(Attribute attr) - { - } -} diff --git a/source/java/org/alfresco/repo/attributes/hibernate/Attributes.hbm.xml b/source/java/org/alfresco/repo/attributes/hibernate/Attributes.hbm.xml deleted file mode 100644 index 367025745a..0000000000 --- a/source/java/org/alfresco/repo/attributes/hibernate/Attributes.hbm.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/source/java/org/alfresco/repo/attributes/hibernate/GlobalAttributeEntryDAOHibernate.java b/source/java/org/alfresco/repo/attributes/hibernate/GlobalAttributeEntryDAOHibernate.java deleted file mode 100644 index f5e04ec626..0000000000 --- a/source/java/org/alfresco/repo/attributes/hibernate/GlobalAttributeEntryDAOHibernate.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes.hibernate; - -import java.util.List; - -import org.alfresco.repo.attributes.Attribute; -import org.alfresco.repo.attributes.AttributeDAO; -import org.alfresco.repo.attributes.GlobalAttributeEntry; -import org.alfresco.repo.attributes.GlobalAttributeEntryDAO; -import org.alfresco.repo.attributes.GlobalAttributeEntryImpl; -import org.alfresco.repo.domain.hibernate.DirtySessionMethodInterceptor; -import org.hibernate.Query; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; - -/** - * Hibernate implementation of Global Attribute Entries. - * @author britt - */ -public class GlobalAttributeEntryDAOHibernate extends HibernateDaoSupport - implements GlobalAttributeEntryDAO -{ - private AttributeDAO fAttributeDAO; - - public GlobalAttributeEntryDAOHibernate() - { - } - - public void setAttributeDao(AttributeDAO dao) - { - fAttributeDAO = dao; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.GlobalAttributeEntryDAO#delete(org.alfresco.repo.attributes.GlobalAttributeEntry) - */ - public void delete(GlobalAttributeEntry entry) - { - Attribute attr = entry.getAttribute(); - getSession().delete(entry); - fAttributeDAO.delete(attr); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.GlobalAttributeEntryDAO#delete(java.lang.String) - */ - public void delete(String name) - { - delete((GlobalAttributeEntry)getSession().get(GlobalAttributeEntryImpl.class, name)); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.GlobalAttributeEntryDAO#get(java.lang.String) - */ - public GlobalAttributeEntry get(String name) - { - return (GlobalAttributeEntry)getSession().get(GlobalAttributeEntryImpl.class, name); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.GlobalAttributeEntryDAO#save(org.alfresco.repo.attributes.GlobalAttributeEntry) - */ - public void save(GlobalAttributeEntry entry) - { - getSession().save(entry); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.GlobalAttributeEntryDAO#getKeys() - */ - @SuppressWarnings("unchecked") - public List getKeys() - { - Query query = getSession().createQuery("select gae.name from GlobalAttributeEntryImpl gae"); - DirtySessionMethodInterceptor.setQueryFlushMode(getSession(), query); - return (List)query.list(); - } -} diff --git a/source/java/org/alfresco/repo/attributes/hibernate/ListEntryDAOHibernate.java b/source/java/org/alfresco/repo/attributes/hibernate/ListEntryDAOHibernate.java deleted file mode 100644 index 5a47310ed7..0000000000 --- a/source/java/org/alfresco/repo/attributes/hibernate/ListEntryDAOHibernate.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes.hibernate; - -import java.util.List; - -import org.alfresco.repo.attributes.ListAttribute; -import org.alfresco.repo.attributes.ListEntry; -import org.alfresco.repo.attributes.ListEntryDAO; -import org.alfresco.repo.attributes.ListEntryImpl; -import org.alfresco.repo.attributes.ListEntryKey; -import org.alfresco.repo.domain.hibernate.DirtySessionMethodInterceptor; -import org.hibernate.Query; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; - -/** - * @author britt - * - */ -public class ListEntryDAOHibernate extends HibernateDaoSupport implements - ListEntryDAO -{ - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.ListEntryDAO#delete(org.alfresco.repo.attributes.ListEntry) - */ - public void delete(ListEntry entry) - { - getSession().delete(entry); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.ListEntryDAO#delete(org.alfresco.repo.attributes.ListAttribute) - */ - public void delete(ListAttribute list) - { - Query query = getSession().createQuery("delete from ListEntryImpl le where le.key.list = :list"); - query.setEntity("list", list); - query.executeUpdate(); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.ListEntryDAO#get(org.alfresco.repo.attributes.ListAttribute, int) - */ - public ListEntry get(ListEntryKey key) - { - return (ListEntry)getSession().get(ListEntryImpl.class, key); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.ListEntryDAO#get(org.alfresco.repo.attributes.ListAttribute) - */ - @SuppressWarnings("unchecked") - public List get(ListAttribute list) - { - Query query = getSession().createQuery("from ListEntryImpl le where le.key.list = :list"); - query.setEntity("list", list); - DirtySessionMethodInterceptor.setQueryFlushMode(getSession(), query); - return (List)query.list(); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.ListEntryDAO#save(org.alfresco.repo.attributes.ListEntry) - */ - public void save(ListEntry entry) - { - getSession().save(entry); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.ListEntryDAO#size(org.alfresco.repo.attributes.ListAttribute) - */ - public int size(ListAttribute list) - { - Query query = getSession().createQuery("select count(*) from ListEntryImpl le where le.key.list = :list"); - query.setEntity("list", list); - DirtySessionMethodInterceptor.setQueryFlushMode(getSession(), query); - return ((Long)query.uniqueResult()).intValue(); - } -} diff --git a/source/java/org/alfresco/repo/attributes/hibernate/MapEntryDAOHibernate.java b/source/java/org/alfresco/repo/attributes/hibernate/MapEntryDAOHibernate.java deleted file mode 100644 index 28d20f1313..0000000000 --- a/source/java/org/alfresco/repo/attributes/hibernate/MapEntryDAOHibernate.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.attributes.hibernate; - -import java.util.List; - -import org.alfresco.repo.attributes.MapAttribute; -import org.alfresco.repo.attributes.MapEntry; -import org.alfresco.repo.attributes.MapEntryDAO; -import org.alfresco.repo.attributes.MapEntryImpl; -import org.alfresco.repo.attributes.MapEntryKey; -import org.alfresco.repo.domain.hibernate.DirtySessionMethodInterceptor; -import org.hibernate.Query; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; - -/** - * Hibernate implementation of persistence for MapEntries. - * @author britt - */ -public class MapEntryDAOHibernate extends HibernateDaoSupport implements - MapEntryDAO -{ - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.MapEntryDAO#delete(org.alfresco.repo.attributes.MapEntry) - */ - public void delete(MapEntry entry) - { - getSession().delete(entry); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.MapEntryDAO#delete(org.alfresco.repo.attributes.MapAttribute) - */ - public void delete(MapAttribute mapAttr) - { - Query query = getSession().createQuery("delete from MapEntryImpl me where me.key.map = :map"); - query.setEntity("map", mapAttr); - query.executeUpdate(); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.MapEntryDAO#get(org.alfresco.repo.attributes.MapAttribute, java.lang.String) - */ - public MapEntry get(MapEntryKey key) - { - return (MapEntry)getSession().get(MapEntryImpl.class, key); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.MapEntryDAO#get(org.alfresco.repo.attributes.MapAttribute) - */ - @SuppressWarnings("unchecked") - public List get(MapAttribute mapAttr) - { - Query query = getSession().createQuery("from MapEntryImpl me where me.key.map = :map"); - query.setEntity("map", mapAttr); - DirtySessionMethodInterceptor.setQueryFlushMode(getSession(), query); - return (List)query.list(); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.MapEntryDAO#save(org.alfresco.repo.attributes.MapEntry) - */ - public void save(MapEntry entry) - { - getSession().save(entry); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.MapEntryDAO#size(org.alfresco.repo.attributes.MapAttribute) - */ - public int size(MapAttribute mapAttr) - { - Query query = getSession().createQuery("select count(*) from MapEntryImpl me where me.key.map = :map"); - query.setEntity("map", mapAttr); - DirtySessionMethodInterceptor.setQueryFlushMode(getSession(), query); - return ((Long)query.uniqueResult()).intValue(); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.attributes.MapEntryDAO#evict(org.alfresco.repo.attributes.MapEntry) - */ - public void evict(MapEntry entry) - { - } -} diff --git a/source/java/org/alfresco/repo/audit/AuditableAspectTest.java b/source/java/org/alfresco/repo/audit/AuditableAspectTest.java index d6de6e8f50..fa04a984ac 100644 --- a/source/java/org/alfresco/repo/audit/AuditableAspectTest.java +++ b/source/java/org/alfresco/repo/audit/AuditableAspectTest.java @@ -30,8 +30,10 @@ 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.QName; +import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.BaseSpringTest; import org.alfresco.util.debug.NodeStoreInspector; +import org.springframework.context.ApplicationContext; /** * Checks that the behaviour of the {@link org.alfresco.repo.audit.AuditableAspect auditable aspect} @@ -41,48 +43,48 @@ import org.alfresco.util.debug.NodeStoreInspector; */ public class AuditableAspectTest extends BaseSpringTest { - /** - * Services used by the tests - */ - private NodeService nodeService; - - /** - * Data used by the tests - */ - private StoreRef storeRef; - private NodeRef rootNodeRef; - - /** - * On setup in transaction implementation - */ - @Override - protected void onSetUpInTransaction() - throws Exception - { - // Set the services - this.nodeService = (NodeService)this.applicationContext.getBean("dbNodeService"); - - // Create the store and get the root node reference - this.storeRef = this.nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis()); - this.rootNodeRef = this.nodeService.getRootNode(storeRef); - } - - + private static final ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + + /* + * Services used by the tests + */ + private NodeService nodeService; + + /** + * Data used by the tests + */ + private StoreRef storeRef; + private NodeRef rootNodeRef; + + /** + * On setup in transaction implementation + */ + @Override + protected void onSetUpInTransaction() throws Exception + { + // Set the services + this.nodeService = (NodeService)ctx.getBean("dbNodeService"); + + // Create the store and get the root node reference + this.storeRef = this.nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis()); + this.rootNodeRef = this.nodeService.getRootNode(storeRef); + } + public void testAudit() - { + { // Create a folder ChildAssociationRef childAssocRef = nodeService.createNode( rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{test}testfolder"), ContentModel.TYPE_FOLDER); - + // Assert auditable properties exist on folder assertAuditableProperties(childAssocRef.getChildRef()); System.out.println(NodeStoreInspector.dumpNodeStore(nodeService, storeRef)); - } - + } + public void testNoAudit() { // Create a person (which doesn't have auditable capability by default) @@ -99,7 +101,7 @@ public class AuditableAspectTest extends BaseSpringTest ContentModel.TYPE_PERSON, personProps); NodeRef nodeRef = childAssocRef.getChildRef(); - + // Assert the person is not auditable Set aspects = nodeService.getAspects(nodeRef); assertFalse("cm:auditable must not be present.", aspects.contains(ContentModel.ASPECT_AUDITABLE)); @@ -114,12 +116,6 @@ public class AuditableAspectTest extends BaseSpringTest System.out.println(NodeStoreInspector.dumpNodeStore(nodeService, storeRef)); } - public void test() throws Throwable - { - - } - - public void testAddAudit() { // Create a person @@ -135,14 +131,15 @@ public class AuditableAspectTest extends BaseSpringTest QName.createQName("{test}testperson"), ContentModel.TYPE_PERSON, personProps); - + // Assert the person is not auditable Set aspects = nodeService.getAspects(childAssocRef.getChildRef()); assertFalse(aspects.contains(ContentModel.ASPECT_AUDITABLE)); // Add auditable capability nodeService.addAspect(childAssocRef.getChildRef(), ContentModel.ASPECT_AUDITABLE, null); - + + // Add (titled) aspect nodeService.addAspect(childAssocRef.getChildRef(), ContentModel.ASPECT_TITLED, null); // Assert the person is now audiable @@ -155,7 +152,7 @@ public class AuditableAspectTest extends BaseSpringTest System.out.println(NodeStoreInspector.dumpNodeStore(nodeService, storeRef)); } - public synchronized void testAddAspect() throws Exception + public synchronized void testAddAndRemoveAspect() throws Exception { // Create a person (which doesn't have auditable capability by default) Map personProps = new HashMap(); @@ -174,6 +171,7 @@ public class AuditableAspectTest extends BaseSpringTest ContentModel.TYPE_PERSON, personProps); NodeRef nodeRef = childAssocRef.getChildRef(); + // Add auditable capability nodeService.addAspect(nodeRef, ContentModel.ASPECT_AUDITABLE, null); @@ -192,9 +190,12 @@ public class AuditableAspectTest extends BaseSpringTest aspectModifiedDate1.getTime() < t2); long t3 = System.currentTimeMillis(); - this.wait(100); + this.wait(100); // Needed for system clock inaccuracies - // Add auditable capability + // Pause to allow for node modifiedDate tolerance (of 1000ms - refer to AbstractNodeDAOImpl.updateNodeImpl) + this.wait(1500); // + + // Add (titled) aspect nodeService.addAspect(nodeRef, ContentModel.ASPECT_TITLED, null); // Check that the dates were set correctly @@ -202,17 +203,78 @@ public class AuditableAspectTest extends BaseSpringTest Date aspectModifiedDate2 = (Date) nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED); assertEquals("The created date must not change", aspectCreatedDate1, aspectCreatedDate2); assertTrue("New modified date should be later than t3", t3 < aspectModifiedDate2.getTime()); - + + System.out.println(NodeStoreInspector.dumpNodeStore(nodeService, storeRef)); + + nodeService.removeAspect(nodeRef, ContentModel.ASPECT_AUDITABLE); + + assertNotAuditableProperties(nodeRef); + System.out.println(NodeStoreInspector.dumpNodeStore(nodeService, storeRef)); } + + /** + * ALF-2565: Allow cm:auditable values to be set programmatically + */ + public void testCreateNodeWithAuditableProperties_ALF_2565() + { + // Create a person (which doesn't have auditable capability by default) + Map personProps = new HashMap(); + personProps.put(ContentModel.PROP_USERNAME, "test person"); + personProps.put(ContentModel.PROP_HOMEFOLDER, rootNodeRef); + personProps.put(ContentModel.PROP_FIRSTNAME, "test first name "); + personProps.put(ContentModel.PROP_LASTNAME, "test last name"); + // Add some auditable properties + Map auditableProps = new HashMap(); + auditableProps.put(ContentModel.PROP_CREATED, new Date(0L)); + auditableProps.put(ContentModel.PROP_CREATOR, "ZeroPerson"); + auditableProps.put(ContentModel.PROP_MODIFIED, new Date(1L)); + auditableProps.put(ContentModel.PROP_MODIFIER, "OnePerson"); + + personProps.putAll(auditableProps); + ChildAssociationRef childAssocRef = nodeService.createNode( + rootNodeRef, + ContentModel.ASSOC_CHILDREN, + QName.createQName("{test}testperson"), + ContentModel.TYPE_PERSON, + personProps); + NodeRef nodeRef = childAssocRef.getChildRef(); + + assertAuditableProperties(nodeRef, auditableProps); + } + private void assertAuditableProperties(NodeRef nodeRef) + { + assertAuditableProperties(nodeRef, null); + } + + private void assertAuditableProperties(NodeRef nodeRef, Map checkProps) { Map props = nodeService.getProperties(nodeRef); assertNotNull(props.get(ContentModel.PROP_CREATED)); assertNotNull(props.get(ContentModel.PROP_MODIFIED)); assertNotNull(props.get(ContentModel.PROP_CREATOR)); assertNotNull(props.get(ContentModel.PROP_MODIFIER)); + if (checkProps != null) + { + assertEquals("PROP_CREATED not correct", + checkProps.get(ContentModel.PROP_CREATED), props.get(ContentModel.PROP_CREATED)); + assertEquals("PROP_MODIFIED not correct", + checkProps.get(ContentModel.PROP_MODIFIED), props.get(ContentModel.PROP_MODIFIED)); + assertEquals("PROP_CREATOR not correct", + checkProps.get(ContentModel.PROP_CREATOR), props.get(ContentModel.PROP_CREATOR)); + assertEquals("PROP_MODIFIER not correct", + checkProps.get(ContentModel.PROP_MODIFIER), props.get(ContentModel.PROP_MODIFIER)); + } } + private void assertNotAuditableProperties(NodeRef nodeRef) + { + Map props = nodeService.getProperties(nodeRef); + assertNull(props.get(ContentModel.PROP_CREATED)); + assertNull(props.get(ContentModel.PROP_MODIFIED)); + assertNull(props.get(ContentModel.PROP_CREATOR)); + assertNull(props.get(ContentModel.PROP_MODIFIER)); + } } diff --git a/source/java/org/alfresco/repo/avm/AVMDAOs.java b/source/java/org/alfresco/repo/avm/AVMDAOs.java index 164e9d7b3d..4b95cddb96 100644 --- a/source/java/org/alfresco/repo/avm/AVMDAOs.java +++ b/source/java/org/alfresco/repo/avm/AVMDAOs.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,194 +14,170 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . */ - -package org.alfresco.repo.avm; - -import org.alfresco.repo.attributes.AttributeDAO; -import org.alfresco.repo.attributes.GlobalAttributeEntryDAO; -import org.alfresco.repo.attributes.ListEntryDAO; -import org.alfresco.repo.attributes.MapEntryDAO; + * along with Alfresco. If not, see . */ + +package org.alfresco.repo.avm; + import org.alfresco.repo.domain.contentdata.ContentDataDAO; - -/** - * This is the (shudder) global context for AVM. It a rendezvous - * point for access to needed global instances. - * @author britt - */ -public class AVMDAOs -{ - /** - * The single instance of an AVMContext. - */ - private static final AVMDAOs fgInstance = new AVMDAOs(); - - private AVMDAOs() - { - } - - /** - * Get the instance of this. - * @return - */ - public static AVMDAOs Instance() - { - return fgInstance; - } - - /** - * The AVMNodeDAO. - */ - public AVMNodeDAO fAVMNodeDAO; - - public org.alfresco.repo.domain.avm.AVMNodeDAO newAVMNodeDAO; - public org.alfresco.repo.domain.avm.AVMNodeLinksDAO newAVMNodeLinksDAO; +import org.alfresco.repo.domain.permissions.AclDAO; + +/** + * This is the (shudder) global context for AVM. It a rendezvous + * point for access to needed global instances. + * @author britt + */ +public class AVMDAOs +{ + /** + * The single instance of an AVMContext. + */ + private static final AVMDAOs fgInstance = new AVMDAOs(); + + private AVMDAOs() + { + } + + /** + * Get the instance of this. + * @return + */ + public static AVMDAOs Instance() + { + return fgInstance; + } + + /** + * The AVMNodeDAO. + */ + public AVMNodeDAO fAVMNodeDAO; + + public org.alfresco.repo.domain.avm.AVMNodeDAO newAVMNodeDAO; + public org.alfresco.repo.domain.avm.AVMNodeLinksDAO newAVMNodeLinksDAO; public ContentDataDAO contentDataDAO; - - /** - * The AVMStore DAO. - */ - public AVMStoreDAO fAVMStoreDAO; - - public org.alfresco.repo.domain.avm.AVMStoreDAO newAVMStoreDAO; - - /** - * The VersionRootDAO. - */ - public VersionRootDAO fVersionRootDAO; - - public org.alfresco.repo.domain.avm.AVMVersionRootDAO newAVMVersionRootDAO; - - /** - * The ChildEntryDAO. - */ - public ChildEntryDAO fChildEntryDAO; - - /** - * The HistoryLinkDAO. - */ - public HistoryLinkDAO fHistoryLinkDAO; - - /** - * The MergeLinkDAO. - */ - public MergeLinkDAO fMergeLinkDAO; - - /** - * The AVMStorePropertyDAO - */ - public AVMStorePropertyDAO fAVMStorePropertyDAO; - - public AttributeDAO fAttributeDAO; - - public MapEntryDAO fMapEntryDAO; - - public GlobalAttributeEntryDAO fGlobalAttributeEntryDAO; - - public ListEntryDAO fListEntryDAO; - - public VersionLayeredNodeEntryDAO fVersionLayeredNodeEntryDAO; - - /** - * @param nodeDAO the fAVMNodeDAO to set - */ - public void setNodeDAO(AVMNodeDAO nodeDAO) - { - fAVMNodeDAO = nodeDAO; - } - - public void setNewAvmNodeDAO(org.alfresco.repo.domain.avm.AVMNodeDAO newAVMNodeDAO) - { - this.newAVMNodeDAO = newAVMNodeDAO; - } - - public void setNewAvmNodeLinksDAO(org.alfresco.repo.domain.avm.AVMNodeLinksDAO newAVMNodeLinksDAO) - { - this.newAVMNodeLinksDAO = newAVMNodeLinksDAO; - } - + + /** + * The AVMStore DAO. + */ + public AVMStoreDAO fAVMStoreDAO; + + public org.alfresco.repo.domain.avm.AVMStoreDAO newAVMStoreDAO; + + /** + * The VersionRootDAO. + */ + public VersionRootDAO fVersionRootDAO; + + public org.alfresco.repo.domain.avm.AVMVersionRootDAO newAVMVersionRootDAO; + + /** + * The ChildEntryDAO. + */ + public ChildEntryDAO fChildEntryDAO; + + /** + * The HistoryLinkDAO. + */ + public HistoryLinkDAO fHistoryLinkDAO; + + /** + * The MergeLinkDAO. + */ + public MergeLinkDAO fMergeLinkDAO; + + /** + * The AVMStorePropertyDAO + */ + public AVMStorePropertyDAO fAVMStorePropertyDAO; + + public VersionLayeredNodeEntryDAO fVersionLayeredNodeEntryDAO; + + public AclDAO fAclDAO; + + /** + * @param nodeDAO the fAVMNodeDAO to set + */ + public void setNodeDAO(AVMNodeDAO nodeDAO) + { + fAVMNodeDAO = nodeDAO; + } + + public void setNewAvmNodeDAO(org.alfresco.repo.domain.avm.AVMNodeDAO newAVMNodeDAO) + { + this.newAVMNodeDAO = newAVMNodeDAO; + } + + public void setNewAvmNodeLinksDAO(org.alfresco.repo.domain.avm.AVMNodeLinksDAO newAVMNodeLinksDAO) + { + this.newAVMNodeLinksDAO = newAVMNodeLinksDAO; + } + public void setContentDataDAO(ContentDataDAO contentDataDAO) { this.contentDataDAO = contentDataDAO; } - /** - * @param childEntryDAO the fChildEntryDAO to set - */ - public void setChildEntryDAO(ChildEntryDAO childEntryDAO) - { - fChildEntryDAO = childEntryDAO; - } - - /** - * @param historyLinkDAO the fHistoryLinkDAO to set - */ - public void setHistoryLinkDAO(HistoryLinkDAO historyLinkDAO) - { - fHistoryLinkDAO = historyLinkDAO; - } - - /** - * @param mergeLinkDAO the fMergeLinkDAO to set - */ - public void setMergeLinkDAO(MergeLinkDAO mergeLinkDAO) - { - fMergeLinkDAO = mergeLinkDAO; - } - - /** - * @param aVMStoreDAO The fAVMStoreDAO to set - */ - public void setAvmStoreDAO(AVMStoreDAO aVMStoreDAO) - { - fAVMStoreDAO = aVMStoreDAO; - } - - public void setNewAvmStoreDAO(org.alfresco.repo.domain.avm.AVMStoreDAO newAVMStoreDAO) - { - this.newAVMStoreDAO = newAVMStoreDAO; - } - - /** - * @param versionRootDAO the fVersionRootDAO to set - */ - public void setVersionRootDAO(VersionRootDAO versionRootDAO) - { - fVersionRootDAO = versionRootDAO; - } - - public void setNewAvmVersionRootDAO(org.alfresco.repo.domain.avm.AVMVersionRootDAO newAVMVersionRootDAO) - { - this.newAVMVersionRootDAO = newAVMVersionRootDAO; - } - - public void setAvmStorePropertyDAO(AVMStorePropertyDAO avmStorePropertyDAO) - { - fAVMStorePropertyDAO = avmStorePropertyDAO; - } - - public void setAttributeDAO(AttributeDAO dao) - { - fAttributeDAO = dao; - } - - public void setMapEntryDAO(MapEntryDAO dao) - { - fMapEntryDAO = dao; - } - - public void setGlobalAttributeEntryDAO(GlobalAttributeEntryDAO dao) - { - fGlobalAttributeEntryDAO = dao; - } - - public void setListEntryDAO(ListEntryDAO dao) - { - fListEntryDAO = dao; - } - - public void setVersionLayeredNodeEntryDAO(VersionLayeredNodeEntryDAO dao) - { - fVersionLayeredNodeEntryDAO = dao; - } -} + /** + * @param childEntryDAO the fChildEntryDAO to set + */ + public void setChildEntryDAO(ChildEntryDAO childEntryDAO) + { + fChildEntryDAO = childEntryDAO; + } + + /** + * @param historyLinkDAO the fHistoryLinkDAO to set + */ + public void setHistoryLinkDAO(HistoryLinkDAO historyLinkDAO) + { + fHistoryLinkDAO = historyLinkDAO; + } + + /** + * @param mergeLinkDAO the fMergeLinkDAO to set + */ + public void setMergeLinkDAO(MergeLinkDAO mergeLinkDAO) + { + fMergeLinkDAO = mergeLinkDAO; + } + + /** + * @param aVMStoreDAO The fAVMStoreDAO to set + */ + public void setAvmStoreDAO(AVMStoreDAO aVMStoreDAO) + { + fAVMStoreDAO = aVMStoreDAO; + } + + public void setNewAvmStoreDAO(org.alfresco.repo.domain.avm.AVMStoreDAO newAVMStoreDAO) + { + this.newAVMStoreDAO = newAVMStoreDAO; + } + + /** + * @param versionRootDAO the fVersionRootDAO to set + */ + public void setVersionRootDAO(VersionRootDAO versionRootDAO) + { + fVersionRootDAO = versionRootDAO; + } + + public void setNewAvmVersionRootDAO(org.alfresco.repo.domain.avm.AVMVersionRootDAO newAVMVersionRootDAO) + { + this.newAVMVersionRootDAO = newAVMVersionRootDAO; + } + + public void setAvmStorePropertyDAO(AVMStorePropertyDAO avmStorePropertyDAO) + { + fAVMStorePropertyDAO = avmStorePropertyDAO; + } + + public void setVersionLayeredNodeEntryDAO(VersionLayeredNodeEntryDAO dao) + { + fVersionLayeredNodeEntryDAO = dao; + } + + public void setAclDAO(AclDAO dao) + { + fAclDAO = dao; + } +} diff --git a/source/java/org/alfresco/repo/avm/AVMExpiredContentProcessor.java b/source/java/org/alfresco/repo/avm/AVMExpiredContentProcessor.java index 3625604d37..77edbb402c 100644 --- a/source/java/org/alfresco/repo/avm/AVMExpiredContentProcessor.java +++ b/source/java/org/alfresco/repo/avm/AVMExpiredContentProcessor.java @@ -30,7 +30,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.alfresco.config.JNDIConstants; -import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.mbeans.VirtServerRegistry; import org.alfresco.model.ContentModel; import org.alfresco.model.WCMAppModel; @@ -38,11 +37,9 @@ import org.alfresco.repo.domain.PropertyValue; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.workflow.WorkflowModel; -import org.alfresco.wcm.sandbox.SandboxConstants; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.AVMStoreDescriptor; -import org.alfresco.service.cmr.avm.locking.AVMLock; import org.alfresco.service.cmr.avm.locking.AVMLockingService; import org.alfresco.service.cmr.avmsync.AVMSyncService; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; @@ -61,9 +58,11 @@ import org.alfresco.service.cmr.workflow.WorkflowTaskState; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.Pair; +import org.alfresco.wcm.sandbox.SandboxConstants; import org.alfresco.wcm.sandbox.SandboxFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.I18NUtil; /** * Bean that is responsible for locating expired content and routing @@ -335,12 +334,12 @@ public class AVMExpiredContentProcessor // before doing anything else see whether the item is locked by any user, // if it is then just log a warning messge and wait until the next time around String[] splitPath = nodePath.split(":"); - AVMLock lock = this.avmLockingService.getLock(storeName, splitPath[1]); + String lockOwner = this.avmLockingService.getLockOwner(storeName, splitPath[1]); if (logger.isDebugEnabled()) - logger.debug("lock details for '" + nodePath + "': " + lock); + logger.debug("lock details for '" + nodePath + "': " + lockOwner); - if (lock == null) + if (lockOwner == null) { // get the map of expired content for the store Map> storeExpiredContent = this.expiredContent.get(storeName); diff --git a/source/java/org/alfresco/repo/avm/AVMInterpreter.java b/source/java/org/alfresco/repo/avm/AVMInterpreter.java index e80392e9c5..35d465af07 100644 --- a/source/java/org/alfresco/repo/avm/AVMInterpreter.java +++ b/source/java/org/alfresco/repo/avm/AVMInterpreter.java @@ -1,975 +1,970 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.avm; - -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Pattern; - -import org.alfresco.repo.avm.util.BulkLoader; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.cmr.avm.AVMNotFoundException; -import org.alfresco.service.cmr.avm.AVMService; -import org.alfresco.service.cmr.avm.AVMStoreDescriptor; -import org.alfresco.service.cmr.avm.VersionDescriptor; -import org.alfresco.service.cmr.avm.locking.AVMLock; -import org.alfresco.service.cmr.avm.locking.AVMLockingService; -import org.alfresco.service.cmr.avmsync.AVMDifference; -import org.alfresco.service.cmr.avmsync.AVMSyncService; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.namespace.QName; -import org.alfresco.wcm.util.WCMUtil; -import org.springframework.context.support.FileSystemXmlApplicationContext; -import org.springframework.extensions.surf.util.ISO8601DateFormat; - -/** - * An interactive console for the AVM repository. - * - * @author britt - * @author Gavin Cornwell - * @author janv - */ -public class AVMInterpreter -{ - private static final Pattern collectionPattern = Pattern.compile("^\\[(.*)\\]$"); - private static final Pattern nodeRefPattern = Pattern.compile("^\\w+://\\w+\\w+$"); - private static final Pattern integerPattern = Pattern.compile("^\\d+$"); - private static final Pattern dateTimePattern = Pattern.compile("^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$"); - - /** - * The service interface. - */ - private AVMService fService; - - /** - * The sync service. - */ - private AVMSyncService fSyncService; - - /** - * The locking service. - */ - private AVMLockingService fLockingService; - - /** - * The permission service. - */ - private PermissionService fPermissionService; - - /** - * The reader for interaction. - */ - private BufferedReader fIn; - - /** - * The Bulk Loader. - */ - private BulkLoader fLoader; - - /** - * Main entry point. - * Syntax: AVMInteractiveConsole storage (new|old). - */ - public static void main(String[] args) - { - FileSystemXmlApplicationContext context = - new FileSystemXmlApplicationContext("config/alfresco/application-context.xml"); - AVMInterpreter console = new AVMInterpreter(); - console.setAvmService((AVMService)context.getBean("AVMService")); - console.setAvmSyncService((AVMSyncService)context.getBean("AVMSyncService")); - console.setAvmLockingService((AVMLockingService)context.getBean("AVMLockingService")); - console.setPermissionService((PermissionService)context.getBean("PermissionService")); - BulkLoader loader = new BulkLoader(); - loader.setAvmService((AVMService)context.getBean("AVMService")); - console.setBulkLoader(loader); - console.rep(); - context.close(); - } - - /** - * Make up a new console. - */ - public AVMInterpreter() - { - fIn = new BufferedReader(new InputStreamReader(System.in)); - } - - /** - * Set the AVMService. - * @param service The AVMService instance. - */ - public void setAvmService(AVMService service) - { - fService = service; - } - - /** - * Set the AVM sync service. - * @param syncService - */ - public void setAvmSyncService(AVMSyncService syncService) - { - fSyncService = syncService; - } - - /** - * Set the AVM locking service. - * @param lockService - */ - public void setAvmLockingService(AVMLockingService lockService) - { - fLockingService = lockService; - } - - /** - * Set the PermissionService. - * @param service The PermissionService instance. - */ - public void setPermissionService(PermissionService service) - { - fPermissionService = service; - } - - /** - * Set the bulk loader. - * @param loader - */ - public void setBulkLoader(BulkLoader loader) - { - fLoader = loader; - } - - /** - * A Read-Eval-Print loop. - */ - public void rep() - { - while (true) - { - System.out.print("> "); - try - { - String line = fIn.readLine(); - if (line.equals("exit")) - { - return; - } - System.out.println(interpretCommand(line, fIn)); - } - catch (IOException ie) - { - ie.printStackTrace(System.err); - System.exit(2); - } - } - } - - /** - * Interpret a single command using the BufferedReader passed in for any data needed. - * @param line The unparsed command - * @param in A Reader to be used for commands that need input data. - * @return The textual output of the command. - */ - public String interpretCommand(String line, BufferedReader in) - { - String[] command = line.split(",\\s+"); - if (command.length == 0) - { - command = new String[1]; - command[0] = line; - } - try - { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - PrintStream out = new PrintStream(bout); - if (command[0].equals("ls")) - { - if (command.length < 2) - { - return "Syntax Error."; - } - int version = (command.length == 2) ? -1 : Integer.parseInt(command[2]); - AVMNodeDescriptor desc = fService.lookup(version, command[1]); - if (desc == null) - { - return "Not Found."; - } - Map listing = - fService.getDirectoryListing(desc, true); - for (String name : listing.keySet()) - { - out.println(name + " " + listing.get(name)); - } - } - else if (command[0].equals("lsr")) - { - if (command.length < 2) - { - return "Syntax Error."; - } - int version = (command.length == 2) ? -1 : Integer.parseInt(command[2]); - AVMNodeDescriptor desc = fService.lookup(version, command[1]); - recursiveList(out, desc, 0); - } - else if (command[0].equals("lsrep")) - { - List repos = fService.getStores(); - for (AVMStoreDescriptor repo : repos) - { - out.println(repo); - } - } - else if (command[0].equals("lsver")) - { - if ((command.length < 2) || (command.length > 4)) - { - return "Syntax Error."; - } - - List listing = null; - String storeName = command[1]; - if (command.length == 2) - { - listing = fService.getStoreVersions(storeName); - } - else - { - Date fromDate = ISO8601DateFormat.parse(command[2]); - Date toDate = new Date(); - if (command.length == 4) - { - toDate = ISO8601DateFormat.parse(command[3]); - } - listing = fService.getStoreVersions(storeName, fromDate, toDate); - } - - for (VersionDescriptor desc : listing) - { - out.println(desc); - } - } - else if (command[0].equals("mkrep")) - { - if (command.length != 2) - { - return "Syntax Error."; - } - fService.createStore(command[1]); - } - else if (command[0].equals("load")) - { - if (command.length != 3) - { - return "Syntax Error."; - } - fLoader.recursiveLoad(command[1], command[2]); - } - else if (command[0].equals("mkdir")) - { - if (command.length != 3) - { - return "Syntax Error."; - } - fService.createDirectory(command[1], command[2]); - } - else if (command[0].equals("mkbr")) - { - if (command.length != 5) - { - return "Syntax Error."; - } - fService.createBranch(Integer.parseInt(command[4]), command[1], command[2], command[3]); - } - else if (command[0].equals("mkldir")) - { - if (command.length != 4) - { - return "Syntax Error."; - } - fService.createLayeredDirectory(command[1], command[2], command[3]); - } - else if (command[0].equals("setopacity")) - { - if (command.length != 3) - { - return "Syntax Error."; - } - boolean isOpaque = new Boolean(command[2]); - fService.setOpacity(command[1], isOpaque); - } - else if (command[0].equals("rename")) - { - if (command.length != 5) - { - return "Syntax Error."; - } - fService.rename(command[1], command[2], command[3], command[4]); - } - else if (command[0].equals("cp")) - { - if (command.length != 5) - { - return "Syntax Error."; - } - InputStream fin = fService.getFileInputStream(Integer.parseInt(command[2]), command[1]); - OutputStream fout = fService.createFile(command[3], command[4]); - byte [] buff = new byte[8192]; - int read; - while ((read = fin.read(buff)) != -1) - { - fout.write(buff, 0, read); - } - fin.close(); - fout.close(); - } - else if (command[0].equals("retarget")) - { - if (command.length != 3) - { - return "Syntax Error."; - } - fService.retargetLayeredDirectory(command[1], command[2]); - } - else if (command[0].equals("mkprimary")) - { - if (command.length != 2) - { - return "Syntax Error."; - } - fService.makePrimary(command[1]); - } - else if (command[0].equals("mklfile")) - { - if (command.length != 4) - { - return "Syntax Error."; - } - fService.createLayeredFile(command[1], command[2], command[3]); - } - else if (command[0].equals("snap")) - { - if ((command.length < 2) || (command.length > 4)) - { - return "Syntax Error."; - } - - String tag = (command.length > 2) ? command[2] : null; - String description = (command.length > 3) ? command[3] : null; - - fService.createSnapshot(command[1], tag, description); - } - else if (command[0].equals("cat")) - { - if (command.length < 2) - { - return "Syntax Error."; - } - int version = (command.length == 2) ? -1 : Integer.parseInt(command[2]); - BufferedReader reader = - new BufferedReader( - new InputStreamReader(fService.getFileInputStream(version, command[1]))); - String l; - while ((l = reader.readLine()) != null) - { - out.println(l); - } - reader.close(); - } - else if (command[0].equals("rm")) - { - if (command.length != 3) - { - return "Syntax Error."; - } - fService.removeNode(command[1], command[2]); - } - else if (command[0].equals("rmrep")) - { - if (command.length != 2) - { - return "Syntax Error."; - } - fService.purgeStore(command[1]); - } - else if (command[0].equals("rmver")) - { - if (command.length != 3) - { - return "Syntax Error."; - } - - String storeName = command[1]; - int ver =Integer.parseInt(command[2]); - String wpStoreId = WCMUtil.getWebProject(fService, storeName); - if ((wpStoreId != null) && (ver <= 2)) - { - return "WCM store - cannot delete versions 0-2"; - } - fService.purgeVersion(ver, storeName); - } - else if (command[0].equals("rmvers")) - { - if (command.length != 4) - { - return "Syntax Error."; - } - String storeName = command[1]; - String wpStoreId = WCMUtil.getWebProject(fService, storeName); - - Date fromDate = ISO8601DateFormat.parse(command[2]); - Date toDate = ISO8601DateFormat.parse(command[3]); - - List listing = fService.getStoreVersions(storeName, fromDate, toDate); - for (VersionDescriptor desc : listing) - { - int ver = desc.getVersionID(); - if ((wpStoreId != null) && (ver <= 2)) - { - return "WCM store - cannot delete versions 0-2"; - } - fService.purgeVersion(ver, storeName); - } - } - else if (command[0].equals("write")) - { - if (command.length != 2) - { - return "Syntax Error."; - } - PrintStream ps = - new PrintStream(fService.getFileOutputStream(command[1])); - String l; - while (!(l = in.readLine()).equals("")) - { - ps.println(l); - } - ps.close(); - } - else if (command[0].equals("create")) - { - if (command.length != 3) - { - return "Syntax Error."; - } - PrintStream ps = - new PrintStream(fService.createFile(command[1], command[2])); - String l; - while (!(l = in.readLine()).equals("")) - { - ps.println(l); - } - ps.close(); - } - else if (command[0].equals("stat")) - { - if (command.length < 2) - { - return "Syntax Error."; - } - int version = (command.length == 2) ? -1 : Integer.parseInt(command[2]); - AVMNodeDescriptor desc = fService.lookup(version, command[1]); - out.println(desc); - out.println("Version: " + desc.getVersionID()); - out.println("Owner: " + desc.getOwner()); - out.println("Mod Time: " + new Date(desc.getModDate())); - } - else if (command[0].equals("getnodeproperties")) - { - if (command.length < 2) - { - return "Syntax Error."; - } - int version = (command.length == 2) ? -1 : Integer.parseInt(command[2]); - final Map properties = fService.getNodeProperties(version, command[1]); - for (final Map.Entry p : properties.entrySet()) - { - out.println(p.getKey() + ": " + p.getValue()); - } - } - else if (command[0].equals("setnodepermission")) - { - if (command.length != 4) - { - return "Syntax Error."; - } - - fPermissionService.setPermission( - AVMNodeConverter.ToNodeRef(-1, command[1]), command[2], command[3], true); - } - else if (command[0].equals("clearnodepermission")) - { - if (command.length != 3) - { - return "Syntax Error."; - } - - fPermissionService.clearPermission( - AVMNodeConverter.ToNodeRef(-1, command[1]), command[2]); - } - else if (command[0].equals("descnode")) - { - if (command.length < 2) - { - return "Syntax Error."; - } - - String path = command[1]; - int version = (command.length == 2) ? -1 : Integer.parseInt(command[2]); - AVMNodeDescriptor nodeDesc = fService.lookup(version, path); - if (nodeDesc == null) - { - return "Path Not Found."; - } - - out.println(nodeDesc.toString()); - out.println("isDirectory: " + nodeDesc.isDirectory()); - out.println("isFile: " + nodeDesc.isFile()); - out.println("isPrimary: " + nodeDesc.isPrimary()); - out.println("isOpaque: " + nodeDesc.getOpacity()); - out.println("creator: " + nodeDesc.getCreator()); - out.println("owner: " + nodeDesc.getOwner()); - out.println("lastModifier: " + nodeDesc.getLastModifier()); - out.println("created: " + new Date(nodeDesc.getCreateDate())); - out.println("modified: " + new Date(nodeDesc.getModDate())); - out.println("lastAccess: " + new Date(nodeDesc.getAccessDate())); - - // get lock information - String lockPath = path.substring(path.indexOf("/")); - String store = path.substring(0, path.indexOf(":")); - String mainStore = store; - if (store.indexOf("--") != -1) - { - mainStore = store.substring(0, store.indexOf("--")); - } - - try - { - AVMLock lock = fLockingService.getLock(mainStore, lockPath); - out.print("lock: "); - if (lock != null) - { - out.print("store = "); - out.print(lock.getStore()); - out.print(", owners = "); - out.println(lock.getOwners()); - } - else - { - out.println("No locks found"); - } - } - catch (AVMNotFoundException avmerr) - { - out.println("No locks found"); - } - } - else if (command[0].equals("deletenodeproperty")) - { - if (command.length != 3) - { - return "Syntax Error."; - } - - fService.deleteNodeProperty(command[1], QName.createQName(command[2])); - out.println("deleted property " + command[2] + " of " + command[1]); - } - else if (command[0].equals("history")) - { - if (command.length != 4) - { - return "Syntax Error."; - } - AVMNodeDescriptor desc = fService.lookup(Integer.parseInt(command[2]), command[1]); - List history = fService.getHistory(desc, Integer.parseInt(command[3])); - for (AVMNodeDescriptor node : history) - { - out.println(node); - out.println("Version: " + node.getVersionID()); - out.println("Owner: " + node.getOwner()); - out.println("Mod Time: " + new Date(node.getModDate())); - } - } - /* - else if (command[0].equals("catver")) - { - if (command.length != 4) - { - return "Syntax Error."; - } - AVMNodeDescriptor desc = fService.lookup(Integer.parseInt(command[2]), command[1]); - List history = fService.getHistory(desc, Integer.parseInt(command[3])); - if (history.size() == 0) - { - return "No History."; - } - BufferedReader reader = - new BufferedReader( - new InputStreamReader( - fService.getFileInputStream(history.get(history.size() - 1)))); - String l; - while ((l = reader.readLine()) != null) - { - out.println(l); - } - reader.close(); - } - */ - else if (command[0].equals("ca")) - { - if (command.length != 5) - { - return "Syntax Error."; - } - AVMNodeDescriptor left = fService.lookup(Integer.parseInt(command[2]), command[1]); - AVMNodeDescriptor right = fService.lookup(Integer.parseInt(command[4]), command[3]); - AVMNodeDescriptor ca = fService.getCommonAncestor(left, right); - out.println(ca); - } - else if (command[0].equals("statstore")) - { - if (command.length != 2) - { - return "Syntax Error."; - } - AVMStoreDescriptor desc = fService.getStore(command[1]); - if (desc == null) - { - return "Not Found."; - } - out.println(desc); - Map props = - fService.getStoreProperties(command[1]); - for (QName name : props.keySet()) - { - out.println(name + ": " + props.get(name)); - } - } - else if (command[0].equals("compare")) - { - if (command.length != 5) - { - return "Syntax Error."; - } - List diffs = fSyncService.compare(Integer.parseInt(command[2]), - command[1], - Integer.parseInt(command[4]), - command[3], - null); - for (AVMDifference diff : diffs) - { - out.println(diff); - } - } - else if (command[0].equals("update")) - { - if (command.length != 4) - { - return "Syntax Error."; - } - AVMDifference diff = new AVMDifference(Integer.parseInt(command[2]), command[1], - -1, command[3], AVMDifference.NEWER); - List diffs = new ArrayList(); - diffs.add(diff); - fSyncService.update(diffs, null, false, false, false, false, null, null); - } - else if (command[0].equals("resetLayer")) - { - if (command.length != 2) - { - return "Syntax Error."; - } - fSyncService.resetLayer(command[1]); - } - else if (command[0].equals("flatten")) - { - if (command.length != 3) - { - return "Syntax Error."; - } - fSyncService.flatten(command[1], command[2]); - } - else if (command[0].equals("getnodeaspects")) - { - if (command.length != 3) - { - return "Syntax Error."; - } - - final Set aspects = fService.getAspects(Integer.parseInt(command[2]), command[1]); - for (final QName qn : aspects) - { - out.println(qn.toString()); - } - } - else if (command[0].equals("addnodeaspect")) - { - if (command.length != 3) - { - return "Syntax Error."; - } - - fService.addAspect(command[1], QName.createQName(command[2])); - } - else if (command[0].equals("deletenodeaspect")) - { - if (command.length != 3) - { - return "Syntax Error."; - } - - fService.removeAspect(command[1], QName.createQName(command[2])); - } - else if (command[0].equals("setnodeproperty")) - { - if (command.length < 4) - { - return "Syntax Error."; - } - - QName valueQName = QName.createQName(command[2]); - - String propertyValue = ""; - - // If multiple values are specified then concatenate the values - if (command.length > 4) - { - StringBuffer sb = new StringBuffer(); - for (int i=3; i 4) - { - StringBuffer sb = new StringBuffer(); - for (int i=3; i listing = fService.getDirectoryListing(dir, true); - for (String name : listing.keySet()) - { - AVMNodeDescriptor child = listing.get(name); - for (int i = 0; i < indent; i++) - { - out.print(' '); - } - out.println(name + " " + child); - if (child.isDirectory()) - { - recursiveList(out, child, indent + 2); - } - } - } - - private static Serializable convertValueFromSring(String sValue) - { - Serializable retValue = ""; - - CharSequence seq = sValue.subSequence(0, sValue.length()); - - if (collectionPattern.matcher(seq).matches()) - { - String[] elements = getCSVArray(sValue.substring(1, sValue.length()-1)); - - // Should this be an ArrayList or a HashSet? - Collection propValues = new HashSet(elements.length); - for (int i=0; i. + */ + +package org.alfresco.repo.avm; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +import org.alfresco.repo.avm.util.BulkLoader; +import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.cmr.avm.AVMNotFoundException; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avm.AVMStoreDescriptor; +import org.alfresco.service.cmr.avm.VersionDescriptor; +import org.alfresco.service.cmr.avm.locking.AVMLockingService; +import org.alfresco.service.cmr.avmsync.AVMDifference; +import org.alfresco.service.cmr.avmsync.AVMSyncService; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.QName; +import org.alfresco.wcm.util.WCMUtil; +import org.springframework.context.support.FileSystemXmlApplicationContext; +import org.springframework.extensions.surf.util.ISO8601DateFormat; + +/** + * An interactive console for the AVM repository. + * + * @author britt + * @author Gavin Cornwell + * @author janv + */ +public class AVMInterpreter +{ + private static final Pattern collectionPattern = Pattern.compile("^\\[(.*)\\]$"); + private static final Pattern nodeRefPattern = Pattern.compile("^\\w+://\\w+\\w+$"); + private static final Pattern integerPattern = Pattern.compile("^\\d+$"); + private static final Pattern dateTimePattern = Pattern.compile("^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$"); + + /** + * The service interface. + */ + private AVMService fService; + + /** + * The sync service. + */ + private AVMSyncService fSyncService; + + /** + * The locking service. + */ + private AVMLockingService fLockingService; + + /** + * The permission service. + */ + private PermissionService fPermissionService; + + /** + * The reader for interaction. + */ + private BufferedReader fIn; + + /** + * The Bulk Loader. + */ + private BulkLoader fLoader; + + /** + * Main entry point. + * Syntax: AVMInteractiveConsole storage (new|old). + */ + public static void main(String[] args) + { + FileSystemXmlApplicationContext context = + new FileSystemXmlApplicationContext("config/alfresco/application-context.xml"); + AVMInterpreter console = new AVMInterpreter(); + console.setAvmService((AVMService)context.getBean("AVMService")); + console.setAvmSyncService((AVMSyncService)context.getBean("AVMSyncService")); + console.setAvmLockingService((AVMLockingService)context.getBean("AVMLockingService")); + console.setPermissionService((PermissionService)context.getBean("PermissionService")); + BulkLoader loader = new BulkLoader(); + loader.setAvmService((AVMService)context.getBean("AVMService")); + console.setBulkLoader(loader); + console.rep(); + context.close(); + } + + /** + * Make up a new console. + */ + public AVMInterpreter() + { + fIn = new BufferedReader(new InputStreamReader(System.in)); + } + + /** + * Set the AVMService. + * @param service The AVMService instance. + */ + public void setAvmService(AVMService service) + { + fService = service; + } + + /** + * Set the AVM sync service. + * @param syncService + */ + public void setAvmSyncService(AVMSyncService syncService) + { + fSyncService = syncService; + } + + /** + * Set the AVM locking service. + * @param lockService + */ + public void setAvmLockingService(AVMLockingService lockService) + { + fLockingService = lockService; + } + + /** + * Set the PermissionService. + * @param service The PermissionService instance. + */ + public void setPermissionService(PermissionService service) + { + fPermissionService = service; + } + + /** + * Set the bulk loader. + * @param loader + */ + public void setBulkLoader(BulkLoader loader) + { + fLoader = loader; + } + + /** + * A Read-Eval-Print loop. + */ + public void rep() + { + while (true) + { + System.out.print("> "); + try + { + String line = fIn.readLine(); + if (line.equals("exit")) + { + return; + } + System.out.println(interpretCommand(line, fIn)); + } + catch (IOException ie) + { + ie.printStackTrace(System.err); + System.exit(2); + } + } + } + + /** + * Interpret a single command using the BufferedReader passed in for any data needed. + * @param line The unparsed command + * @param in A Reader to be used for commands that need input data. + * @return The textual output of the command. + */ + public String interpretCommand(String line, BufferedReader in) + { + String[] command = line.split(",\\s+"); + if (command.length == 0) + { + command = new String[1]; + command[0] = line; + } + try + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + PrintStream out = new PrintStream(bout); + if (command[0].equals("ls")) + { + if (command.length < 2) + { + return "Syntax Error."; + } + int version = (command.length == 2) ? -1 : Integer.parseInt(command[2]); + AVMNodeDescriptor desc = fService.lookup(version, command[1]); + if (desc == null) + { + return "Not Found."; + } + Map listing = + fService.getDirectoryListing(desc, true); + for (String name : listing.keySet()) + { + out.println(name + " " + listing.get(name)); + } + } + else if (command[0].equals("lsr")) + { + if (command.length < 2) + { + return "Syntax Error."; + } + int version = (command.length == 2) ? -1 : Integer.parseInt(command[2]); + AVMNodeDescriptor desc = fService.lookup(version, command[1]); + recursiveList(out, desc, 0); + } + else if (command[0].equals("lsrep")) + { + List repos = fService.getStores(); + for (AVMStoreDescriptor repo : repos) + { + out.println(repo); + } + } + else if (command[0].equals("lsver")) + { + if ((command.length < 2) || (command.length > 4)) + { + return "Syntax Error."; + } + + List listing = null; + String storeName = command[1]; + if (command.length == 2) + { + listing = fService.getStoreVersions(storeName); + } + else + { + Date fromDate = ISO8601DateFormat.parse(command[2]); + Date toDate = new Date(); + if (command.length == 4) + { + toDate = ISO8601DateFormat.parse(command[3]); + } + listing = fService.getStoreVersions(storeName, fromDate, toDate); + } + + for (VersionDescriptor desc : listing) + { + out.println(desc); + } + } + else if (command[0].equals("mkrep")) + { + if (command.length != 2) + { + return "Syntax Error."; + } + fService.createStore(command[1]); + } + else if (command[0].equals("load")) + { + if (command.length != 3) + { + return "Syntax Error."; + } + fLoader.recursiveLoad(command[1], command[2]); + } + else if (command[0].equals("mkdir")) + { + if (command.length != 3) + { + return "Syntax Error."; + } + fService.createDirectory(command[1], command[2]); + } + else if (command[0].equals("mkbr")) + { + if (command.length != 5) + { + return "Syntax Error."; + } + fService.createBranch(Integer.parseInt(command[4]), command[1], command[2], command[3]); + } + else if (command[0].equals("mkldir")) + { + if (command.length != 4) + { + return "Syntax Error."; + } + fService.createLayeredDirectory(command[1], command[2], command[3]); + } + else if (command[0].equals("setopacity")) + { + if (command.length != 3) + { + return "Syntax Error."; + } + boolean isOpaque = new Boolean(command[2]); + fService.setOpacity(command[1], isOpaque); + } + else if (command[0].equals("rename")) + { + if (command.length != 5) + { + return "Syntax Error."; + } + fService.rename(command[1], command[2], command[3], command[4]); + } + else if (command[0].equals("cp")) + { + if (command.length != 5) + { + return "Syntax Error."; + } + InputStream fin = fService.getFileInputStream(Integer.parseInt(command[2]), command[1]); + OutputStream fout = fService.createFile(command[3], command[4]); + byte [] buff = new byte[8192]; + int read; + while ((read = fin.read(buff)) != -1) + { + fout.write(buff, 0, read); + } + fin.close(); + fout.close(); + } + else if (command[0].equals("retarget")) + { + if (command.length != 3) + { + return "Syntax Error."; + } + fService.retargetLayeredDirectory(command[1], command[2]); + } + else if (command[0].equals("mkprimary")) + { + if (command.length != 2) + { + return "Syntax Error."; + } + fService.makePrimary(command[1]); + } + else if (command[0].equals("mklfile")) + { + if (command.length != 4) + { + return "Syntax Error."; + } + fService.createLayeredFile(command[1], command[2], command[3]); + } + else if (command[0].equals("snap")) + { + if ((command.length < 2) || (command.length > 4)) + { + return "Syntax Error."; + } + + String tag = (command.length > 2) ? command[2] : null; + String description = (command.length > 3) ? command[3] : null; + + fService.createSnapshot(command[1], tag, description); + } + else if (command[0].equals("cat")) + { + if (command.length < 2) + { + return "Syntax Error."; + } + int version = (command.length == 2) ? -1 : Integer.parseInt(command[2]); + BufferedReader reader = + new BufferedReader( + new InputStreamReader(fService.getFileInputStream(version, command[1]))); + String l; + while ((l = reader.readLine()) != null) + { + out.println(l); + } + reader.close(); + } + else if (command[0].equals("rm")) + { + if (command.length != 3) + { + return "Syntax Error."; + } + fService.removeNode(command[1], command[2]); + } + else if (command[0].equals("rmrep")) + { + if (command.length != 2) + { + return "Syntax Error."; + } + fService.purgeStore(command[1]); + } + else if (command[0].equals("rmver")) + { + if (command.length != 3) + { + return "Syntax Error."; + } + + String storeName = command[1]; + int ver =Integer.parseInt(command[2]); + String wpStoreId = WCMUtil.getWebProject(fService, storeName); + if ((wpStoreId != null) && (ver <= 2)) + { + return "WCM store - cannot delete versions 0-2"; + } + fService.purgeVersion(ver, storeName); + } + else if (command[0].equals("rmvers")) + { + if (command.length != 4) + { + return "Syntax Error."; + } + String storeName = command[1]; + String wpStoreId = WCMUtil.getWebProject(fService, storeName); + + Date fromDate = ISO8601DateFormat.parse(command[2]); + Date toDate = ISO8601DateFormat.parse(command[3]); + + List listing = fService.getStoreVersions(storeName, fromDate, toDate); + for (VersionDescriptor desc : listing) + { + int ver = desc.getVersionID(); + if ((wpStoreId != null) && (ver <= 2)) + { + return "WCM store - cannot delete versions 0-2"; + } + fService.purgeVersion(ver, storeName); + } + } + else if (command[0].equals("write")) + { + if (command.length != 2) + { + return "Syntax Error."; + } + PrintStream ps = + new PrintStream(fService.getFileOutputStream(command[1])); + String l; + while (!(l = in.readLine()).equals("")) + { + ps.println(l); + } + ps.close(); + } + else if (command[0].equals("create")) + { + if (command.length != 3) + { + return "Syntax Error."; + } + PrintStream ps = + new PrintStream(fService.createFile(command[1], command[2])); + String l; + while (!(l = in.readLine()).equals("")) + { + ps.println(l); + } + ps.close(); + } + else if (command[0].equals("stat")) + { + if (command.length < 2) + { + return "Syntax Error."; + } + int version = (command.length == 2) ? -1 : Integer.parseInt(command[2]); + AVMNodeDescriptor desc = fService.lookup(version, command[1]); + out.println(desc); + out.println("Version: " + desc.getVersionID()); + out.println("Owner: " + desc.getOwner()); + out.println("Mod Time: " + new Date(desc.getModDate())); + } + else if (command[0].equals("getnodeproperties")) + { + if (command.length < 2) + { + return "Syntax Error."; + } + int version = (command.length == 2) ? -1 : Integer.parseInt(command[2]); + final Map properties = fService.getNodeProperties(version, command[1]); + for (final Map.Entry p : properties.entrySet()) + { + out.println(p.getKey() + ": " + p.getValue()); + } + } + else if (command[0].equals("setnodepermission")) + { + if (command.length != 4) + { + return "Syntax Error."; + } + + fPermissionService.setPermission( + AVMNodeConverter.ToNodeRef(-1, command[1]), command[2], command[3], true); + } + else if (command[0].equals("clearnodepermission")) + { + if (command.length != 3) + { + return "Syntax Error."; + } + + fPermissionService.clearPermission( + AVMNodeConverter.ToNodeRef(-1, command[1]), command[2]); + } + else if (command[0].equals("descnode")) + { + if (command.length < 2) + { + return "Syntax Error."; + } + + String path = command[1]; + int version = (command.length == 2) ? -1 : Integer.parseInt(command[2]); + AVMNodeDescriptor nodeDesc = fService.lookup(version, path); + if (nodeDesc == null) + { + return "Path Not Found."; + } + + out.println(nodeDesc.toString()); + out.println("isDirectory: " + nodeDesc.isDirectory()); + out.println("isFile: " + nodeDesc.isFile()); + out.println("isPrimary: " + nodeDesc.isPrimary()); + out.println("isOpaque: " + nodeDesc.getOpacity()); + out.println("creator: " + nodeDesc.getCreator()); + out.println("owner: " + nodeDesc.getOwner()); + out.println("lastModifier: " + nodeDesc.getLastModifier()); + out.println("created: " + new Date(nodeDesc.getCreateDate())); + out.println("modified: " + new Date(nodeDesc.getModDate())); + out.println("lastAccess: " + new Date(nodeDesc.getAccessDate())); + + // get lock information + String lockPath = path.substring(path.indexOf("/")); + String store = path.substring(0, path.indexOf(":")); + String mainStore = store; + if (store.indexOf("--") != -1) + { + mainStore = store.substring(0, store.indexOf("--")); + } + + try + { + String lockOwner = fLockingService.getLockOwner(mainStore, lockPath); + if (lockOwner != null) + { + out.println("lock: " + lockOwner); + } + else + { + out.println("No locks found"); + } + } + catch (AVMNotFoundException avmerr) + { + out.println("No locks found"); + } + } + else if (command[0].equals("deletenodeproperty")) + { + if (command.length != 3) + { + return "Syntax Error."; + } + + fService.deleteNodeProperty(command[1], QName.createQName(command[2])); + out.println("deleted property " + command[2] + " of " + command[1]); + } + else if (command[0].equals("history")) + { + if (command.length != 4) + { + return "Syntax Error."; + } + AVMNodeDescriptor desc = fService.lookup(Integer.parseInt(command[2]), command[1]); + List history = fService.getHistory(desc, Integer.parseInt(command[3])); + for (AVMNodeDescriptor node : history) + { + out.println(node); + out.println("Version: " + node.getVersionID()); + out.println("Owner: " + node.getOwner()); + out.println("Mod Time: " + new Date(node.getModDate())); + } + } + /* + else if (command[0].equals("catver")) + { + if (command.length != 4) + { + return "Syntax Error."; + } + AVMNodeDescriptor desc = fService.lookup(Integer.parseInt(command[2]), command[1]); + List history = fService.getHistory(desc, Integer.parseInt(command[3])); + if (history.size() == 0) + { + return "No History."; + } + BufferedReader reader = + new BufferedReader( + new InputStreamReader( + fService.getFileInputStream(history.get(history.size() - 1)))); + String l; + while ((l = reader.readLine()) != null) + { + out.println(l); + } + reader.close(); + } + */ + else if (command[0].equals("ca")) + { + if (command.length != 5) + { + return "Syntax Error."; + } + AVMNodeDescriptor left = fService.lookup(Integer.parseInt(command[2]), command[1]); + AVMNodeDescriptor right = fService.lookup(Integer.parseInt(command[4]), command[3]); + AVMNodeDescriptor ca = fService.getCommonAncestor(left, right); + out.println(ca); + } + else if (command[0].equals("statstore")) + { + if (command.length != 2) + { + return "Syntax Error."; + } + AVMStoreDescriptor desc = fService.getStore(command[1]); + if (desc == null) + { + return "Not Found."; + } + out.println(desc); + Map props = + fService.getStoreProperties(command[1]); + for (QName name : props.keySet()) + { + out.println(name + ": " + props.get(name)); + } + } + else if (command[0].equals("compare")) + { + if (command.length != 5) + { + return "Syntax Error."; + } + List diffs = fSyncService.compare(Integer.parseInt(command[2]), + command[1], + Integer.parseInt(command[4]), + command[3], + null); + for (AVMDifference diff : diffs) + { + out.println(diff); + } + } + else if (command[0].equals("update")) + { + if (command.length != 4) + { + return "Syntax Error."; + } + AVMDifference diff = new AVMDifference(Integer.parseInt(command[2]), command[1], + -1, command[3], AVMDifference.NEWER); + List diffs = new ArrayList(); + diffs.add(diff); + fSyncService.update(diffs, null, false, false, false, false, null, null); + } + else if (command[0].equals("resetLayer")) + { + if (command.length != 2) + { + return "Syntax Error."; + } + fSyncService.resetLayer(command[1]); + } + else if (command[0].equals("flatten")) + { + if (command.length != 3) + { + return "Syntax Error."; + } + fSyncService.flatten(command[1], command[2]); + } + else if (command[0].equals("getnodeaspects")) + { + if (command.length != 3) + { + return "Syntax Error."; + } + + final Set aspects = fService.getAspects(Integer.parseInt(command[2]), command[1]); + for (final QName qn : aspects) + { + out.println(qn.toString()); + } + } + else if (command[0].equals("addnodeaspect")) + { + if (command.length != 3) + { + return "Syntax Error."; + } + + fService.addAspect(command[1], QName.createQName(command[2])); + } + else if (command[0].equals("deletenodeaspect")) + { + if (command.length != 3) + { + return "Syntax Error."; + } + + fService.removeAspect(command[1], QName.createQName(command[2])); + } + else if (command[0].equals("setnodeproperty")) + { + if (command.length < 4) + { + return "Syntax Error."; + } + + QName valueQName = QName.createQName(command[2]); + + String propertyValue = ""; + + // If multiple values are specified then concatenate the values + if (command.length > 4) + { + StringBuffer sb = new StringBuffer(); + for (int i=3; i 4) + { + StringBuffer sb = new StringBuffer(); + for (int i=3; i listing = fService.getDirectoryListing(dir, true); + for (String name : listing.keySet()) + { + AVMNodeDescriptor child = listing.get(name); + for (int i = 0; i < indent; i++) + { + out.print(' '); + } + out.println(name + " " + child); + if (child.isDirectory()) + { + recursiveList(out, child, indent + 2); + } + } + } + + private static Serializable convertValueFromSring(String sValue) + { + Serializable retValue = ""; + + CharSequence seq = sValue.subSequence(0, sValue.length()); + + if (collectionPattern.matcher(seq).matches()) + { + String[] elements = getCSVArray(sValue.substring(1, sValue.length()-1)); + + // Should this be an ArrayList or a HashSet? + Collection propValues = new HashSet(elements.length); + for (int i=0; i. */ - package org.alfresco.repo.avm; import java.io.InputStream; import java.io.OutputStream; -import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; @@ -30,18 +29,18 @@ import java.util.SortedMap; import org.alfresco.repo.avm.util.AVMUtil; import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.AVMStoreDescriptor; import org.alfresco.service.cmr.avm.LayeringDescriptor; import org.alfresco.service.cmr.avm.VersionDescriptor; -import org.alfresco.service.cmr.avm.locking.AVMLock; import org.alfresco.service.cmr.avm.locking.AVMLockingException; import org.alfresco.service.cmr.avm.locking.AVMLockingService; +import org.alfresco.service.cmr.avm.locking.AVMLockingService.LockState; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; -import org.alfresco.service.cmr.security.AuthenticationService; import org.alfresco.service.namespace.QName; import org.alfresco.util.Pair; import org.alfresco.wcm.util.WCMUtil; @@ -61,17 +60,12 @@ public class AVMLockingAwareService implements AVMService, ApplicationContextAwa private AVMLockingService fLockingService; - private AuthenticationService fAuthenticationService; - private ApplicationContext fContext; public AVMLockingAwareService() { } - /* (non-Javadoc) - * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext) - */ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { fContext = applicationContext; @@ -81,577 +75,362 @@ public class AVMLockingAwareService implements AVMService, ApplicationContextAwa { fService = (AVMService)fContext.getBean("avmService"); fLockingService = (AVMLockingService)fContext.getBean("avmLockingService"); - fAuthenticationService = (AuthenticationService)fContext.getBean("authenticationService"); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#addAspect(java.lang.String, org.alfresco.service.namespace.QName) - */ public void addAspect(String path, QName aspectName) { grabLock(path); fService.addAspect(path, aspectName); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#copy(int, java.lang.String, java.lang.String, java.lang.String) - */ public void copy(int srcVersion, String srcPath, String dstPath, String name) { fService.copy(srcVersion, srcPath, dstPath, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#createBranch(int, java.lang.String, java.lang.String, java.lang.String) - */ public void createBranch(int version, String srcPath, String dstPath, String name) { fService.createBranch(version, srcPath, dstPath, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#createDirectory(java.lang.String, java.lang.String) - */ public void createDirectory(String path, String name) { fService.createDirectory(path, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#createFile(java.lang.String, java.lang.String) - */ public OutputStream createFile(String path, String name) { grabLock(AVMUtil.extendAVMPath(path, name)); return fService.createFile(path, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#createFile(java.lang.String, java.lang.String, java.io.InputStream) - */ public void createFile(String path, String name, InputStream in) { grabLock(AVMUtil.extendAVMPath(path, name)); fService.createFile(path, name, in); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#createLayeredDirectory(java.lang.String, java.lang.String, java.lang.String) - */ public void createLayeredDirectory(String targetPath, String parent, String name) { fService.createLayeredDirectory(targetPath, parent, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#createLayeredFile(java.lang.String, java.lang.String, java.lang.String) - */ public void createLayeredFile(String targetPath, String parent, String name) { grabLock(AVMUtil.extendAVMPath(parent, name)); fService.createLayeredFile(targetPath, parent, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#createSnapshot(java.lang.String, java.lang.String, java.lang.String) - */ public Map createSnapshot(String store, String tag, String description) { return fService.createSnapshot(store, tag, description); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#createStore(java.lang.String) - */ public void createStore(String name) { fService.createStore(name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#createStore(java.lang.String, java.util.Map) - */ public void createStore(String name, Map props) { fService.createStore(name, props); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#deleteNodeProperties(java.lang.String) - */ public void deleteNodeProperties(String path) { grabLock(path); fService.deleteNodeProperties(path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#deleteNodeProperty(java.lang.String, org.alfresco.service.namespace.QName) - */ public void deleteNodeProperty(String path, QName name) { grabLock(path); fService.deleteNodeProperty(path, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#deleteStoreProperty(java.lang.String, org.alfresco.service.namespace.QName) - */ public void deleteStoreProperty(String store, QName name) { fService.deleteStoreProperty(store, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#forceCopy(java.lang.String) - */ public AVMNodeDescriptor forceCopy(String path) { grabLock(path); return fService.forceCopy(path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getAPath(org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ public Pair getAPath(AVMNodeDescriptor desc) { return fService.getAPath(desc); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getPathsInStoreVersion(org.alfresco.service.cmr.avm.AVMNodeDescriptor, java.lang.String, int) - */ public List getPathsInStoreVersion(AVMNodeDescriptor desc, String store, int version) { return fService.getPathsInStoreVersion(desc, store, version); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getAspects(int, java.lang.String) - */ public Set getAspects(int version, String path) { return fService.getAspects(version, path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getAspects(org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ public Set getAspects(AVMNodeDescriptor desc) { return fService.getAspects(desc); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getCommonAncestor(org.alfresco.service.cmr.avm.AVMNodeDescriptor, org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ public AVMNodeDescriptor getCommonAncestor(AVMNodeDescriptor left, AVMNodeDescriptor right) { return fService.getCommonAncestor(left, right); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getContentDataForRead(int, java.lang.String) - */ public ContentData getContentDataForRead(int version, String path) { return fService.getContentDataForRead(version, path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getContentDataForRead(org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ public ContentData getContentDataForRead(AVMNodeDescriptor desc) { return fService.getContentDataForRead(desc); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getContentDataForWrite(java.lang.String) - */ public ContentData getContentDataForWrite(String path) { grabLock(path); return fService.getContentDataForWrite(path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getContentReader(int, java.lang.String) - */ public ContentReader getContentReader(int version, String path) { return fService.getContentReader(version, path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getContentWriter(java.lang.String, boolean) - */ - public ContentWriter getContentWriter(String path, boolean update) + public ContentWriter getContentWriter(String path, boolean update) { grabLock(path); - return fService.getContentWriter(path, update); + return fService.getContentWriter(path, update); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getDeleted(int, java.lang.String) - */ public List getDeleted(int version, String path) { return fService.getDeleted(version, path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getDirectoryListing(int, java.lang.String) - */ - public SortedMap getDirectoryListing( - int version, String path) + public SortedMap getDirectoryListing(int version, String path) { return fService.getDirectoryListing(version, path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getDirectoryListing(int, java.lang.String, boolean) - */ - public SortedMap getDirectoryListing( - int version, String path, boolean includeDeleted) + public SortedMap getDirectoryListing(int version, String path, boolean includeDeleted) { return fService.getDirectoryListing(version, path, includeDeleted); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getDirectoryListing(org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ - public SortedMap getDirectoryListing( - AVMNodeDescriptor dir) + public SortedMap getDirectoryListing(AVMNodeDescriptor dir) { return fService.getDirectoryListing(dir); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getDirectoryListing(org.alfresco.service.cmr.avm.AVMNodeDescriptor, String) - */ - public SortedMap getDirectoryListing( - AVMNodeDescriptor dir, String childNamePattern) + public SortedMap getDirectoryListing(AVMNodeDescriptor dir, String childNamePattern) { return fService.getDirectoryListing(dir, childNamePattern); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getDirectoryListing(org.alfresco.service.cmr.avm.AVMNodeDescriptor, boolean) - */ - public SortedMap getDirectoryListing( - AVMNodeDescriptor dir, boolean includeDeleted) + public SortedMap getDirectoryListing(AVMNodeDescriptor dir, boolean includeDeleted) { return fService.getDirectoryListing(dir, includeDeleted); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getDirectoryListingArray(int, java.lang.String, boolean) - */ - public AVMNodeDescriptor[] getDirectoryListingArray(int version, - String path, boolean includeDeleted) + public AVMNodeDescriptor[] getDirectoryListingArray(int version, String path, boolean includeDeleted) { return fService.getDirectoryListingArray(version, path, includeDeleted); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getDirectoryListingArray(org.alfresco.service.cmr.avm.AVMNodeDescriptor, boolean) - */ - public AVMNodeDescriptor[] getDirectoryListingArray(AVMNodeDescriptor dir, - boolean includeDeleted) + public AVMNodeDescriptor[] getDirectoryListingArray(AVMNodeDescriptor dir, boolean includeDeleted) { return fService.getDirectoryListingArray(dir, includeDeleted); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getDirectoryListingDirect(int, java.lang.String) - */ - public SortedMap getDirectoryListingDirect( - int version, String path) + public SortedMap getDirectoryListingDirect(int version, String path) { return fService.getDirectoryListingDirect(version, path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getDirectoryListingDirect(int, java.lang.String, boolean) - */ - public SortedMap getDirectoryListingDirect( - int version, String path, boolean includeDeleted) + public SortedMap getDirectoryListingDirect(int version, String path, boolean includeDeleted) { return fService.getDirectoryListingDirect(version, path, includeDeleted); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getDirectoryListingDirect(org.alfresco.service.cmr.avm.AVMNodeDescriptor, boolean) - */ public SortedMap getDirectoryListingDirect( AVMNodeDescriptor dir, boolean includeDeleted) { return fService.getDirectoryListingDirect(dir, includeDeleted); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getFileInputStream(int, java.lang.String) - */ public InputStream getFileInputStream(int version, String path) { return fService.getFileInputStream(version, path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getFileInputStream(org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ public InputStream getFileInputStream(AVMNodeDescriptor desc) { return fService.getFileInputStream(desc); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getFileOutputStream(java.lang.String) - */ public OutputStream getFileOutputStream(String path) { grabLock(path); return fService.getFileOutputStream(path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getHeadPaths(org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ public List> getHeadPaths(AVMNodeDescriptor desc) { return fService.getHeadPaths(desc); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getHistory(org.alfresco.service.cmr.avm.AVMNodeDescriptor, int) - */ public List getHistory(AVMNodeDescriptor desc, int count) { return fService.getHistory(desc, count); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getIndirectionPath(int, java.lang.String) - */ public String getIndirectionPath(int version, String path) { return fService.getIndirectionPath(version, path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getLatestSnapshotID(java.lang.String) - */ public int getLatestSnapshotID(String storeName) { return fService.getLatestSnapshotID(storeName); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getLayeringInfo(int, java.lang.String) - */ public LayeringDescriptor getLayeringInfo(int version, String path) { return fService.getLayeringInfo(version, path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getNextVersionID(java.lang.String) - */ public int getNextVersionID(String storeName) { return fService.getNextVersionID(storeName); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getNodeProperties(int, java.lang.String) - */ public Map getNodeProperties(int version, String path) { return fService.getNodeProperties(version, path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getNodeProperties(org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ public Map getNodeProperties(AVMNodeDescriptor desc) { return fService.getNodeProperties(desc); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getNodeProperty(int, java.lang.String, org.alfresco.service.namespace.QName) - */ public PropertyValue getNodeProperty(int version, String path, QName name) { return fService.getNodeProperty(version, path, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getPaths(org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ public List> getPaths(AVMNodeDescriptor desc) { return fService.getPaths(desc); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getPathsInStoreHead(org.alfresco.service.cmr.avm.AVMNodeDescriptor, java.lang.String) - */ public List> getPathsInStoreHead( AVMNodeDescriptor desc, String store) { return fService.getPathsInStoreHead(desc, store); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getStore(java.lang.String) - */ public AVMStoreDescriptor getStore(String name) { return fService.getStore(name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getStoreProperties(java.lang.String) - */ public Map getStoreProperties(String store) { return fService.getStoreProperties(store); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getStoreProperty(java.lang.String, org.alfresco.service.namespace.QName) - */ public PropertyValue getStoreProperty(String store, QName name) { return fService.getStoreProperty(store, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getStoreRoot(int, java.lang.String) - */ public AVMNodeDescriptor getStoreRoot(int version, String name) { return fService.getStoreRoot(version, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getStoreVersions(java.lang.String) - */ public List getStoreVersions(String name) { return fService.getStoreVersions(name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getStoreVersions(java.lang.String, java.util.Date, java.util.Date) - */ - public List getStoreVersions(String name, Date from, - Date to) + public List getStoreVersions(String name, Date from, Date to) { return fService.getStoreVersions(name, from, to); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getStores() - */ public List getStores() { return fService.getStores(); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getSystemStore() - */ public AVMStoreDescriptor getSystemStore() { return fService.getSystemStore(); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#hasAspect(int, java.lang.String, org.alfresco.service.namespace.QName) - */ public boolean hasAspect(int version, String path, QName aspectName) { return fService.hasAspect(version, path, aspectName); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#link(java.lang.String, java.lang.String, org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ public void link(String parentPath, String name, AVMNodeDescriptor toLink) { // TODO Does this need a lock? I don't think so, but revisit. fService.link(parentPath, name, toLink); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#updateLink(java.lang.String, java.lang.String, org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ public void updateLink(String parentPath, String name, AVMNodeDescriptor toLink) { // TODO Does this need a lock? I don't think so, but revisit. fService.updateLink(parentPath, name, toLink); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#lookup(int, java.lang.String) - */ public AVMNodeDescriptor lookup(int version, String path) { return fService.lookup(version, path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#lookup(int, java.lang.String, boolean) - */ public AVMNodeDescriptor lookup(int version, String path, boolean includeDeleted) { return fService.lookup(version, path, includeDeleted); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#lookup(org.alfresco.service.cmr.avm.AVMNodeDescriptor, java.lang.String) - */ public AVMNodeDescriptor lookup(AVMNodeDescriptor dir, String name) { return fService.lookup(dir, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#lookup(org.alfresco.service.cmr.avm.AVMNodeDescriptor, java.lang.String, boolean) - */ public AVMNodeDescriptor lookup(AVMNodeDescriptor dir, String name, boolean includeDeleted) { return fService.lookup(dir, name, includeDeleted); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#makePrimary(java.lang.String) - */ public void makePrimary(String path) { fService.makePrimary(path); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#makeTransparent(java.lang.String, java.lang.String) - */ public void makeTransparent(String dirPath, String name) { fService.makeTransparent(dirPath, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#purgeStore(java.lang.String) - */ public void purgeStore(String name) { fService.purgeStore(name); @@ -659,86 +438,66 @@ public class AVMLockingAwareService implements AVMService, ApplicationContextAwa String webProject = WCMUtil.getWebProject(fService, name); if (webProject != null) { - fLockingService.removeStoreLocks(name); + fLockingService.removeLocks(name); } } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#purgeVersion(int, java.lang.String) - */ public void purgeVersion(int version, String name) { fService.purgeVersion(version, name); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#queryStorePropertyKey(java.lang.String, org.alfresco.service.namespace.QName) - */ - public Map queryStorePropertyKey(String store, - QName keyPattern) + public Map queryStorePropertyKey(String store, QName keyPattern) { return fService.queryStorePropertyKey(store, keyPattern); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#queryStoresPropertyKeys(org.alfresco.service.namespace.QName) - */ - public Map> queryStoresPropertyKeys( - QName keyPattern) + public Map> queryStoresPropertyKeys(QName keyPattern) { return fService.queryStoresPropertyKeys(keyPattern); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#removeAspect(java.lang.String, org.alfresco.service.namespace.QName) - */ public void removeAspect(String path, QName aspectName) { grabLock(path); fService.removeAspect(path, aspectName); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#removeNode(java.lang.String, java.lang.String) - */ public void removeNode(String parent, String name) { String path = AVMUtil.extendAVMPath(parent, name); grabLock(path); fService.removeNode(parent, name); String[] storePath = AVMUtil.splitPath(parent); - fService.createSnapshot(storePath[0], null, "Removed "+path); - String webProject = WCMUtil.getWebProject(fService, storePath[0]); + String avmStore = storePath[0]; + fService.createSnapshot(avmStore, null, "Removed "+path); + String webProject = WCMUtil.getWebProject(fService, avmStore); if (webProject != null) { - fLockingService.removeLocksInDirectory(webProject, storePath[0], AVMUtil.extendAVMPath(storePath[1], name)); + Map lockDataToMatch = Collections.singletonMap(WCMUtil.LOCK_KEY_STORE_NAME, avmStore); + String relPath = AVMUtil.extendAVMPath(storePath[1], name); // store-relative path, eg. /www/avm_webapps/ROOT/my.txt + fLockingService.removeLocks(webProject, relPath, lockDataToMatch); } } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#removeNode(java.lang.String) - */ public void removeNode(String path) { grabLock(path); fService.removeNode(path); String[] storePath = AVMUtil.splitPath(path); - fService.createSnapshot(storePath[0], null, "Removed "+path); - String webProject = WCMUtil.getWebProject(fService, storePath[0]); + String avmStore = storePath[0]; + String relPath = storePath[1]; // store-relative path, eg. /www/avm_webapps/ROOT/my.txt + fService.createSnapshot(avmStore, null, "Removed "+path); + String webProject = WCMUtil.getWebProject(fService, avmStore); if (webProject != null) { - fLockingService.removeLocksInDirectory(webProject, storePath[0], storePath[1]); + Map lockDataToMatch = Collections.singletonMap(WCMUtil.LOCK_KEY_STORE_NAME, avmStore); + fLockingService.removeLocks(webProject, relPath, lockDataToMatch); } } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#rename(java.lang.String, java.lang.String, java.lang.String, java.lang.String) - */ - public void rename(String srcParent, String srcName, String dstParent, - String dstName) + public void rename(String srcParent, String srcName, String dstParent, String dstName) { - // TODO Unresolved: how to deal with directory level locking. - String srcPath = AVMUtil.extendAVMPath(srcParent, srcName); String dstPath = AVMUtil.extendAVMPath(dstParent, dstName); @@ -760,90 +519,65 @@ public class AVMLockingAwareService implements AVMService, ApplicationContextAwa if ((dstWebProject != null) && (dstWebProject.equals(srcWebProject))) { - fLockingService.modifyLock(dstWebProject, srcStorePath[1], dstStorePath[1], dstStorePath[0], null, null); + // Make sure we hold the lock already + grabLock(dstPath); } else { + // Remove the old lock and take the new fLockingService.removeLock(srcWebProject, srcStorePath[1]); grabLock(dstPath); } } } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#renameStore(java.lang.String, java.lang.String) - */ public void renameStore(String sourceName, String destName) { fService.renameStore(sourceName, destName); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#retargetLayeredDirectory(java.lang.String, java.lang.String) - */ public void retargetLayeredDirectory(String path, String target) { // TODO This assumes that directories are not locked. fService.retargetLayeredDirectory(path, target); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#revert(java.lang.String, org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ public void revert(String path, AVMNodeDescriptor toRevertTo) { grabLock(path); fService.revert(path, toRevertTo); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#setContentData(java.lang.String, org.alfresco.service.cmr.repository.ContentData) - */ public void setContentData(String path, ContentData data) { grabLock(path); fService.setContentData(path, data); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#setEncoding(java.lang.String, java.lang.String) - */ public void setEncoding(String path, String encoding) { grabLock(path); fService.setEncoding(path, encoding); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#setGuid(java.lang.String, java.lang.String) - */ public void setGuid(String path, String guid) { grabLock(path); fService.setGuid(path, guid); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#setMetaDataFrom(java.lang.String, org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ public void setMetaDataFrom(String path, AVMNodeDescriptor from) { grabLock(path); fService.setMetaDataFrom(path, from); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#setMimeType(java.lang.String, java.lang.String) - */ public void setMimeType(String path, String mimeType) { grabLock(path); fService.setMimeType(path, mimeType); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#setNodeProperties(java.lang.String, java.util.Map) - */ public void setNodeProperties(String path, Map properties) { @@ -851,49 +585,45 @@ public class AVMLockingAwareService implements AVMService, ApplicationContextAwa fService.setNodeProperties(path, properties); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#setNodeProperty(java.lang.String, org.alfresco.service.namespace.QName, org.alfresco.repo.domain.PropertyValue) - */ public void setNodeProperty(String path, QName name, PropertyValue value) { grabLock(path); fService.setNodeProperty(path, name, value); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#setOpacity(java.lang.String, boolean) - */ public void setOpacity(String path, boolean opacity) { // TODO Assumes no directory locking. fService.setOpacity(path, opacity); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#setStoreProperties(java.lang.String, java.util.Map) - */ public void setStoreProperties(String store, Map props) { fService.setStoreProperties(store, props); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#setStoreProperty(java.lang.String, org.alfresco.service.namespace.QName, org.alfresco.repo.domain.PropertyValue) - */ public void setStoreProperty(String store, QName name, PropertyValue value) { fService.setStoreProperty(store, name, value); } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#uncover(java.lang.String, java.lang.String) - */ public void uncover(String dirPath, String name) { // TODO What about when this is a directory? grabLock(AVMUtil.extendAVMPath(dirPath, name)); fService.uncover(dirPath, name); } + + public void createDirectory(String path, String name, List aspects, Map properties) + { + fService.createDirectory(path, name, aspects, properties); + } + + public void createFile(String path, String name, InputStream in, List aspects, Map properties) + { + grabLock(AVMUtil.extendAVMPath(path, name)); + fService.createFile(path, name, in, aspects, properties); + } private void grabLock(String path) { @@ -903,59 +633,33 @@ public class AVMLockingAwareService implements AVMService, ApplicationContextAwa return; } String[] storePath = AVMUtil.splitPath(path); + String avmStore = storePath[0]; String webProject = WCMUtil.getWebProject(fService, storePath[0]); - if (webProject != null && webProject.equals(storePath[0])) + if (webProject != null && webProject.equals(avmStore)) { // Don't do locking in staging. return; } if (webProject != null) { - String userName = fAuthenticationService.getCurrentUserName(); - - boolean hasAccess = fLockingService.hasAccess(webProject, path, userName); - AVMLock lock = fLockingService.getLock(webProject, storePath[1]); - - if (!hasAccess) + String userName = AuthenticationUtil.getFullyAuthenticatedUser(); + LockState lockState = fLockingService.getLockState(webProject, storePath[1], userName); + switch (lockState) { - String owners = null; - if (lock == null) - { - owners = null; - } - else - { - owners = lock.getOwners().toString(); // eg. '[alice]' or '[alice, bob]' - } - throw new AVMLockingException("avmlockservice.locked", new Object[]{path, owners}); - } - if (lock == null) - { - List owners = new ArrayList(1); - owners.add(userName); - lock = new AVMLock(webProject, storePath[0], storePath[1], AVMLockingService.Type.DISCRETIONARY, owners); - fLockingService.lockPath(lock); + case LOCK_NOT_OWNER: + String lockOwner = fLockingService.getLockOwner(webProject, storePath[1]); + throw new AVMLockingException("avmlockservice.locked", path, lockOwner); + case NO_LOCK: + Map lockAttributes = Collections.singletonMap(WCMUtil.LOCK_KEY_STORE_NAME, avmStore); + fLockingService.lock(webProject, storePath[1], userName, lockAttributes); + break; + case LOCK_OWNER: + // Nothing to do + break; } } } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#createDirectory(java.lang.String, java.lang.String, java.util.List, java.util.Map) - */ - public void createDirectory(String path, String name, List aspects, Map properties) - { - fService.createDirectory(path, name, aspects, properties); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#createFile(java.lang.String, java.lang.String, java.io.InputStream, java.util.List, java.util.Map) - */ - public void createFile(String path, String name, InputStream in, List aspects, Map properties) - { - grabLock(AVMUtil.extendAVMPath(path, name)); - fService.createFile(path, name, in, aspects, properties); - } - public List getStoreVersionsTo(String name, int version) { return fService.getStoreVersionsTo(name, version); diff --git a/source/java/org/alfresco/repo/avm/AVMNode.java b/source/java/org/alfresco/repo/avm/AVMNode.java index bac1d43638..5a152df52b 100644 --- a/source/java/org/alfresco/repo/avm/AVMNode.java +++ b/source/java/org/alfresco/repo/avm/AVMNode.java @@ -22,8 +22,9 @@ import java.util.Set; import org.alfresco.repo.domain.DbAccessControlList; import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.security.permissions.ACLCopyMode; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.QName; /** * The Interface for versionable objects. @@ -148,41 +149,41 @@ public interface AVMNode /** * Set a property. - * @param qname the QName - * @param value The value to set. + * @param qname the QName + * @param value The value to set. */ - public void setProperty(QName qname, PropertyValue value); + public void setProperty(QName qname, PropertyValue value); /** * Set a collection of properties on this node. - * @param properties The Map of QNames to PropertyValues. + * @param properties The Map of QNames to PropertyValues. */ - public void setProperties(Map properties); + public void setProperties(Map properties); + + /** + * Add properties to those that already exist. + * @param properties The properties to add. + */ + public void addProperties(Map properties); /** - * Add properties to those that already exist. - * @param properties The properties to add. - */ - public void addProperties(Map properties); - - /** * Get a property by name. * @param name The name of the property to get. * @return A PropertyValue */ - public PropertyValue getProperty(QName name); + public PropertyValue getProperty(QName name); /** * Get all the properties associated with this node. * @return A Map of QNames to PropertyValues. */ - public Map getProperties(); + public Map getProperties(); /** * Delete a property from this node. * @param qnameEntityId the ID of the QName to delete */ - public void deleteProperty(QName qname); + public void deleteProperty(QName qname); /** * Delete all properties from this node. @@ -212,7 +213,17 @@ public interface AVMNode * @return The store that we're new in. */ public AVMStore getStoreNew(); - + + /** + * Copy ACL from another node. + * + * @param other + * @param mode + */ + public void copyACLs(AVMNode other, ACLCopyMode mode); + + public void copyACLs(DbAccessControlList otherAcl, DbAccessControlList parentAcl, ACLCopyMode mode); + /** * Copy metadata from another node. * @param other The other node. @@ -235,11 +246,11 @@ public interface AVMNode * Get the Aspects that this node has. * @return A Set of Aspects IDs. */ - public Set getAspects(); - - public void addAspect(QName aspectQName); - - public void removeAspect(QName aspectQName); + public Set getAspects(); + + public void addAspect(QName aspectQName); + + public void removeAspect(QName aspectQName); /** * Get the Basic Attributes on this node. diff --git a/source/java/org/alfresco/repo/avm/AVMNodeDAO.java b/source/java/org/alfresco/repo/avm/AVMNodeDAO.java index 2bf3f1445e..b323aeb0f8 100644 --- a/source/java/org/alfresco/repo/avm/AVMNodeDAO.java +++ b/source/java/org/alfresco/repo/avm/AVMNodeDAO.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,147 +14,118 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . */ -package org.alfresco.repo.avm; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.service.namespace.QName; - -/** - * DAO for AVMNodes interface. - * @author britt - */ -public interface AVMNodeDAO -{ - /** - * Save the given node, having never been saved before. - */ - public void save(AVMNode node); - - /** - * Delete a single node. - * @param node The node to delete. - */ - public void delete(AVMNode node); - - public void createAspect(long nodeId, QName aspectQName); - - public void deleteAspect(long nodeId, QName aspectQName); - - public void deleteAspects(long nodeId); - - public Set getAspects(long nodeId); - - public void createOrUpdateProperty(long nodeId, QName propQName, PropertyValue value); - - public void deleteProperty(long nodeId, QName propQName); - - public void deleteProperties(long nodeId); - - public Map getProperties(long nodeId); - - /** - * Get by ID. - * @param id The id to get. - */ - public AVMNode getByID(long id); - - /** - * Get the root of a particular version. - * @param store The store we're querying. - * @param version The version. - * @return The VersionRoot or null. - */ - public DirectoryNode getAVMStoreRoot(AVMStore store, int version); - - /** - * Update a node that has been dirtied. - * @param node The node. - */ - public void update(AVMNode node); - - // update optimisation, eg. when creating files - public void updateModTimeAndGuid(AVMNode node); - - /** - * Get the ancestor of a node. - * @param node The node whose ancestor is desired. - * @return The ancestor or null. - */ - public AVMNode getAncestor(AVMNode node); - - /** - * Get the node the given node was merged from. - * @param node The node whose merged from is desired. - * @return The merged from node or null. - */ - public AVMNode getMergedFrom(AVMNode node); - - /** - * Get up to batchSize orphans. - * @param batchSize Get no more than this number. - * @return A List of orphaned AVMNodes. - */ - public List getOrphans(int batchSize); - - - /** - * Get all the nodes that are new in the given store. - * @param store The store to query. - * @return A List of AVMNodes. - */ - public List getNewInStore(AVMStore store); - - /** - * Clear newInStore field for a store. (Snapshot) - * @param store - */ - public void clearNewInStore(AVMStore store); - - /** - * Get any new layered entries in a store. - * @param store - * @return - */ - public List getNewLayeredInStoreIDs(AVMStore store); - - public List getNewLayeredInStore(AVMStore store); - - /** - * Inappropriate hack to get Hibernate to play nice. - * - * @deprecated - */ - public void flush(); - - /** - * Evict an AVMNode that is no longer going to be used. - * @param node - * - * @deprecated - */ - public void evict(AVMNode node); - - /** - * Clear the cache. - */ - public void clear(); - - /** - * Turn off 2nd level caching. - * - * @deprecated - */ - public void noCache(); - - /** - * Turn on 2nd level caching. - * - * @deprecated - */ - public void yesCache(); -} + * along with Alfresco. If not, see . */ +package org.alfresco.repo.avm; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.service.namespace.QName; + +/** + * DAO for AVMNodes interface. + * @author britt + */ +public interface AVMNodeDAO +{ + /** + * Save the given node, having never been saved before. + */ + public void save(AVMNode node); + + /** + * Delete a single node. + * @param node The node to delete. + */ + public void delete(AVMNode node); + + public void createAspect(long nodeId, QName aspectQName); + + public void deleteAspect(long nodeId, QName aspectQName); + + public void deleteAspects(long nodeId); + + public Set getAspects(long nodeId); + + public void createOrUpdateProperty(long nodeId, QName propQName, PropertyValue value); + + public void deleteProperty(long nodeId, QName propQName); + + public void deleteProperties(long nodeId); + + public Map getProperties(long nodeId); + + /** + * Get by ID. + * @param id The id to get. + */ + public AVMNode getByID(long id); + + /** + * Get the root of a particular version. + * @param store The store we're querying. + * @param version The version. + * @return The VersionRoot or null. + */ + public DirectoryNode getAVMStoreRoot(AVMStore store, int version); + + /** + * Update a node that has been dirtied. + * @param node The node. + */ + public void update(AVMNode node); + + // update optimisation, eg. when creating files + public void updateModTimeAndGuid(AVMNode node); + + /** + * Get the ancestor of a node. + * @param node The node whose ancestor is desired. + * @return The ancestor or null. + */ + public AVMNode getAncestor(AVMNode node); + + /** + * Get the node the given node was merged from. + * @param node The node whose merged from is desired. + * @return The merged from node or null. + */ + public AVMNode getMergedFrom(AVMNode node); + + /** + * Get up to batchSize orphans. + * @param batchSize Get no more than this number. + * @return A List of orphaned AVMNodes. + */ + public List getOrphans(int batchSize); + + + /** + * Get all the nodes that are new in the given store. + * @param store The store to query. + * @return A List of AVMNodes. + */ + public List getNewInStore(AVMStore store); + + /** + * Clear newInStore field for a store. (Snapshot) + * @param store + */ + public void clearNewInStore(AVMStore store); + + /** + * Get any new layered entries in a store. + * @param store + * @return + */ + public List getNewLayeredInStoreIDs(AVMStore store); + + public List getNewLayeredInStore(AVMStore store); + + /** + * Clear the cache. + */ + public void clear(); +} diff --git a/source/java/org/alfresco/repo/avm/AVMNodeImpl.java b/source/java/org/alfresco/repo/avm/AVMNodeImpl.java index 8d64a5dc88..386e258862 100644 --- a/source/java/org/alfresco/repo/avm/AVMNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMNodeImpl.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,570 +14,595 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . */ - -package org.alfresco.repo.avm; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.alfresco.repo.avm.util.RawServices; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.security.permissions.ACLCopyMode; -import org.alfresco.service.cmr.avm.AVMReadOnlyException; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.GUID; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Base class for all repository file system like objects. - * @author britt - */ -public abstract class AVMNodeImpl implements AVMNode -{ - private static Log logger = LogFactory.getLog(AVMNodeImpl.class); - - protected static final boolean DEBUG = logger.isDebugEnabled(); - - /** - * The Object ID. - */ - private long fID; - - /** - * The Version ID. - */ - private int fVersionID; - - /** - * The basic attributes of this. Owner, creator, mod time, etc. - */ - private BasicAttributes fBasicAttributes; - - /** - * The version number (for concurrency control). - */ - private long fVers; - - /** - * The rootness of this node. - */ - private boolean fIsRoot; - - /** - * The ACL on this node. - */ - private DbAccessControlList fACL; - - /** - * The Store that we're new in. - */ - private AVMStore fStoreNew; - - /** - * The GUID for this version. - */ - private String fGUID; - - /** - * The Aspects that belong to this node. - */ - private Set fAspects; - - private Map fProperties; - - /** - * Default constructor. - */ - protected AVMNodeImpl() - { - } - - /** - * Constructor used when creating a new concrete subclass instance. - * @param store The AVMStore that owns this. - */ - protected AVMNodeImpl(AVMStore store) - { - this(); - - setVersionID(-1); - setIsRoot(false); - - long time = System.currentTimeMillis(); - String user = - RawServices.Instance().getAuthenticationContext().getCurrentUserName(); - if (user == null) - { - user = RawServices.Instance().getAuthenticationContext().getSystemUserName(); - } - setBasicAttributes(new BasicAttributesImpl(user, - user, - user, - time, - time, - time)); - setStoreNew(store); - setGuid(GUID.generate()); - } - - /** - * Set the ancestor of this node. - * @param ancestor The ancestor to set. - */ - public void setAncestor(AVMNode ancestor) - { - if (ancestor == null) - { - return; - } - HistoryLinkImpl link = new HistoryLinkImpl(); - link.setAncestor(ancestor); - link.setDescendent(this); - AVMDAOs.Instance().fHistoryLinkDAO.save(link); - } - - /** - * Change the ancestor of this node. - * @param ancestor The new ancestor to give it. - */ - public void changeAncestor(AVMNode ancestor) - { - HistoryLink old = AVMDAOs.Instance().fHistoryLinkDAO.getByDescendent(this); - if (old != null) - { - AVMDAOs.Instance().fHistoryLinkDAO.delete(old); - } - setAncestor(ancestor); - } - - /** - * Get the ancestor of this node. - * @return The ancestor of this node. - */ - public AVMNode getAncestor() - { - return AVMDAOs.Instance().fAVMNodeDAO.getAncestor(this); - } - - /** - * Set the node that was merged into this. - * @param mergedFrom The node that was merged into this. - */ - public void setMergedFrom(AVMNode mergedFrom) - { - if (mergedFrom == null) - { - return; - } - MergeLinkImpl link = new MergeLinkImpl(); - link.setMfrom(mergedFrom); - link.setMto(this); - AVMDAOs.Instance().fMergeLinkDAO.save(link); - } - - /** - * Get the node that was merged into this. - * @return The node that was merged into this. - */ - public AVMNode getMergedFrom() - { - return AVMDAOs.Instance().fAVMNodeDAO.getMergedFrom(this); - } - - /** - * Equality based on object ids. - * @param obj The thing to compare against. - * @return Equality. - */ - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (!(obj instanceof AVMNode)) - { - return false; - } - return getId() == ((AVMNode)obj).getId(); - } - - /** - * Get a reasonable hash value. - * @return The hash code. - */ - @Override - public int hashCode() - { - return (int)getId(); - } - - /** - * Set the object id. - * @param id The id to set. - */ - public void setId(long id) - { - fID = id; - } - - /** - * Get the id of this node. - * @return The object id. - */ - public long getId() - { - return fID; - } - - /** - * Set the versionID for this node. - * @param versionID The id to set. - */ - public void setVersionID(int versionID) - { - fVersionID = versionID; - } - - /** - * Get the version id of this node. - * @return The version id. - */ - public int getVersionID() - { - return fVersionID; - } - - /** - * Set the basic attributes. - * @param attrs - */ - public void setBasicAttributes(BasicAttributes attrs) - { - fBasicAttributes = attrs; - } - - /** - * Get the basic attributes. - * @return The basic attributes. - */ - public BasicAttributes getBasicAttributes() - { - return fBasicAttributes; - } - - /** - * Get whether this is a new node. - * @return Whether this is new. - */ - public boolean getIsNew() - { - return getStoreNew() != null; - } - - /** - * Set the version (for concurrency control). - * @param The version for optimistic locks. - */ - public void setVers(long vers) - { - fVers = vers; - } - - /** - * Get the version (for concurrency control). - * @return vers The version for optimistic locks. - */ - public long getVers() - { - return fVers; - } - - /** - * Get whether this is a root node. - * @return Whether this is a root node. - */ - public boolean getIsRoot() - { - return fIsRoot; - } - - /** - * @param isRoot - */ - public void setIsRoot(boolean isRoot) - { - fIsRoot = isRoot; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.AVMNode#updateModTime() - */ - public void updateModTime() - { - if (DEBUG) - { - checkReadOnly(); - } - String user = - RawServices.Instance().getAuthenticationContext().getCurrentUserName(); - if (user == null) - { - user = RawServices.Instance().getAuthenticationContext().getSystemUserName(); - } - getBasicAttributes().setModDate(System.currentTimeMillis()); - getBasicAttributes().setLastModifier(user); - } - - /** - * Copy all properties from another node. - * @param other The other node. - */ - protected void copyProperties(AVMNode other) - { - Map props = new HashMap(); - for (Map.Entry entry : other.getProperties().entrySet()) - { - props.put(entry.getKey(), entry.getValue()); - } - - setProperties(props); - } - - /** - * Copy all aspects from another node. - * @param other The other node. - */ - protected void copyAspects(AVMNode other) - { - Set aspects = new HashSet(other.getAspects()); - setAspects(aspects); - } - - protected void copyCreationAndOwnerBasicAttributes(AVMNode other) - { - getBasicAttributes().setCreateDate(other.getBasicAttributes().getCreateDate()); - getBasicAttributes().setCreator(other.getBasicAttributes().getCreator()); - getBasicAttributes().setOwner(other.getBasicAttributes().getOwner()); - } - - protected void copyACLs(AVMNode other, Long parentAcl, ACLCopyMode mode) - { - DbAccessControlList acl = other.getAcl(); - if (acl != null) - { - setAcl(acl.getCopy(parentAcl, mode)); - } - } - - /** - * Copy out metadata from another node. - * @param other The other node. - */ - public void copyMetaDataFrom(AVMNode other, Long parentAcl) - { - copyAspects(other); - copyACLs(other, parentAcl, ACLCopyMode.COPY); - copyProperties(other); - copyCreationAndOwnerBasicAttributes(other); - } - - /** - * Set a property on a node. Overwrite it if it exists. - * @param name The name of the property. - * @param value The value to set. - */ - public void setProperty(QName qname, PropertyValue value) - { - if (DEBUG) - { - checkReadOnly(); - } - - getProperties().put(qname, value); - - AVMDAOs.Instance().fAVMNodeDAO.createOrUpdateProperty(this.getId(), qname, value); - } - - public void addProperties(Map properties) - { - for (Map.Entry entry : properties.entrySet()) - { - setProperty(entry.getKey(), entry.getValue()); - } - } - - /** - * Set a collection of properties on this node. - * @param properties The Map of QNames to PropertyValues. - */ - public void setProperties(Map properties) - { - fProperties = properties; - - for (Map.Entry entry : properties.entrySet()) - { - setProperty(entry.getKey(), entry.getValue()); - } - } - - /** - * Get a property by name. - * @param name The name of the property. - * @return The PropertyValue or null if non-existent. - */ - public PropertyValue getProperty(QName qname) - { - return getProperties().get(qname); - } - - /** - * {@inheritDoc} - */ - public Map getProperties() - { - if (fProperties == null) - { - fProperties = AVMDAOs.Instance().fAVMNodeDAO.getProperties(getId()); - } - return fProperties; - } - - /** - * Delete a property from this node. - * @param name The name of the property. - */ - public void deleteProperty(QName qname) - { - if (DEBUG) - { - checkReadOnly(); - } - getProperties().remove(qname); - - AVMDAOs.Instance().fAVMNodeDAO.deleteProperty(getId(), qname); - } - - /** - * Delete all properties from this node. - */ - public void deleteProperties() - { - getProperties().clear(); - - AVMDAOs.Instance().fAVMNodeDAO.deleteProperties(getId()); - } - - /** - * Set the ACL on this node. - * @param acl The ACL to set. - */ - public void setAcl(DbAccessControlList acl) - { - fACL = acl; - } - - /** - * Get the ACL on this node. - * @return The ACL on this node. - */ - public DbAccessControlList getAcl() - { - return fACL; - } - - /** - * Set the store we are new in. - * @param store The store we are new in. - */ - public void setStoreNew(AVMStore store) - { - fStoreNew = store; - } - - /** - * Get the possibly null store we are new in. - * @return The store we are new in. - */ - public AVMStore getStoreNew() - { - return fStoreNew; - } - - protected void checkReadOnly() - { - if (getStoreNew() == null) - { - throw new AVMReadOnlyException("Write Operation on R/O Node."); - } - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.AVMNode#getGuid() - */ - public String getGuid() - { - return fGUID; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.AVMNode#setGuid(java.lang.String) - */ - public void setGuid(String guid) - { - fGUID = guid; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.AVMNode#getAspects() - */ - public Set getAspects() - { - if (fAspects == null) - { - fAspects = AVMDAOs.Instance().fAVMNodeDAO.getAspects(getId()); - } - return fAspects; - } - - /** - * Set the aspects on this node. - * @param aspects - */ - public void setAspects(Set aspects) - { - fAspects = aspects; - - if ((aspects != null) && (aspects.size() > 0)) - { - for (QName aspectQName : aspects) - { - AVMDAOs.Instance().fAVMNodeDAO.createAspect(this.getId(), aspectQName); - } - } - } - - public void addAspect(QName aspectQName) - { - fAspects = null; - AVMDAOs.Instance().fAVMNodeDAO.createAspect(this.getId(), aspectQName); - } - - public void removeAspect(QName aspectQName) - { - fAspects = null; - AVMDAOs.Instance().fAVMNodeDAO.deleteAspect(this.getId(), aspectQName); - } - - // debug - public String toString() - { - return toString(null); - } -} + * along with Alfresco. If not, see . */ + +package org.alfresco.repo.avm; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.avm.util.RawServices; +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.security.permissions.ACLCopyMode; +import org.alfresco.service.cmr.avm.AVMReadOnlyException; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.GUID; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Base class for all repository file system like objects. + * @author britt + */ +public abstract class AVMNodeImpl implements AVMNode +{ + private static Log logger = LogFactory.getLog(AVMNodeImpl.class); + + protected static final boolean DEBUG = logger.isDebugEnabled(); + + /** + * The Object ID. + */ + private long fID; + + /** + * The Version ID. + */ + private int fVersionID; + + /** + * The basic attributes of this. Owner, creator, mod time, etc. + */ + private BasicAttributes fBasicAttributes; + + /** + * The version number (for concurrency control). + */ + private long fVers; + + /** + * The rootness of this node. + */ + private boolean fIsRoot; + + /** + * The ACL on this node. + */ + private DbAccessControlList fACL; + + /** + * The Store that we're new in. + */ + private AVMStore fStoreNew; + + /** + * The GUID for this version. + */ + private String fGUID; + + /** + * The Aspects that belong to this node. + */ + private Set fAspects; + + private Map fProperties; + + /** + * Default constructor. + */ + protected AVMNodeImpl() + { + } + + /** + * Constructor used when creating a new concrete subclass instance. + * @param store The AVMStore that owns this. + */ + protected AVMNodeImpl(AVMStore store) + { + this(); + + setVersionID(-1); + setIsRoot(false); + + long time = System.currentTimeMillis(); + String user = + RawServices.Instance().getAuthenticationContext().getCurrentUserName(); + if (user == null) + { + user = RawServices.Instance().getAuthenticationContext().getSystemUserName(); + } + setBasicAttributes(new BasicAttributesImpl(user, + user, + user, + time, + time, + time)); + setStoreNew(store); + setGuid(GUID.generate()); + } + + /** + * Set the ancestor of this node. + * @param ancestor The ancestor to set. + */ + public void setAncestor(AVMNode ancestor) + { + if (ancestor == null) + { + return; + } + HistoryLinkImpl link = new HistoryLinkImpl(); + link.setAncestor(ancestor); + link.setDescendent(this); + AVMDAOs.Instance().fHistoryLinkDAO.save(link); + } + + /** + * Change the ancestor of this node. + * @param ancestor The new ancestor to give it. + */ + public void changeAncestor(AVMNode ancestor) + { + HistoryLink old = AVMDAOs.Instance().fHistoryLinkDAO.getByDescendent(this); + if (old != null) + { + AVMDAOs.Instance().fHistoryLinkDAO.delete(old); + } + setAncestor(ancestor); + } + + /** + * Get the ancestor of this node. + * @return The ancestor of this node. + */ + public AVMNode getAncestor() + { + return AVMDAOs.Instance().fAVMNodeDAO.getAncestor(this); + } + + /** + * Set the node that was merged into this. + * @param mergedFrom The node that was merged into this. + */ + public void setMergedFrom(AVMNode mergedFrom) + { + if (mergedFrom == null) + { + return; + } + MergeLinkImpl link = new MergeLinkImpl(); + link.setMfrom(mergedFrom); + link.setMto(this); + AVMDAOs.Instance().fMergeLinkDAO.save(link); + } + + /** + * Get the node that was merged into this. + * @return The node that was merged into this. + */ + public AVMNode getMergedFrom() + { + return AVMDAOs.Instance().fAVMNodeDAO.getMergedFrom(this); + } + + /** + * Equality based on object ids. + * @param obj The thing to compare against. + * @return Equality. + */ + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (!(obj instanceof AVMNode)) + { + return false; + } + return getId() == ((AVMNode)obj).getId(); + } + + /** + * Get a reasonable hash value. + * @return The hash code. + */ + @Override + public int hashCode() + { + return (int)getId(); + } + + /** + * Set the object id. + * @param id The id to set. + */ + public void setId(long id) + { + fID = id; + } + + /** + * Get the id of this node. + * @return The object id. + */ + public long getId() + { + return fID; + } + + /** + * Set the versionID for this node. + * @param versionID The id to set. + */ + public void setVersionID(int versionID) + { + fVersionID = versionID; + } + + /** + * Get the version id of this node. + * @return The version id. + */ + public int getVersionID() + { + return fVersionID; + } + + /** + * Set the basic attributes. + * @param attrs + */ + public void setBasicAttributes(BasicAttributes attrs) + { + fBasicAttributes = attrs; + } + + /** + * Get the basic attributes. + * @return The basic attributes. + */ + public BasicAttributes getBasicAttributes() + { + return fBasicAttributes; + } + + /** + * Get whether this is a new node. + * @return Whether this is new. + */ + public boolean getIsNew() + { + return getStoreNew() != null; + } + + /** + * Set the version (for concurrency control). + * @param The version for optimistic locks. + */ + public void setVers(long vers) + { + fVers = vers; + } + + /** + * Get the version (for concurrency control). + * @return vers The version for optimistic locks. + */ + public long getVers() + { + return fVers; + } + + /** + * Get whether this is a root node. + * @return Whether this is a root node. + */ + public boolean getIsRoot() + { + return fIsRoot; + } + + /** + * @param isRoot + */ + public void setIsRoot(boolean isRoot) + { + fIsRoot = isRoot; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.avm.AVMNode#updateModTime() + */ + public void updateModTime() + { + if (DEBUG) + { + checkReadOnly(); + } + String user = + RawServices.Instance().getAuthenticationContext().getCurrentUserName(); + if (user == null) + { + user = RawServices.Instance().getAuthenticationContext().getSystemUserName(); + } + getBasicAttributes().setModDate(System.currentTimeMillis()); + getBasicAttributes().setLastModifier(user); + } + + /** + * Copy all properties from another node. + * @param other The other node. + */ + protected void copyProperties(AVMNode other) + { + Map props = new HashMap(); + for (Map.Entry entry : other.getProperties().entrySet()) + { + props.put(entry.getKey(), entry.getValue()); + } + + setProperties(props); + } + + /** + * Copy all aspects from another node. + * @param other The other node. + */ + protected void copyAspects(AVMNode other) + { + Set aspects = new HashSet(other.getAspects()); + setAspects(aspects); + } + + protected void copyCreationAndOwnerBasicAttributes(AVMNode other) + { + getBasicAttributes().setCreateDate(other.getBasicAttributes().getCreateDate()); + getBasicAttributes().setCreator(other.getBasicAttributes().getCreator()); + getBasicAttributes().setOwner(other.getBasicAttributes().getOwner()); + } + + public void copyACLs(AVMNode other, ACLCopyMode mode) + { + DbAccessControlList otherAcl = other.getAcl(); + Long otherAclId = (otherAcl == null ? null : otherAcl.getId()); + copyACLs(otherAclId, otherAclId, mode); + } + + public void copyACLs(DbAccessControlList otherAcl, DbAccessControlList parentAcl, ACLCopyMode mode) + { + Long otherAclId = (otherAcl == null ? null : otherAcl.getId()); + Long parentAclId = (parentAcl == null ? null : parentAcl.getId()); + + copyACLs(otherAclId, parentAclId, mode); + } + + protected void copyACLs(AVMNode other, Long parentAcl, ACLCopyMode mode) + { + DbAccessControlList otherAcl = other.getAcl(); + copyACLs((otherAcl == null ? null : otherAcl.getId()), parentAcl, mode); + } + + protected void copyACLs(Long otherAcl, Long parentAcl, ACLCopyMode mode) + { + if (otherAcl != null) + { + DbAccessControlList aclCopy = AVMDAOs.Instance().fAclDAO.getDbAccessControlListCopy(otherAcl, parentAcl, mode); + setAcl(aclCopy); + } + else + { + setAcl(null); + } + } + + /** + * Copy out metadata from another node. + * @param other The other node. + */ + public void copyMetaDataFrom(AVMNode other, Long parentAcl) + { + copyAspects(other); + copyACLs(other, parentAcl, ACLCopyMode.COPY); + copyProperties(other); + copyCreationAndOwnerBasicAttributes(other); + } + + /** + * Set a property on a node. Overwrite it if it exists. + * @param name The name of the property. + * @param value The value to set. + */ + public void setProperty(QName qname, PropertyValue value) + { + if (DEBUG) + { + checkReadOnly(); + } + + getProperties().put(qname, value); + + AVMDAOs.Instance().fAVMNodeDAO.createOrUpdateProperty(this.getId(), qname, value); + } + + public void addProperties(Map properties) + { + for (Map.Entry entry : properties.entrySet()) + { + setProperty(entry.getKey(), entry.getValue()); + } + } + + /** + * Set a collection of properties on this node. + * @param properties The Map of QNames to PropertyValues. + */ + public void setProperties(Map properties) + { + fProperties = properties; + + for (Map.Entry entry : properties.entrySet()) + { + setProperty(entry.getKey(), entry.getValue()); + } + } + + /** + * Get a property by name. + * @param name The name of the property. + * @return The PropertyValue or null if non-existent. + */ + public PropertyValue getProperty(QName qname) + { + return getProperties().get(qname); + } + + /** + * {@inheritDoc} + */ + public Map getProperties() + { + if (fProperties == null) + { + fProperties = AVMDAOs.Instance().fAVMNodeDAO.getProperties(getId()); + } + return fProperties; + } + + /** + * Delete a property from this node. + * @param name The name of the property. + */ + public void deleteProperty(QName qname) + { + if (DEBUG) + { + checkReadOnly(); + } + getProperties().remove(qname); + + AVMDAOs.Instance().fAVMNodeDAO.deleteProperty(getId(), qname); + } + + /** + * Delete all properties from this node. + */ + public void deleteProperties() + { + getProperties().clear(); + + AVMDAOs.Instance().fAVMNodeDAO.deleteProperties(getId()); + } + + /** + * Set the ACL on this node. + * @param acl The ACL to set. + */ + public void setAcl(DbAccessControlList acl) + { + fACL = acl; + } + + /** + * Get the ACL on this node. + * @return The ACL on this node. + */ + public DbAccessControlList getAcl() + { + return fACL; + } + + /** + * Set the store we are new in. + * @param store The store we are new in. + */ + public void setStoreNew(AVMStore store) + { + fStoreNew = store; + } + + /** + * Get the possibly null store we are new in. + * @return The store we are new in. + */ + public AVMStore getStoreNew() + { + return fStoreNew; + } + + protected void checkReadOnly() + { + if (getStoreNew() == null) + { + throw new AVMReadOnlyException("Write Operation on R/O Node."); + } + } + + /* (non-Javadoc) + * @see org.alfresco.repo.avm.AVMNode#getGuid() + */ + public String getGuid() + { + return fGUID; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.avm.AVMNode#setGuid(java.lang.String) + */ + public void setGuid(String guid) + { + fGUID = guid; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.avm.AVMNode#getAspects() + */ + public Set getAspects() + { + if (fAspects == null) + { + fAspects = AVMDAOs.Instance().fAVMNodeDAO.getAspects(getId()); + } + return fAspects; + } + + /** + * Set the aspects on this node. + * @param aspects + */ + public void setAspects(Set aspects) + { + fAspects = aspects; + + if ((aspects != null) && (aspects.size() > 0)) + { + for (QName aspectQName : aspects) + { + AVMDAOs.Instance().fAVMNodeDAO.createAspect(this.getId(), aspectQName); + } + } + } + + public void addAspect(QName aspectQName) + { + fAspects = null; + AVMDAOs.Instance().fAVMNodeDAO.createAspect(this.getId(), aspectQName); + } + + public void removeAspect(QName aspectQName) + { + fAspects = null; + AVMDAOs.Instance().fAVMNodeDAO.deleteAspect(this.getId(), aspectQName); + } + + // debug + public String toString() + { + return toString(null); + } +} diff --git a/source/java/org/alfresco/repo/avm/AVMNodeService.java b/source/java/org/alfresco/repo/avm/AVMNodeService.java index bef59e088d..43b211e2d8 100644 --- a/source/java/org/alfresco/repo/avm/AVMNodeService.java +++ b/source/java/org/alfresco/repo/avm/AVMNodeService.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,1973 +14,1973 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . */ - -package org.alfresco.repo.avm; - -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.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; - -import org.alfresco.model.ContentModel; -import org.alfresco.model.WCMModel; -import org.alfresco.repo.avm.util.AVMUtil; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.node.AbstractNodeServiceImpl; -import org.alfresco.service.cmr.avm.AVMException; -import org.alfresco.service.cmr.avm.AVMExistsException; -import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.cmr.avm.AVMNotFoundException; -import org.alfresco.service.cmr.avm.AVMService; -import org.alfresco.service.cmr.avm.AVMStoreDescriptor; -import org.alfresco.service.cmr.dictionary.AspectDefinition; -import org.alfresco.service.cmr.dictionary.ClassDefinition; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -import org.alfresco.service.cmr.dictionary.DictionaryException; -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.ContentData; -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.datatype.TypeConversionException; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.service.namespace.QNamePattern; -import org.alfresco.util.Pair; + * along with Alfresco. If not, see . */ + +package org.alfresco.repo.avm; + +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.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; + +import org.alfresco.model.ContentModel; +import org.alfresco.model.WCMModel; +import org.alfresco.repo.avm.util.AVMUtil; +import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.node.AbstractNodeServiceImpl; +import org.alfresco.service.cmr.avm.AVMException; +import org.alfresco.service.cmr.avm.AVMExistsException; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.cmr.avm.AVMNotFoundException; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avm.AVMStoreDescriptor; +import org.alfresco.service.cmr.dictionary.AspectDefinition; +import org.alfresco.service.cmr.dictionary.ClassDefinition; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryException; +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.ContentData; +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.datatype.TypeConversionException; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.QNamePattern; +import org.alfresco.util.Pair; import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * NodeService implementing facade over AVMService. - * @author britt - */ -public class AVMNodeService extends AbstractNodeServiceImpl implements NodeService -{ - private static Log logger = LogFactory.getLog(AVMNodeService.class); - - /** - * Flag for whether policy callbacks are made. - */ - private boolean fInvokePolicies = false; - - /** - * Reference to AVMService. - */ - private AVMService fAVMService; - - /** - * Set the AVMService. For Spring. - * @param service The AVMService instance. - */ - public void setAvmService(AVMService service) - { - fAVMService = service; - } - - /** - * Default constructor. - */ - public AVMNodeService() - { - } - - public void setInvokePolicies(boolean invoke) - { - fInvokePolicies = invoke; - } - - /** - * Helper method to convert the Serializable value into a full, - * persistable {@link PropertyValue}. - *

- * Where the property definition is null, the value will take on the - * {@link DataTypeDefinition#ANY generic ANY} value. - *

- * Where the property definition specifies a multi-valued property but the - * value provided is not a collection, the value will be wrapped in a collection. - * - * @param propertyDef the property dictionary definition, may be null - * @param value the value, which will be converted according to the definition - - * may be null - * @return Returns the persistable property value - */ - protected PropertyValue makePropertyValue(PropertyDefinition propertyDef, Serializable value) - { - // get property attributes - QName propertyTypeQName = null; - if (propertyDef == null) // property not recognised - { - // allow it for now - persisting excess properties can be useful sometimes - propertyTypeQName = DataTypeDefinition.ANY; - } - else - { - propertyTypeQName = propertyDef.getDataType().getName(); - // check that multi-valued properties are allowed - boolean isMultiValued = propertyDef.isMultiValued(); - if (isMultiValued && !(value instanceof Collection)) - { - if (value != null) - { - // put the value into a collection - // the implementation gives back a Serializable list - value = (Serializable) Collections.singletonList(value); - } - } - else if (!isMultiValued && (value instanceof Collection)) - { - // we only allow this case if the property type is ANY - if (!propertyTypeQName.equals(DataTypeDefinition.ANY)) - { - throw new DictionaryException( - "A single-valued property of this type may not be a collection: \n" + - " Property: " + propertyDef + "\n" + - " Type: " + propertyTypeQName + "\n" + - " Value: " + value); - } - } - } - try - { - PropertyValue propertyValue = new PropertyValue(propertyTypeQName, value); - // done - return propertyValue; - } - catch (TypeConversionException e) - { - throw new TypeConversionException( - "The property value is not compatible with the type defined for the property: \n" + - " property: " + (propertyDef == null ? "unknown" : propertyDef) + "\n" + - " value: " + value + "\n" + - " value type: " + value.getClass(), - e); - } - } - - /** - * Extracts the externally-visible property from the {@link PropertyValue propertyValue}. - * - * @param propertyDef the model property definition - may be null - * @param propertyValue the persisted property - * @return Returns the value of the property in the format dictated by the property - * definition, or null if the property value is null - */ - protected Serializable makeSerializableValue(PropertyDefinition propertyDef, PropertyValue propertyValue) - { - if (propertyValue == null) - { - return null; - } - // get property attributes - QName propertyTypeQName = null; - if (propertyDef == null) - { - // allow this for now - propertyTypeQName = DataTypeDefinition.ANY; - } - else - { - propertyTypeQName = propertyDef.getDataType().getName(); - } - try - { - Serializable value = propertyValue.getValue(propertyTypeQName); - // done - return value; - } - catch (TypeConversionException e) - { - throw new TypeConversionException( - "The property value is not compatible with the type defined for the property: \n" + - " property: " + (propertyDef == null ? "unknown" : propertyDef) + "\n" + - " property value: " + propertyValue, - e); - } - } - - /** - * Gets a list of all available node store references - * - * @return Returns a list of store references - */ - public List getStores() - { - // For AVM stores we fake up StoreRefs. - List stores = fAVMService.getStores(); - List result = new ArrayList(); - for (AVMStoreDescriptor desc : stores) - { - String name = desc.getName(); - result.add(new StoreRef(StoreRef.PROTOCOL_AVM, name)); - } - return result; - } - - /** - * Create a new AVM store. - * @param protocol the implementation protocol - * @param identifier the protocol-specific identifier - * @return Returns a reference to the store - * @throws StoreExistsException - */ - public StoreRef createStore(String protocol, String identifier) throws StoreExistsException - { - StoreRef result = new StoreRef(StoreRef.PROTOCOL_AVM, identifier); - // invokeBeforeCreateStore(ContentModel.TYPE_STOREROOT, result); - try - { - fAVMService.createStore(identifier); - NodeRef rootRef = getRootNode(result); - addAspect(rootRef, ContentModel.ASPECT_ROOT, - Collections.emptyMap()); - // invokeOnCreateStore(rootRef); - return result; - } - catch (AVMExistsException e) - { - throw new StoreExistsException("AVMStore exists", result); - } - } - - /** - * @throws UnsupportedOperationException Always - */ - public void deleteStore(StoreRef storeRef) throws InvalidStoreRefException - { - throw new UnsupportedOperationException(); - } - - /** - * Does the indicated store exist? - * @param storeRef a reference to the store to look for - * @return Returns true if the store exists, otherwise false - */ - public boolean exists(StoreRef storeRef) - { - return fAVMService.getStore(storeRef.getIdentifier()) != null; - } - - /** - * @param nodeRef a reference to the node to look for - * @return Returns true if the node exists, otherwise false - */ - public boolean exists(NodeRef nodeRef) - { - Pair avmInfo = AVMNodeConverter.ToAVMVersionPath(nodeRef); - int version = avmInfo.getFirst(); - String avmPath = avmInfo.getSecond(); - return fAVMService.lookup(version, avmPath) != null; - } - - /** - * Gets the ID of the last transaction that caused the node to change. This includes - * deletions, so it is possible that the node being referenced no longer exists. - * If the node never existed, then null is returned. - * - * @param nodeRef a reference to a current or previously existing node - * @return Returns the status of the node, or null if the node never existed - */ - public NodeRef.Status getNodeStatus(NodeRef nodeRef) - { - // TODO Need to find out if this is important and if so - // need to capture Transaction IDs. - return new NodeRef.Status("Unknown", null, !exists(nodeRef)); - } - - /** - * @param storeRef a reference to an existing store - * @return Returns a reference to the root node of the store - * @throws InvalidStoreRefException if the store could not be found - */ - public NodeRef getRootNode(StoreRef storeRef) throws InvalidStoreRefException - { - String storeName = storeRef.getIdentifier(); - if (fAVMService.getStore(storeName) != null) - { - return AVMNodeConverter.ToNodeRef(-1, storeName + ":/"); - } - else - { - throw new InvalidStoreRefException(storeName +":/" + " not found.", storeRef); - } - } - - /** - * @see #createNode(NodeRef, QName, QName, QName, Map) - */ - public ChildAssociationRef createNode( - NodeRef parentRef, - QName assocTypeQName, - QName assocQName, - QName nodeTypeQName) - throws InvalidNodeRefException, InvalidTypeException - { - return createNode(parentRef, - assocTypeQName, - assocQName, - nodeTypeQName, - new HashMap()); - } - - /** - * Creates a new, non-abstract, real node as a primary child of the given parent node. - * - * @param parentRef the parent node - * @param assocTypeQName the type of the association to create. This is used - * for verification against the data dictionary. - * @param assocQName the qualified name of the association - * @param nodeTypeQName a reference to the node type - * @param properties optional map of properties to keyed by their qualified names - * @return Returns a reference to the newly created child association - * @throws InvalidNodeRefException if the parent reference is invalid - * @throws InvalidTypeException if the node type reference is not recognised - * - * @see org.alfresco.service.cmr.dictionary.DictionaryService - */ - public ChildAssociationRef createNode( - NodeRef parentRef, - QName assocTypeQName, - QName assocQName, - QName nodeTypeQName, - Map properties) - throws InvalidNodeRefException, InvalidTypeException - { - // AVM stores only allow simple child associations. - if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS)) - { - throw new InvalidTypeException(assocTypeQName); - } - String nodeName = assocQName.getLocalName(); - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef); - int version = avmVersionPath.getFirst(); - if (version >= 0) - { - throw new InvalidNodeRefException("Read only store.", parentRef); - } - String avmPath = avmVersionPath.getSecond(); - // Invoke policy behavior. - // invokeBeforeUpdateNode(parentRef); - // invokeBeforeCreateNode(parentRef, assocTypeQName, assocQName, nodeTypeQName); - // Look up the type definition in the dictionary. - TypeDefinition nodeTypeDef = dictionaryService.getType(nodeTypeQName); - // Do the creates for supported types, or error out. - try - { - if (nodeTypeQName.equals(WCMModel.TYPE_AVM_PLAIN_FOLDER) || - nodeTypeQName.equals(ContentModel.TYPE_FOLDER)) - { - fAVMService.createDirectory(avmPath, nodeName); - } - else if (nodeTypeQName.equals(WCMModel.TYPE_AVM_PLAIN_CONTENT) || - nodeTypeQName.equals(ContentModel.TYPE_CONTENT)) - { - fAVMService.createFile(avmPath, nodeName); - } - else if (nodeTypeQName.equals(WCMModel.TYPE_AVM_LAYERED_CONTENT)) - { - NodeRef indirection = (NodeRef)properties.get(WCMModel.PROP_AVM_FILE_INDIRECTION); - if (indirection == null) - { - throw new InvalidTypeException("No Indirection Property", nodeTypeQName); - } - Pair indVersionPath = AVMNodeConverter.ToAVMVersionPath(indirection); - fAVMService.createLayeredFile(indVersionPath.getSecond(), avmPath, nodeName); - } - else if (nodeTypeQName.equals(WCMModel.TYPE_AVM_LAYERED_FOLDER)) - { - NodeRef indirection = (NodeRef)properties.get(WCMModel.PROP_AVM_DIR_INDIRECTION); - if (indirection == null) - { - throw new InvalidTypeException("No Indirection Property.", nodeTypeQName); - } - Pair indVersionPath = AVMNodeConverter.ToAVMVersionPath(indirection); - fAVMService.createLayeredDirectory(indVersionPath.getSecond(), avmPath, nodeName); - } - else - { - throw new InvalidTypeException("Invalid node type for AVM.", nodeTypeQName); - } - properties.putAll(getDefaultProperties(nodeTypeDef)); - addDefaultAspects(nodeTypeDef, avmPath, properties); - } - catch (AVMNotFoundException e) - { - throw new InvalidNodeRefException(avmPath + " not found.", parentRef); - } - catch (AVMExistsException e) - { - throw new InvalidNodeRefException("Child " + nodeName + " exists", parentRef); - } - String newAVMPath = AVMNodeConverter.ExtendAVMPath(avmPath, nodeName); - NodeRef childRef = AVMNodeConverter.ToNodeRef(-1, newAVMPath); - properties.putAll(getDefaultProperties(nodeTypeDef)); - addDefaultAspects(nodeTypeDef, newAVMPath, properties); - Map props = new HashMap(); - for (Map.Entry entry : properties.entrySet()) - { - QName propertyQName = entry.getKey(); - if (isBuiltInProperty(propertyQName)) - { - continue; - } - Serializable value = entry.getValue(); - PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); - PropertyValue propertyValue = makePropertyValue(propertyDef, value); - props.put(propertyQName, propertyValue); - } - fAVMService.setNodeProperties(newAVMPath, props); - ChildAssociationRef ref = - new ChildAssociationRef(assocTypeQName, - parentRef, - assocQName, - childRef, - true, - -1); -// invokeOnCreateNode(ref); -// invokeOnUpdateNode(parentRef); -// if (properties.size() != 0) -// { -// invokeOnUpdateProperties(childRef, new HashMap(), properties); -// } - return ref; - } - - /** - * Moves the primary location of the given node. - *

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

- * If the new parent is in a different store from the original, then the entire - * node hierarchy is moved to the new store. Inter-store associations are not - * affected. - * - * @param nodeToMoveRef the node to move - * @param newParentRef the new parent of the moved node - * @param assocTypeQName the type of the association to create. This is used - * for verification against the data dictionary. - * @param assocQName the qualified name of the new child association - * @return Returns a reference to the newly created child association - * @throws InvalidNodeRefException if either the parent node or move node reference is invalid - * @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add - * - * @see #getPrimaryParent(NodeRef) - */ - public ChildAssociationRef moveNode( - NodeRef nodeToMoveRef, - NodeRef newParentRef, - QName assocTypeQName, - QName assocQName) - throws InvalidNodeRefException - { - // AVM stores only allow simple child associations. - if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS)) - { - throw new InvalidTypeException(assocTypeQName); - } - // Extract the parts from the source. - Pair src = AVMNodeConverter.ToAVMVersionPath(nodeToMoveRef); - int srcVersion = src.getFirst(); - if (srcVersion >= 0) - { - throw new InvalidNodeRefException("Read Only Store.", nodeToMoveRef); - } - String srcPath = src.getSecond(); - String [] splitSrc = null; - try - { - splitSrc = AVMNodeConverter.SplitBase(srcPath); - } - catch (AVMException e) - { - throw new InvalidNodeRefException("Invalid src path.", nodeToMoveRef); - } - String srcParent = splitSrc[0]; - if (srcParent == null) - { - throw new InvalidNodeRefException("Cannot rename root node.", nodeToMoveRef); - } - String srcName = splitSrc[1]; - // Extract and setup the parts of the destination. - Pair dst = AVMNodeConverter.ToAVMVersionPath(newParentRef); - if (dst.getFirst() >= 0) - { - throw new InvalidNodeRefException("Read Only Store.", newParentRef); - } - String dstParent = dst.getSecond(); - String dstName = assocQName.getLocalName(); - // TODO Invoke policy behavior. Not quite sure how to translate this. -// NodeRef oldParentRef = AVMNodeConverter.ToNodeRef(-1, srcParent); -// ChildAssociationRef oldAssocRef = -// new ChildAssociationRef(assocTypeQName, -// oldParentRef, -// QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, srcName), -// nodeToMoveRef, -// true, -// -1); -// invokeBeforeDeleteChildAssociation(oldAssocRef); - String dstPath = AVMNodeConverter.ExtendAVMPath(dstParent, dstName); - NodeRef newChildRef = AVMNodeConverter.ToNodeRef(-1, dstPath); -// invokeBeforeCreateChildAssociation(newParentRef, newChildRef, assocTypeQName, assocQName); -// invokeBeforeUpdateNode(oldParentRef); -// invokeBeforeUpdateNode(newParentRef); - // Actually perform the rename and return a pseudo - // ChildAssociationRef. - try - { - fAVMService.rename(srcParent, srcName, dstParent, dstName); - ChildAssociationRef newAssocRef = - new ChildAssociationRef(assocTypeQName, - newParentRef, - assocQName, - newChildRef, - true, - -1); -// invokeOnCreateChildAssociation(newAssocRef); -// invokeOnDeleteChildAssociation(oldAssocRef); -// invokeOnUpdateNode(oldParentRef); -// invokeOnUpdateNode(newParentRef); - return newAssocRef; - } - catch (AVMNotFoundException e) - { - throw new InvalidNodeRefException("Non existent node.", nodeToMoveRef); - } - catch (AVMExistsException e) - { - throw new InvalidNodeRefException("Target already exists.", newParentRef); - } - catch (AVMException e) - { - throw new InvalidNodeRefException("Illegal move.", nodeToMoveRef); - } - } - - /** - * Set the ordering index of the child association. This affects the ordering of - * of the return values of methods that return a set of children or child - * associations. - * - * @param childAssocRef the child association that must be moved in the order - * @param index an arbitrary index that will affect the return order - * - * @see #getChildAssocs(NodeRef) - * @see #getChildAssocs(NodeRef, QNamePattern, QNamePattern) - * @see ChildAssociationRef#getNthSibling() - */ - public void setChildAssociationIndex( - ChildAssociationRef childAssocRef, - int index) - throws InvalidChildAssociationRefException - { - // TODO We'll keep this a no-op unless there's a - // compelling reason to implement this capability - // for the AVM repository. - } - - /** - * @param nodeRef - * @return Returns the type name - * @throws InvalidNodeRefException if the node could not be found - * - * @see org.alfresco.service.cmr.dictionary.DictionaryService - */ - public QName getType(NodeRef nodeRef) throws InvalidNodeRefException - { - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - AVMNodeDescriptor desc = fAVMService.lookup(avmVersionPath.getFirst(), - avmVersionPath.getSecond()); - if (desc == null) - { - throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); - } - if (desc.isPlainDirectory()) - { - return WCMModel.TYPE_AVM_PLAIN_FOLDER; - } - else if (desc.isPlainFile()) - { - return WCMModel.TYPE_AVM_PLAIN_CONTENT; - } - else if (desc.isLayeredDirectory()) - { - return WCMModel.TYPE_AVM_LAYERED_FOLDER; - } - else - { - return WCMModel.TYPE_AVM_LAYERED_CONTENT; - } - } - - /** - * Re-sets the type of the node. Can be called in order specialise a node to a sub-type. - * - * This should be used with caution since calling it changes the type of the node and thus - * implies a different set of aspects, properties and associations. It is the calling codes - * responsibility to ensure that the node is in a approriate state after changing the type. - * - * @param nodeRef the node reference - * @param typeQName the type QName - * - * @since 1.1 - */ - public void setType(NodeRef nodeRef, QName typeQName) throws InvalidNodeRefException - { - throw new UnsupportedOperationException("AVM Types are immutable."); - } - - /** - * Applies an aspect to the given node. After this method has been called, - * the node with have all the aspect-related properties present - * - * @param nodeRef - * @param aspectTypeQName the aspect to apply to the node - * @param aspectProperties a minimum of the mandatory properties required for - * the aspect - * @throws InvalidNodeRefException - * @throws InvalidAspectException if the class reference is not to a valid aspect - * - * @see org.alfresco.service.cmr.dictionary.DictionaryService#getAspect(QName) - * @see org.alfresco.service.cmr.dictionary.ClassDefinition#getProperties() - */ - public void addAspect( - NodeRef nodeRef, - QName aspectTypeQName, - Map aspectProperties) - throws InvalidNodeRefException, InvalidAspectException - { - // Check that the aspect exists. - AspectDefinition aspectDef = this.dictionaryService.getAspect(aspectTypeQName); - if (aspectDef == null) - { - throw new InvalidAspectException("The aspect is invalid: " + aspectTypeQName, - aspectTypeQName); - } - // Invoke policy behaviors. -// invokeBeforeUpdateNode(nodeRef); -// invokeBeforeAddAspect(nodeRef, aspectTypeQName); - // Crack the nodeRef. - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - int version = avmVersionPath.getFirst(); - if (version >= 0) - { - throw new InvalidNodeRefException("Read Only node.", nodeRef); - } - String avmPath = avmVersionPath.getSecond(); - // Accumulate properties. - Map properties = new HashMap(); - // Add the supplied properties. - if (aspectProperties != null) - { - properties.putAll(aspectProperties); - } - // Now set any unspecified default properties for the aspect. - Map defaultProperties = getDefaultProperties(aspectDef); - properties.putAll(defaultProperties); - // Now add any cascading aspects. - addDefaultAspects(aspectDef, avmPath, properties); - // Set the property values on the AVM Node. - if (properties.size() != 0) - { - Map props = new HashMap(); - for (Map.Entry entry : properties.entrySet()) - { - QName propertyQName = entry.getKey(); - if (isBuiltInProperty(propertyQName)) - { - continue; - } - Serializable value = entry.getValue(); - PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); - PropertyValue propertyValue = makePropertyValue(propertyDef, value); - props.put(propertyQName, propertyValue); - } - if (props.size() != 0) - { - fAVMService.setNodeProperties(avmPath, props); - } - } - if (isBuiltinAspect(aspectTypeQName)) - { - // No more work to do in this case. - return; - } - try - { - fAVMService.addAspect(avmPath, aspectTypeQName); - // Invoke policy behaviors. -// invokeOnUpdateNode(nodeRef); -// invokeOnAddAspect(nodeRef, aspectTypeQName); - } - catch (AVMNotFoundException e) - { - throw new InvalidNodeRefException(nodeRef); - } - } - - /** - * Add any aspects that are mandatory for the ClassDefinition. - * @param classDef The ClassDefinition. - * @param path The path to the AVMNode. - * @param properties The in/out map of accumulated properties. - */ - private void addDefaultAspects(ClassDefinition classDef, String path, - Map properties) - { - NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, path); - // Get mandatory aspects. - List defaultAspectDefs = classDef.getDefaultAspects(); - // add all the aspects (and there dependent aspects recursively). - for (AspectDefinition def : defaultAspectDefs) - { -// invokeBeforeAddAspect(nodeRef, def.getName()); - addAspect(nodeRef, def.getName(), Collections.emptyMap()); - properties.putAll(getDefaultProperties(def)); -// invokeOnAddAspect(nodeRef, def.getName()); - // recurse - addDefaultAspects(def, path, properties); - } - } - - /** - * Remove an aspect and all related properties from a node - * - * @param nodeRef - * @param aspectTypeQName the type of aspect to remove - * @throws InvalidNodeRefException if the node could not be found - * @throws InvalidAspectException if the the aspect is unknown or if the - * aspect is mandatory for the class of the node - */ - public void removeAspect(NodeRef nodeRef, QName aspectTypeQName) - throws InvalidNodeRefException, InvalidAspectException - { - // Invoke policy behaviors. -// invokeBeforeUpdateNode(nodeRef); -// invokeBeforeRemoveAspect(nodeRef, aspectTypeQName); - AspectDefinition def = dictionaryService.getAspect(aspectTypeQName); - if (def == null) - { - throw new InvalidAspectException(aspectTypeQName); - } - if (isBuiltinAspect(aspectTypeQName)) - { - // TODO shouldn't we be throwing some kind of exception here. - return; - } - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - int version = avmVersionPath.getFirst(); - if (version >= 0) - { - throw new InvalidNodeRefException("Read Only Node.", nodeRef); - } - String path = avmVersionPath.getSecond(); - try - { - if (fAVMService.hasAspect(-1, path, aspectTypeQName)) - { - fAVMService.removeAspect(path, aspectTypeQName); - Map propDefs = def.getProperties(); - for (QName propertyName : propDefs.keySet()) - { - fAVMService.deleteNodeProperty(path, propertyName); - } - } - // Invoke policy behaviors. -// invokeOnUpdateNode(nodeRef); -// invokeOnRemoveAspect(nodeRef, aspectTypeQName); - } - catch (AVMNotFoundException e) - { - throw new InvalidNodeRefException(nodeRef); - } - } - - /** - * Determines if a given aspect is present on a node. Aspects may only be - * removed if they are NOT mandatory. - * - * @param nodeRef - * @param aspectTypeQName - * @return Returns true if the aspect has been applied to the given node, - * otherwise false - * @throws InvalidNodeRefException if the node could not be found - * @throws InvalidAspectException if the aspect reference is invalid - */ - public boolean hasAspect(NodeRef nodeRef, QName aspectTypeQName) - throws InvalidNodeRefException, InvalidAspectException - { - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - int version = avmVersionPath.getFirst(); - String path = avmVersionPath.getSecond(); - if (isBuiltinAspect(aspectTypeQName)) - { - return true; - } - return fAVMService.hasAspect(version, path, aspectTypeQName); - } - - private static QName [] fgBuiltinAspects = new QName[] { ContentModel.ASPECT_AUDITABLE, - ContentModel.ASPECT_REFERENCEABLE }; - - private boolean isBuiltinAspect(QName aspectQName) - { - for (QName builtin : fgBuiltinAspects) - { - if (builtin.equals(aspectQName)) - { - return true; - } - } - return false; - } - - /** - * @param nodeRef - * @return Returns a set of all aspects applied to the node, including mandatory - * aspects - * @throws InvalidNodeRefException if the node could not be found - */ - public Set getAspects(NodeRef nodeRef) throws InvalidNodeRefException - { - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - int version = avmVersionPath.getFirst(); - String path = avmVersionPath.getSecond(); - Set result = new HashSet(); - // Add the builtin ones. - for (QName name : fgBuiltinAspects) - { - result.add(name); - } - try - { - for (QName name : fAVMService.getAspects(version, path)) - { - result.add(name); - } - return result; - } - catch (AVMNotFoundException e) - { - throw new InvalidNodeRefException(nodeRef); - } - } - - /** - * Deletes the given node. - *

- * All associations (both children and regular node associations) - * will be deleted, and where the given node is the primary parent, - * the children will also be cascade deleted. - * - * @param nodeRef reference to a node within a store - * @throws InvalidNodeRefException if the reference given is invalid - */ - public void deleteNode(NodeRef nodeRef) throws InvalidNodeRefException - { - // Invoke policy behaviors. -// invokeBeforeDeleteNode(nodeRef); - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - if (avmVersionPath.getFirst() != -1) - { - throw new InvalidNodeRefException("Read only store.", nodeRef); - } - String [] avmPathBase = AVMNodeConverter.SplitBase(avmVersionPath.getSecond()); - if (avmPathBase[0] == null) - { - throw new InvalidNodeRefException("Cannot delete root node.", nodeRef); - } - try - { -// QName nodeTypeQName = getType(nodeRef); -// Set aspects = getAspects(nodeRef); - fAVMService.removeNode(avmPathBase[0], avmPathBase[1]); -// ChildAssociationRef childAssocRef = -// new ChildAssociationRef(ContentModel.ASSOC_CHILDREN, -// AVMNodeConverter.ToNodeRef(-1, avmPathBase[0]), -// QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, -// avmPathBase[1]), -// nodeRef); -// invokeOnDeleteNode(childAssocRef, nodeTypeQName, aspects, false); - } - catch (AVMNotFoundException e) - { - throw new InvalidNodeRefException(avmVersionPath.getSecond() +" not found.", nodeRef); - } - } - - /** - * Makes a parent-child association between the given nodes. Both nodes must belong to the same store. - *

- * - * @param parentRef - * @param childRef - * @param assocTypeQName the qualified name of the association type as defined in the datadictionary - * @param qname the qualified name of the association - * @return Returns a reference to the newly created child association - * @throws InvalidNodeRefException if the parent or child nodes could not be found - * @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add - */ - public ChildAssociationRef addChild( - NodeRef parentRef, - NodeRef childRef, - QName assocTypeQName, - QName qname) throws InvalidNodeRefException - { - return addChild(Collections.singletonList(parentRef), childRef, assocTypeQName, qname).get(0); - } - - /** - * Associates a given child node with a given collection of parents. All nodes must belong to the same store. - *

- * - * - * @param parentRefs - * @param childRef - * @param assocTypeQName the qualified name of the association type as defined in the datadictionary - * @param qname the qualified name of the association - * @return Returns a reference to the newly created child association - * @throws InvalidNodeRefException if the parent or child nodes could not be found - * @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add - */ - public List addChild( - Collection parentRefs, - NodeRef childRef, - QName assocTypeQName, - QName qname) throws InvalidNodeRefException - { - Pair childVersionPath = AVMNodeConverter.ToAVMVersionPath(childRef); - AVMNodeDescriptor child = fAVMService.lookup(childVersionPath.getFirst(), - childVersionPath.getSecond()); - if (child == null) - { - throw new InvalidNodeRefException(childVersionPath.getSecond() + " not found.", childRef); - } - - List childAssociationRefs = new ArrayList(parentRefs.size()); - for (NodeRef parentRef : parentRefs) - { - Pair parentVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef); - if (parentVersionPath.getFirst() >= 0) - { - throw new InvalidNodeRefException("Read Only.", parentRef); - } - try - { - fAVMService.link(parentVersionPath.getSecond(), qname.getLocalName(), child); - ChildAssociationRef newChild = new ChildAssociationRef(assocTypeQName, parentRef, qname, - AVMNodeConverter.ToNodeRef(-1, AVMNodeConverter.ExtendAVMPath(parentVersionPath.getSecond(), - qname.getLocalName()))); - childAssociationRefs.add(newChild); - } - catch (AVMException e) - { - throw new InvalidNodeRefException("Could not link.", childRef); - } - } - return childAssociationRefs; - } - - /** - * Severs all parent-child relationships between two nodes. - *

- * The child node will be cascade deleted if one of the associations was the - * primary association, i.e. the one with which the child node was created. - * - * @param parentRef the parent end of the association - * @param childRef the child end of the association - * @throws InvalidNodeRefException if the parent or child nodes could not be found - */ - public void removeChild(NodeRef parentRef, NodeRef childRef) throws InvalidNodeRefException - { - Pair parentVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef); - if (parentVersionPath.getFirst() >= 0) - { - throw new InvalidNodeRefException("Read only store.", parentRef); - } - Pair childVersionPath = AVMNodeConverter.ToAVMVersionPath(childRef); - if (childVersionPath.getFirst() >= 0) - { - throw new InvalidNodeRefException("Read only store.", childRef); - } - String parentPath = parentVersionPath.getSecond(); - String childPath = childVersionPath.getSecond(); - String [] childPathBase = AVMNodeConverter.SplitBase(childPath); - if (childPathBase[0] == null || !childPathBase[0].equals(parentPath)) - { - throw new InvalidNodeRefException(childPath + " not a child of " + parentPath, childRef); - } - try - { -// ChildAssociationRef assocRef = -// new ChildAssociationRef(ContentModel.ASSOC_CHILDREN, -// AVMNodeConverter.ToNodeRef(-1, parentPath), -// QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, -// childPathBase[1]), -// AVMNodeConverter.ToNodeRef(-1, childPath)); -// invokeBeforeDeleteChildAssociation(assocRef); - fAVMService.removeNode(childPathBase[0], childPathBase[1]); -// invokeOnDeleteChildAssociation(assocRef); -// invokeOnUpdateNode(AVMNodeConverter.ToNodeRef(-1, parentPath)); - } - catch (AVMNotFoundException e) - { - throw new InvalidNodeRefException(childPathBase[1] + " not found in " + childPathBase[0], - childRef); - } - } - - /** - * TODO: Check implementation - */ - public boolean removeChildAssociation(ChildAssociationRef childAssocRef) - { - NodeRef parentRef = childAssocRef.getParentRef(); - NodeRef childRef = childAssocRef.getChildRef(); - Pair parentVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef); - if (parentVersionPath.getFirst() >= 0) - { - throw new InvalidNodeRefException("Read only store.", parentRef); - } - Pair childVersionPath = AVMNodeConverter.ToAVMVersionPath(childRef); - if (childVersionPath.getFirst() >= 0) - { - throw new InvalidNodeRefException("Read only store.", childRef); - } - String parentPath = parentVersionPath.getSecond(); - String childPath = childVersionPath.getSecond(); - String [] childPathBase = AVMNodeConverter.SplitBase(childPath); - if (childPathBase[0] == null || !childPathBase[0].equals(parentPath)) - { - return false; - } - try - { - fAVMService.removeNode(childPathBase[0], childPathBase[1]); - return true; - } - catch (AVMNotFoundException e) - { - throw new InvalidNodeRefException("Not found.", childRef); - } - } - - /** - * TODO: Implement - */ - public boolean removeSeconaryChildAssociation(ChildAssociationRef childAssocRef) - { - throw new UnsupportedOperationException(); - } - - /** - * @param nodeRef - * @return Returns all properties keyed by their qualified name - * @throws InvalidNodeRefException if the node could not be found - */ - public Map getProperties(NodeRef nodeRef) throws InvalidNodeRefException - { - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - Map props = null; - AVMNodeDescriptor desc = fAVMService.lookup(avmVersionPath.getFirst(), - avmVersionPath.getSecond()); - try - { - props = fAVMService.getNodeProperties(avmVersionPath.getFirst(), - avmVersionPath.getSecond()); - } - catch (AVMNotFoundException e) - { - throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); - } - Map result = new HashMap(); - for (QName qName : props.keySet()) - { - PropertyValue value = props.get(qName); - PropertyDefinition def = dictionaryService.getProperty(qName); - result.put(qName, makeSerializableValue(def, value)); - } - // Now spoof properties that are built in. - result.put(ContentModel.PROP_CREATED, new Date(desc.getCreateDate())); - result.put(ContentModel.PROP_CREATOR, desc.getCreator()); - result.put(ContentModel.PROP_MODIFIED, new Date(desc.getModDate())); - result.put(ContentModel.PROP_MODIFIER, desc.getLastModifier()); - result.put(ContentModel.PROP_OWNER, desc.getOwner()); - result.put(ContentModel.PROP_NAME, desc.getName()); - result.put(ContentModel.PROP_NODE_UUID, "UNKNOWN"); - result.put(ContentModel.PROP_NODE_DBID, new Long(desc.getId())); - result.put(ContentModel.PROP_STORE_PROTOCOL, "avm"); - result.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier()); - if (desc.isLayeredDirectory()) - { - result.put(WCMModel.PROP_AVM_DIR_INDIRECTION, - AVMNodeConverter.ToNodeRef(-1, desc.getIndirection())); - } - if (desc.isLayeredFile()) - { - result.put(WCMModel.PROP_AVM_FILE_INDIRECTION, - AVMNodeConverter.ToNodeRef(-1, desc.getIndirection())); - } - if (desc.isFile()) - { - try - { - ContentData contentData = fAVMService.getContentDataForRead(avmVersionPath.getFirst(), - avmVersionPath.getSecond()); - result.put(ContentModel.PROP_CONTENT, contentData); - } - catch (AVMException e) - { - // TODO For now ignore. - } - } - return result; - } - - /** - * @param nodeRef - * @param qname the qualified name of the property - * @return Returns the value of the property, or null if not yet set - * @throws InvalidNodeRefException if the node could not be found - */ - public Serializable getProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException - { - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - if (isBuiltInProperty(qname)) - { - return getBuiltInProperty(avmVersionPath, qname, nodeRef); - } - try - { - PropertyValue value = fAVMService.getNodeProperty(avmVersionPath.getFirst(), - avmVersionPath.getSecond(), - qname); - if (value == null) - { - return null; - } - PropertyDefinition def = this.dictionaryService.getProperty(qname); - return makeSerializableValue(def, value); - } - catch (AVMNotFoundException e) - { - throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); - } - } - - /** - * {@inheritDoc} - */ - public void removeProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException - { - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - if (isBuiltInProperty(qname)) - { - // Ignore - return; - } - try - { - fAVMService.deleteNodeProperty(avmVersionPath.getSecond(), qname); - } - catch (AVMNotFoundException e) - { - throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); - } - } - - /** - * A Helper to spoof built in properties. - * @param avmVersionPath The broken out version and path from a NodeRef. - * @param qName The name of the property to retrieve. - * @param nodeRef The original NodeRef (for error reporting). - * @return The property value. - */ - private Serializable getBuiltInProperty(Pair avmVersionPath, - QName qName, - NodeRef nodeRef) - { - if (qName.equals(ContentModel.PROP_CONTENT)) - { - try - { - ContentData contentData = - fAVMService.getContentDataForRead(avmVersionPath.getFirst(), - avmVersionPath.getSecond()); - return contentData; - } - catch (AVMException e) - { - // TODO This seems very wrong. Do something better - // sooner rather than later. - return null; - } - } - AVMNodeDescriptor desc = fAVMService.lookup(avmVersionPath.getFirst(), - avmVersionPath.getSecond()); - if (desc == null) - { - throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); - } - if (qName.equals(ContentModel.PROP_CREATED)) - { - return new Date(desc.getCreateDate()); - } - else if (qName.equals(ContentModel.PROP_CREATOR)) - { - return desc.getCreator(); - } - else if (qName.equals(ContentModel.PROP_MODIFIED)) - { - return new Date(desc.getModDate()); - } - else if (qName.equals(ContentModel.PROP_MODIFIER)) - { - return desc.getLastModifier(); - } - else if (qName.equals(ContentModel.PROP_OWNER)) - { - return desc.getOwner(); - } - else if (qName.equals(ContentModel.PROP_NAME)) - { - return desc.getName(); - } - else if (qName.equals(ContentModel.PROP_NODE_UUID)) - { - return "UNKNOWN"; - } - else if (qName.equals(ContentModel.PROP_NODE_DBID)) - { - return new Long(desc.getId()); - } - else if (qName.equals(ContentModel.PROP_STORE_PROTOCOL)) - { - return "avm"; - } - else if (qName.equals(ContentModel.PROP_STORE_IDENTIFIER)) - { - return nodeRef.getStoreRef().getIdentifier(); - } - else if (qName.equals(WCMModel.PROP_AVM_DIR_INDIRECTION)) - { - if (desc.isLayeredDirectory()) - { - return AVMNodeConverter.ToNodeRef(-1, desc.getIndirection()); - } - return null; - } - else if (qName.equals(WCMModel.PROP_AVM_FILE_INDIRECTION)) - { - if (desc.isLayeredFile()) - { - return AVMNodeConverter.ToNodeRef(-1, desc.getIndirection()); - } - return null; - } - else - { - logger.error("Invalid Built In Property: " + qName); - return null; - } - } - - /** - * Set the values of all properties to be an Serializable instances. - * The properties given must still fulfill the requirements of the class and - * aspects relevant to the node. - *

- * NOTE: Null values are allowed. - * - * @param nodeRef - * @param properties all the properties of the node keyed by their qualified names - * @throws InvalidNodeRefException if the node could not be found - */ - public void setProperties(NodeRef nodeRef, Map properties) throws InvalidNodeRefException - { - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - if (avmVersionPath.getFirst() >= 0) - { - throw new InvalidNodeRefException("Read only store.", nodeRef); - } - // TODO Not sure this try block is necessary. - try - { - // Prepare fr policy invocation. - Map propsBefore = null; - if (fInvokePolicies) - { - propsBefore = getProperties(nodeRef); - } - // Remove all properties - fAVMService.deleteNodeProperties(avmVersionPath.getSecond()); - // Rebuild node properties - Map values = new HashMap(); - for (Map.Entry entry : properties.entrySet()) - { - QName propertyQName = entry.getKey(); - Serializable value = entry.getValue(); - // For AVM nodes is in place. - if (isBuiltInProperty(propertyQName)) - { - if (propertyQName.equals(ContentModel.PROP_CONTENT)) - { - AVMNodeDescriptor desc = fAVMService.lookup(-1, avmVersionPath.getSecond()); - if (desc == null) - { - throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); - } - if (desc.isPlainFile()) - { - fAVMService.setContentData(avmVersionPath.getSecond(), - (ContentData)properties.get(propertyQName)); - } - } - } - PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); - PropertyValue propertyValue = makePropertyValue(propertyDef, value); - values.put(propertyQName, propertyValue); - } - // Finally set node properties - fAVMService.setNodeProperties(avmVersionPath.getSecond(), values); - // Invoke policies - if (fInvokePolicies) - { - Map propsAfter = properties; - invokeOnUpdateProperties(nodeRef, propsBefore, propsAfter); - } - // Invoke policy behaviors. -// invokeOnUpdateNode(nodeRef); -// invokeOnUpdateProperties(nodeRef, oldProps, properties); - } - catch (AVMNotFoundException e) - { - throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); - } - } - - public void addProperties(NodeRef nodeRef, Map properties) - { - // Overwrite the current properties - Map currentProperties = getProperties(nodeRef); - currentProperties.putAll(properties); - setProperties(nodeRef, currentProperties); - } - - static QName [] fgBuiltinProperties = new QName [] - { - ContentModel.PROP_CREATED, - ContentModel.PROP_CREATOR, - ContentModel.PROP_MODIFIED, - ContentModel.PROP_MODIFIER, - ContentModel.PROP_OWNER, - ContentModel.PROP_CONTENT, - ContentModel.PROP_NAME, - ContentModel.PROP_NODE_UUID, - ContentModel.PROP_NODE_DBID, - ContentModel.PROP_STORE_PROTOCOL, - ContentModel.PROP_STORE_IDENTIFIER, - WCMModel.PROP_AVM_FILE_INDIRECTION, - WCMModel.PROP_AVM_DIR_INDIRECTION - }; - - /** - * Helper to distinguish built-in from generic properties. - * @param qName The name of the property to check. - * @return Whether qName is a built-in propety. - */ - private boolean isBuiltInProperty(QName qName) - { - for (QName name : fgBuiltinProperties) - { - if (name.equals(qName)) - { - return true; - } - } - return false; - } - - /** - * Sets the value of a property to be any Serializable instance. - * To remove a property value, use {@link #getProperties(NodeRef)}, remove the - * value and call {@link #setProperties(NodeRef, Map)}. - *

- * NOTE: Null values are allowed. - * - * @param nodeRef - * @param qname the fully qualified name of the property - * @param propertyValue the value of the property - never null - * @throws InvalidNodeRefException if the node could not be found - */ - public void setProperty(NodeRef nodeRef, QName qname, Serializable value) throws InvalidNodeRefException - { - // Invoke policy behaviors. - // invokeBeforeUpdateNode(nodeRef); - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - if (avmVersionPath.getFirst() >= 0) - { - throw new InvalidNodeRefException("Read only store.", nodeRef); - } - - Map propsBefore = null; - if (fInvokePolicies) - { - propsBefore = getProperties(nodeRef); - } - - if (isBuiltInProperty(qname)) - { - if (qname.equals(ContentModel.PROP_CONTENT)) - { - try - { - fAVMService.setContentData(avmVersionPath.getSecond(), (ContentData)value); - if (fInvokePolicies) - { - Map propsAfter = new HashMap(propsBefore); - propsAfter.put(ContentModel.PROP_CONTENT, value); - invokeOnUpdateProperties(nodeRef, propsBefore, propsAfter); - } - } - catch (ClassCastException e) - { - throw new AVMException("Invalid ContentData.", e); - } - } - return; - } - try - { - - PropertyDefinition propertyDef = dictionaryService.getProperty(qname); - PropertyValue propertyValue = makePropertyValue(propertyDef, value); - fAVMService.setNodeProperty(avmVersionPath.getSecond(), qname, propertyValue); - if (fInvokePolicies) - { - Map propsAfter = new HashMap(propsBefore); - propsAfter.put(qname, value); - invokeOnUpdateProperties(nodeRef, propsBefore, propsAfter); - } - // Map propsAfter = getProperties(nodeRef); - // Invoke policy behaviors. - // invokeOnUpdateNode(nodeRef); - // invokeOnUpdateProperties(nodeRef, propsBefore, propsAfter); - } - catch (AVMNotFoundException e) - { - throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); - } - } - - /** - * @param nodeRef the child node - * @return Returns a list of all parent-child associations that exist where the given - * node is the child - * @throws InvalidNodeRefException if the node could not be found - * - * @see #getParentAssocs(NodeRef, QNamePattern, QNamePattern) - */ - public List getParentAssocs(NodeRef nodeRef) throws InvalidNodeRefException - { - // TODO OK, for now we'll simply return the single parent that corresponds - // to the path stuffed in the NodeRef. - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - String path = avmVersionPath.getSecond(); - List result = new ArrayList(); - String [] splitPath = AVMNodeConverter.SplitBase(path); - if (splitPath[0] == null) - { - return result; - } - result.add(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, - AVMNodeConverter.ToNodeRef(avmVersionPath.getFirst(), - splitPath[0]), - QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, - splitPath[1]), - nodeRef, - true, - -1)); - return result; - } - - /** - * Gets all parent associations where the pattern of the association qualified - * name is a match - *

- * The resultant list is ordered by (a) explicit index and (b) association creation time. - * - * @param nodeRef the child node - * @param typeQNamePattern the pattern that the type qualified name of the association must match - * @param qnamePattern the pattern that the qnames of the assocs must match - * @return Returns a list of all parent-child associations that exist where the given - * node is the child - * @throws InvalidNodeRefException if the node could not be found - * - * @see ChildAssociationRef#getNthSibling() - * @see #setChildAssociationIndex(ChildAssociationRef, int) - * @see QName - * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL - */ - public List getParentAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern) - throws InvalidNodeRefException - { - if (!typeQNamePattern.isMatch(ContentModel.ASSOC_CONTAINS)) - { - return new ArrayList(); - } - List result = getParentAssocs(nodeRef); - if (result.size() == 0) - { - return result; - } - if (qnamePattern.isMatch(result.get(0).getQName())) - { - return result; - } - return new ArrayList(); - } - - /** - * Get all child associations of the given node. - *

- * The resultant list is ordered by (a) explicit index and (b) association creation time. - * - * @param nodeRef the parent node - usually a container - * @return Returns a collection of ChildAssocRef instances. If the - * node is not a container then the result will be empty. - * @throws InvalidNodeRefException if the node could not be found - * - * @see #getChildAssocs(NodeRef, QNamePattern, QNamePattern) - * @see #setChildAssociationIndex(ChildAssociationRef, int) - * @see ChildAssociationRef#getNthSibling() - */ - public List getChildAssocs(NodeRef nodeRef) throws InvalidNodeRefException - { - - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - int version = avmVersionPath.getFirst(); - String path = avmVersionPath.getSecond(); - List result = new ArrayList(); - SortedMap children = null; - try - { - children = - fAVMService.getDirectoryListing(version, - path); - } - catch (AVMNotFoundException e) - { - return result; - } - for (String name : children.keySet()) - { - result.add(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, - nodeRef, - QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, - name), - AVMNodeConverter.ToNodeRef( - version, - AVMNodeConverter.ExtendAVMPath(path, name)), - true, - -1)); - } - return result; - } - - /** - * Gets all child associations where the pattern of the association qualified - * name is a match. - * - * @param nodeRef the parent node - usually a container - * @param typeQNamePattern the pattern that the type qualified name of the association must match - * @param qnamePattern the pattern that the qnames of the assocs must match - * @return Returns a list of ChildAssocRef instances. If the - * node is not a container then the result will be empty. - * @throws InvalidNodeRefException if the node could not be found - * - * @see QName - * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL - */ - public List getChildAssocs( - NodeRef nodeRef, - QNamePattern typeQNamePattern, - QNamePattern qnamePattern) - throws InvalidNodeRefException - { - List result = new ArrayList(); - if (!typeQNamePattern.isMatch(ContentModel.ASSOC_CONTAINS)) - { - return result; - } - List all = getChildAssocs(nodeRef); - for (ChildAssociationRef child : all) - { - if (!qnamePattern.isMatch(child.getQName())) - { - continue; - } - result.add(child); - } - return result; - } - - - - public List getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, - QNamePattern qnamePattern, boolean preload) throws InvalidNodeRefException - { - return getChildAssocs(nodeRef, typeQNamePattern, qnamePattern); - } - - public List getChildAssocs(NodeRef nodeRef, Set childNodeTypes) - { - /* - * ETWOTWO-961 forced an implementation, but this is just a workaround. - * We do a listing and then keep files or folders looking specifically - * for cm:folder and cm:content types from childNodeTypes. - */ - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - int version = avmVersionPath.getFirst(); - String path = avmVersionPath.getSecond(); - List result = new ArrayList(); - SortedMap children = null; - try - { - children = - fAVMService.getDirectoryListing(version, - path); - } - catch (AVMNotFoundException e) - { - return result; - } - for (Map.Entry entry : children.entrySet()) - { - String name = entry.getKey(); - AVMNodeDescriptor descriptor = entry.getValue(); - if (descriptor.isFile()) - { - if (!childNodeTypes.contains(ContentModel.TYPE_CONTENT)) - { - continue; - } - } - else if (descriptor.isDirectory()) - { - if (!childNodeTypes.contains(ContentModel.TYPE_FOLDER)) - { - continue; - } - } - else - { - // Not a file or directory??? - continue; - } - result.add(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, - nodeRef, - QName.createQName( - NamespaceService.CONTENT_MODEL_1_0_URI, - name), - AVMNodeConverter.ToNodeRef( - version, - AVMNodeConverter.ExtendAVMPath(path, name)), - true, - -1)); - } - return result; - } - - /** - * getChildrenByName - */ - public List getChildrenByName(NodeRef nodeRef, QName assocTypeQName, Collection childNames) - { - final List results = new ArrayList(100); - - if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS)) - { - throw new UnsupportedOperationException("AVM getChildrenByName only supports ASSOCS_CONTAINS."); - } - - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - try - { - for(String childName : childNames) - { - AVMNodeDescriptor child = fAVMService.lookup(avmVersionPath.getFirst(), - AVMUtil.extendAVMPath(avmVersionPath.getSecond(), childName)); - - if (child != null) - { - NodeRef childRef = AVMNodeConverter.ToNodeRef(avmVersionPath.getFirst(), - child.getPath()); - QName childQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, - childName); - ChildAssociationRef ref = new ChildAssociationRef(assocTypeQName, nodeRef, childQName, childRef); - - if(logger.isDebugEnabled()) - { - logger.debug("got a child node :" + ref); - } - results.add(ref); - } - } - return results; - } - catch (AVMException e) - { - logger.debug("exception in getChildrenByName ", e); - return results; - } - } - - - /** - * Get a child NodeRef by name. - * @param nodeRef The parent node. - * @param assocTypeQName The type of the Child Association. - * @param childName The name of the child to get. - */ - public NodeRef getChildByName(NodeRef nodeRef, QName assocTypeQName, String childName) - { - if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS)) - { - return null; - } - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - try - { - AVMNodeDescriptor child = fAVMService.lookup(avmVersionPath.getFirst(), - AVMUtil.extendAVMPath(avmVersionPath.getSecond(), childName)); - if (child == null) - { - return null; - } - return AVMNodeConverter.ToNodeRef(avmVersionPath.getFirst(), - child.getPath()); - } - catch (AVMException e) - { - return null; - } - } - - /** - * Fetches the primary parent-child relationship. - *

- * For a root node, the parent node reference will be null. - * - * @param nodeRef - * @return Returns the primary parent-child association of the node - * @throws InvalidNodeRefException if the node could not be found - */ - public ChildAssociationRef getPrimaryParent(NodeRef nodeRef) throws InvalidNodeRefException - { - List parents = getParentAssocs(nodeRef); - if (parents.size() == 0) - { - return new ChildAssociationRef(null, null, null, nodeRef); - } - return parents.get(0); - } - - /** - * - * @param sourceRef a reference to a real node - * @param targetRef a reference to a node - * @param assocTypeQName the qualified name of the association type - * @return Returns a reference to the new association - * @throws InvalidNodeRefException if either of the nodes could not be found - * @throws AssociationExistsException - */ - public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) - throws InvalidNodeRefException, AssociationExistsException - { - throw new UnsupportedOperationException("AVM does not support arbitrary associations."); - } - - /** - * - * @param sourceRef the associaton source node - * @param targetRef the association target node - * @param assocTypeQName the qualified name of the association type - * @throws InvalidNodeRefException if either of the nodes could not be found - */ - public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) - throws InvalidNodeRefException - { - throw new UnsupportedOperationException("AVM does not support arbitrary associations."); - } - - /** - * Gets an association by ID. - * - * @param assocId - * the association id - * @return the association, or null if it does not exist - */ - public AssociationRef getAssoc(Long id) - { - return null; - } - - /** - * Fetches all associations from the given source where the associations' - * qualified names match the pattern provided. - * - * @param sourceRef the association source - * @param qnamePattern the association qname pattern to match against - * @return Returns a list of NodeAssocRef instances for which the - * given node is a source - * @throws InvalidNodeRefException if the source node could not be found - * - * @see QName - * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL - */ - public List getTargetAssocs(NodeRef sourceRef, QNamePattern qnamePattern) - throws InvalidNodeRefException - { - return new ArrayList(); - } - - /** - * Fetches all associations to the given target where the associations' - * qualified names match the pattern provided. - * - * @param targetRef the association target - * @param qnamePattern the association qname pattern to match against - * @return Returns a list of NodeAssocRef instances for which the - * given node is a target - * @throws InvalidNodeRefException - * - * @see QName - * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL - */ - public List getSourceAssocs(NodeRef targetRef, QNamePattern qnamePattern) - throws InvalidNodeRefException - { - return new ArrayList(); - } - - /** - * The root node has an entry in the path(s) returned. For this reason, there - * will always be at least one path element in the returned path(s). - * The first element will have a null parent reference and qname. - * - * @param nodeRef - * @return Returns the path to the node along the primary node path - * @throws InvalidNodeRefException if the node could not be found - * - * @see #getPaths(NodeRef, boolean) - */ - public Path getPath(NodeRef nodeRef) throws InvalidNodeRefException - { - // TODO Review later. This may be wrong. - Path path = new Path(); - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - int version = avmVersionPath.getFirst(); - String currPath = avmVersionPath.getSecond(); - while (!currPath.endsWith("/")) - { - String [] splitPath = AVMNodeConverter.SplitBase(currPath); - String parentPath = splitPath[0]; - String name = splitPath[1]; - ChildAssociationRef caRef = - new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, - AVMNodeConverter.ToNodeRef(version, parentPath), - QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, - name), - AVMNodeConverter.ToNodeRef(version, currPath), - true, - -1); - path.prepend(new Path.ChildAssocElement(caRef)); - currPath = parentPath; - } - ChildAssociationRef caRef = new ChildAssociationRef(null, null, null, - AVMNodeConverter.ToNodeRef(version, - currPath)); - path.prepend(new Path.ChildAssocElement(caRef)); - return path; - } - - /** - * The root node has an entry in the path(s) returned. For this reason, there - * will always be at least one path element in the returned path(s). - * The first element will have a null parent reference and qname. - * - * @param nodeRef - * @param primaryOnly true if only the primary path must be retrieved. If true, the - * result will have exactly one entry. - * @return Returns a List of all possible paths to the given node - * @throws InvalidNodeRefException if the node could not be found - */ - public List getPaths(NodeRef nodeRef, boolean primaryOnly) throws InvalidNodeRefException - { - List result = new ArrayList(); - result.add(getPath(nodeRef)); - return result; - } - - /** - * Get the node where archived items will have gone when deleted from the given store. - * - * @param storeRef the store that items were deleted from - * @return Returns the archive node parent - */ - public NodeRef getStoreArchiveNode(StoreRef storeRef) - { - throw new UnsupportedOperationException("AVM does not support this operation."); - } - - /** - * Restore an individual node (along with its sub-tree nodes) to the target location. - * The archived node must have the {@link org.alfresco.model.ContentModel#ASPECT_ARCHIVED archived aspect} - * set against it. - * - * @param archivedNodeRef the archived node - * @param destinationParentNodeRef the parent to move the node into - * or null to use the original - * @param assocTypeQName the primary association type name to use in the new location - * or null to use the original - * @param assocQName the primary association name to use in the new location - * or null to use the original - * @return Returns the reference to the newly created node - */ - public NodeRef restoreNode( - NodeRef archivedNodeRef, - NodeRef destinationParentNodeRef, - QName assocTypeQName, - QName assocQName) - { - throw new UnsupportedOperationException("AVM does not support this operation."); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.repository.NodeService#getChildAssocsWithoutParentAssocsOfType(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName) - */ - public Collection getChildAssocsWithoutParentAssocsOfType(NodeRef parent, QName assocTypeQName) - { - throw new UnsupportedOperationException("AVM does not support this operation."); - } -} +import org.apache.commons.logging.LogFactory; + +/** + * NodeService implementing facade over AVMService. + * @author britt + */ +public class AVMNodeService extends AbstractNodeServiceImpl implements NodeService +{ + private static Log logger = LogFactory.getLog(AVMNodeService.class); + + /** + * Flag for whether policy callbacks are made. + */ + private boolean fInvokePolicies = false; + + /** + * Reference to AVMService. + */ + private AVMService fAVMService; + + /** + * Set the AVMService. For Spring. + * @param service The AVMService instance. + */ + public void setAvmService(AVMService service) + { + fAVMService = service; + } + + /** + * Default constructor. + */ + public AVMNodeService() + { + } + + public void setInvokePolicies(boolean invoke) + { + fInvokePolicies = invoke; + } + + /** + * Helper method to convert the Serializable value into a full, + * persistable {@link PropertyValue}. + *

+ * Where the property definition is null, the value will take on the + * {@link DataTypeDefinition#ANY generic ANY} value. + *

+ * Where the property definition specifies a multi-valued property but the + * value provided is not a collection, the value will be wrapped in a collection. + * + * @param propertyDef the property dictionary definition, may be null + * @param value the value, which will be converted according to the definition - + * may be null + * @return Returns the persistable property value + */ + protected PropertyValue makePropertyValue(PropertyDefinition propertyDef, Serializable value) + { + // get property attributes + QName propertyTypeQName = null; + if (propertyDef == null) // property not recognised + { + // allow it for now - persisting excess properties can be useful sometimes + propertyTypeQName = DataTypeDefinition.ANY; + } + else + { + propertyTypeQName = propertyDef.getDataType().getName(); + // check that multi-valued properties are allowed + boolean isMultiValued = propertyDef.isMultiValued(); + if (isMultiValued && !(value instanceof Collection)) + { + if (value != null) + { + // put the value into a collection + // the implementation gives back a Serializable list + value = (Serializable) Collections.singletonList(value); + } + } + else if (!isMultiValued && (value instanceof Collection)) + { + // we only allow this case if the property type is ANY + if (!propertyTypeQName.equals(DataTypeDefinition.ANY)) + { + throw new DictionaryException( + "A single-valued property of this type may not be a collection: \n" + + " Property: " + propertyDef + "\n" + + " Type: " + propertyTypeQName + "\n" + + " Value: " + value); + } + } + } + try + { + PropertyValue propertyValue = new PropertyValue(propertyTypeQName, value); + // done + return propertyValue; + } + catch (TypeConversionException e) + { + throw new TypeConversionException( + "The property value is not compatible with the type defined for the property: \n" + + " property: " + (propertyDef == null ? "unknown" : propertyDef) + "\n" + + " value: " + value + "\n" + + " value type: " + value.getClass(), + e); + } + } + + /** + * Extracts the externally-visible property from the {@link PropertyValue propertyValue}. + * + * @param propertyDef the model property definition - may be null + * @param propertyValue the persisted property + * @return Returns the value of the property in the format dictated by the property + * definition, or null if the property value is null + */ + protected Serializable makeSerializableValue(PropertyDefinition propertyDef, PropertyValue propertyValue) + { + if (propertyValue == null) + { + return null; + } + // get property attributes + QName propertyTypeQName = null; + if (propertyDef == null) + { + // allow this for now + propertyTypeQName = DataTypeDefinition.ANY; + } + else + { + propertyTypeQName = propertyDef.getDataType().getName(); + } + try + { + Serializable value = propertyValue.getValue(propertyTypeQName); + // done + return value; + } + catch (TypeConversionException e) + { + throw new TypeConversionException( + "The property value is not compatible with the type defined for the property: \n" + + " property: " + (propertyDef == null ? "unknown" : propertyDef) + "\n" + + " property value: " + propertyValue, + e); + } + } + + /** + * Gets a list of all available node store references + * + * @return Returns a list of store references + */ + public List getStores() + { + // For AVM stores we fake up StoreRefs. + List stores = fAVMService.getStores(); + List result = new ArrayList(); + for (AVMStoreDescriptor desc : stores) + { + String name = desc.getName(); + result.add(new StoreRef(StoreRef.PROTOCOL_AVM, name)); + } + return result; + } + + /** + * Create a new AVM store. + * @param protocol the implementation protocol + * @param identifier the protocol-specific identifier + * @return Returns a reference to the store + * @throws StoreExistsException + */ + public StoreRef createStore(String protocol, String identifier) throws StoreExistsException + { + StoreRef result = new StoreRef(StoreRef.PROTOCOL_AVM, identifier); + // invokeBeforeCreateStore(ContentModel.TYPE_STOREROOT, result); + try + { + fAVMService.createStore(identifier); + NodeRef rootRef = getRootNode(result); + addAspect(rootRef, ContentModel.ASPECT_ROOT, + Collections.emptyMap()); + // invokeOnCreateStore(rootRef); + return result; + } + catch (AVMExistsException e) + { + throw new StoreExistsException(result, e); + } + } + + /** + * @throws UnsupportedOperationException Always + */ + public void deleteStore(StoreRef storeRef) throws InvalidStoreRefException + { + throw new UnsupportedOperationException(); + } + + /** + * Does the indicated store exist? + * @param storeRef a reference to the store to look for + * @return Returns true if the store exists, otherwise false + */ + public boolean exists(StoreRef storeRef) + { + return fAVMService.getStore(storeRef.getIdentifier()) != null; + } + + /** + * @param nodeRef a reference to the node to look for + * @return Returns true if the node exists, otherwise false + */ + public boolean exists(NodeRef nodeRef) + { + Pair avmInfo = AVMNodeConverter.ToAVMVersionPath(nodeRef); + int version = avmInfo.getFirst(); + String avmPath = avmInfo.getSecond(); + return fAVMService.lookup(version, avmPath) != null; + } + + /** + * Gets the ID of the last transaction that caused the node to change. This includes + * deletions, so it is possible that the node being referenced no longer exists. + * If the node never existed, then null is returned. + * + * @param nodeRef a reference to a current or previously existing node + * @return Returns the status of the node, or null if the node never existed + */ + public NodeRef.Status getNodeStatus(NodeRef nodeRef) + { + // TODO Need to find out if this is important and if so + // need to capture Transaction IDs. + return new NodeRef.Status("Unknown", null, !exists(nodeRef)); + } + + /** + * @param storeRef a reference to an existing store + * @return Returns a reference to the root node of the store + * @throws InvalidStoreRefException if the store could not be found + */ + public NodeRef getRootNode(StoreRef storeRef) throws InvalidStoreRefException + { + String storeName = storeRef.getIdentifier(); + if (fAVMService.getStore(storeName) != null) + { + return AVMNodeConverter.ToNodeRef(-1, storeName + ":/"); + } + else + { + throw new InvalidStoreRefException(storeName +":/" + " not found.", storeRef); + } + } + + /** + * @see #createNode(NodeRef, QName, QName, QName, Map) + */ + public ChildAssociationRef createNode( + NodeRef parentRef, + QName assocTypeQName, + QName assocQName, + QName nodeTypeQName) + throws InvalidNodeRefException, InvalidTypeException + { + return createNode(parentRef, + assocTypeQName, + assocQName, + nodeTypeQName, + new HashMap()); + } + + /** + * Creates a new, non-abstract, real node as a primary child of the given parent node. + * + * @param parentRef the parent node + * @param assocTypeQName the type of the association to create. This is used + * for verification against the data dictionary. + * @param assocQName the qualified name of the association + * @param nodeTypeQName a reference to the node type + * @param properties optional map of properties to keyed by their qualified names + * @return Returns a reference to the newly created child association + * @throws InvalidNodeRefException if the parent reference is invalid + * @throws InvalidTypeException if the node type reference is not recognised + * + * @see org.alfresco.service.cmr.dictionary.DictionaryService + */ + public ChildAssociationRef createNode( + NodeRef parentRef, + QName assocTypeQName, + QName assocQName, + QName nodeTypeQName, + Map properties) + throws InvalidNodeRefException, InvalidTypeException + { + // AVM stores only allow simple child associations. + if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS)) + { + throw new InvalidTypeException(assocTypeQName); + } + String nodeName = assocQName.getLocalName(); + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef); + int version = avmVersionPath.getFirst(); + if (version >= 0) + { + throw new InvalidNodeRefException("Read only store.", parentRef); + } + String avmPath = avmVersionPath.getSecond(); + // Invoke policy behavior. + // invokeBeforeUpdateNode(parentRef); + // invokeBeforeCreateNode(parentRef, assocTypeQName, assocQName, nodeTypeQName); + // Look up the type definition in the dictionary. + TypeDefinition nodeTypeDef = dictionaryService.getType(nodeTypeQName); + // Do the creates for supported types, or error out. + try + { + if (nodeTypeQName.equals(WCMModel.TYPE_AVM_PLAIN_FOLDER) || + nodeTypeQName.equals(ContentModel.TYPE_FOLDER)) + { + fAVMService.createDirectory(avmPath, nodeName); + } + else if (nodeTypeQName.equals(WCMModel.TYPE_AVM_PLAIN_CONTENT) || + nodeTypeQName.equals(ContentModel.TYPE_CONTENT)) + { + fAVMService.createFile(avmPath, nodeName); + } + else if (nodeTypeQName.equals(WCMModel.TYPE_AVM_LAYERED_CONTENT)) + { + NodeRef indirection = (NodeRef)properties.get(WCMModel.PROP_AVM_FILE_INDIRECTION); + if (indirection == null) + { + throw new InvalidTypeException("No Indirection Property", nodeTypeQName); + } + Pair indVersionPath = AVMNodeConverter.ToAVMVersionPath(indirection); + fAVMService.createLayeredFile(indVersionPath.getSecond(), avmPath, nodeName); + } + else if (nodeTypeQName.equals(WCMModel.TYPE_AVM_LAYERED_FOLDER)) + { + NodeRef indirection = (NodeRef)properties.get(WCMModel.PROP_AVM_DIR_INDIRECTION); + if (indirection == null) + { + throw new InvalidTypeException("No Indirection Property.", nodeTypeQName); + } + Pair indVersionPath = AVMNodeConverter.ToAVMVersionPath(indirection); + fAVMService.createLayeredDirectory(indVersionPath.getSecond(), avmPath, nodeName); + } + else + { + throw new InvalidTypeException("Invalid node type for AVM.", nodeTypeQName); + } + properties.putAll(getDefaultProperties(nodeTypeDef)); + addDefaultAspects(nodeTypeDef, avmPath, properties); + } + catch (AVMNotFoundException e) + { + throw new InvalidNodeRefException(avmPath + " not found.", parentRef); + } + catch (AVMExistsException e) + { + throw new InvalidNodeRefException("Child " + nodeName + " exists", parentRef); + } + String newAVMPath = AVMNodeConverter.ExtendAVMPath(avmPath, nodeName); + NodeRef childRef = AVMNodeConverter.ToNodeRef(-1, newAVMPath); + properties.putAll(getDefaultProperties(nodeTypeDef)); + addDefaultAspects(nodeTypeDef, newAVMPath, properties); + Map props = new HashMap(); + for (Map.Entry entry : properties.entrySet()) + { + QName propertyQName = entry.getKey(); + if (isBuiltInProperty(propertyQName)) + { + continue; + } + Serializable value = entry.getValue(); + PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); + PropertyValue propertyValue = makePropertyValue(propertyDef, value); + props.put(propertyQName, propertyValue); + } + fAVMService.setNodeProperties(newAVMPath, props); + ChildAssociationRef ref = + new ChildAssociationRef(assocTypeQName, + parentRef, + assocQName, + childRef, + true, + -1); +// invokeOnCreateNode(ref); +// invokeOnUpdateNode(parentRef); +// if (properties.size() != 0) +// { +// invokeOnUpdateProperties(childRef, new HashMap(), properties); +// } + return ref; + } + + /** + * Moves the primary location of the given node. + *

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

+ * If the new parent is in a different store from the original, then the entire + * node hierarchy is moved to the new store. Inter-store associations are not + * affected. + * + * @param nodeToMoveRef the node to move + * @param newParentRef the new parent of the moved node + * @param assocTypeQName the type of the association to create. This is used + * for verification against the data dictionary. + * @param assocQName the qualified name of the new child association + * @return Returns a reference to the newly created child association + * @throws InvalidNodeRefException if either the parent node or move node reference is invalid + * @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add + * + * @see #getPrimaryParent(NodeRef) + */ + public ChildAssociationRef moveNode( + NodeRef nodeToMoveRef, + NodeRef newParentRef, + QName assocTypeQName, + QName assocQName) + throws InvalidNodeRefException + { + // AVM stores only allow simple child associations. + if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS)) + { + throw new InvalidTypeException(assocTypeQName); + } + // Extract the parts from the source. + Pair src = AVMNodeConverter.ToAVMVersionPath(nodeToMoveRef); + int srcVersion = src.getFirst(); + if (srcVersion >= 0) + { + throw new InvalidNodeRefException("Read Only Store.", nodeToMoveRef); + } + String srcPath = src.getSecond(); + String [] splitSrc = null; + try + { + splitSrc = AVMNodeConverter.SplitBase(srcPath); + } + catch (AVMException e) + { + throw new InvalidNodeRefException("Invalid src path.", nodeToMoveRef); + } + String srcParent = splitSrc[0]; + if (srcParent == null) + { + throw new InvalidNodeRefException("Cannot rename root node.", nodeToMoveRef); + } + String srcName = splitSrc[1]; + // Extract and setup the parts of the destination. + Pair dst = AVMNodeConverter.ToAVMVersionPath(newParentRef); + if (dst.getFirst() >= 0) + { + throw new InvalidNodeRefException("Read Only Store.", newParentRef); + } + String dstParent = dst.getSecond(); + String dstName = assocQName.getLocalName(); + // TODO Invoke policy behavior. Not quite sure how to translate this. +// NodeRef oldParentRef = AVMNodeConverter.ToNodeRef(-1, srcParent); +// ChildAssociationRef oldAssocRef = +// new ChildAssociationRef(assocTypeQName, +// oldParentRef, +// QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, srcName), +// nodeToMoveRef, +// true, +// -1); +// invokeBeforeDeleteChildAssociation(oldAssocRef); + String dstPath = AVMNodeConverter.ExtendAVMPath(dstParent, dstName); + NodeRef newChildRef = AVMNodeConverter.ToNodeRef(-1, dstPath); +// invokeBeforeCreateChildAssociation(newParentRef, newChildRef, assocTypeQName, assocQName); +// invokeBeforeUpdateNode(oldParentRef); +// invokeBeforeUpdateNode(newParentRef); + // Actually perform the rename and return a pseudo + // ChildAssociationRef. + try + { + fAVMService.rename(srcParent, srcName, dstParent, dstName); + ChildAssociationRef newAssocRef = + new ChildAssociationRef(assocTypeQName, + newParentRef, + assocQName, + newChildRef, + true, + -1); +// invokeOnCreateChildAssociation(newAssocRef); +// invokeOnDeleteChildAssociation(oldAssocRef); +// invokeOnUpdateNode(oldParentRef); +// invokeOnUpdateNode(newParentRef); + return newAssocRef; + } + catch (AVMNotFoundException e) + { + throw new InvalidNodeRefException("Non existent node.", nodeToMoveRef); + } + catch (AVMExistsException e) + { + throw new InvalidNodeRefException("Target already exists.", newParentRef); + } + catch (AVMException e) + { + throw new InvalidNodeRefException("Illegal move.", nodeToMoveRef); + } + } + + /** + * Set the ordering index of the child association. This affects the ordering of + * of the return values of methods that return a set of children or child + * associations. + * + * @param childAssocRef the child association that must be moved in the order + * @param index an arbitrary index that will affect the return order + * + * @see #getChildAssocs(NodeRef) + * @see #getChildAssocs(NodeRef, QNamePattern, QNamePattern) + * @see ChildAssociationRef#getNthSibling() + */ + public void setChildAssociationIndex( + ChildAssociationRef childAssocRef, + int index) + throws InvalidChildAssociationRefException + { + // TODO We'll keep this a no-op unless there's a + // compelling reason to implement this capability + // for the AVM repository. + } + + /** + * @param nodeRef + * @return Returns the type name + * @throws InvalidNodeRefException if the node could not be found + * + * @see org.alfresco.service.cmr.dictionary.DictionaryService + */ + public QName getType(NodeRef nodeRef) throws InvalidNodeRefException + { + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + AVMNodeDescriptor desc = fAVMService.lookup(avmVersionPath.getFirst(), + avmVersionPath.getSecond()); + if (desc == null) + { + throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); + } + if (desc.isPlainDirectory()) + { + return WCMModel.TYPE_AVM_PLAIN_FOLDER; + } + else if (desc.isPlainFile()) + { + return WCMModel.TYPE_AVM_PLAIN_CONTENT; + } + else if (desc.isLayeredDirectory()) + { + return WCMModel.TYPE_AVM_LAYERED_FOLDER; + } + else + { + return WCMModel.TYPE_AVM_LAYERED_CONTENT; + } + } + + /** + * Re-sets the type of the node. Can be called in order specialise a node to a sub-type. + * + * This should be used with caution since calling it changes the type of the node and thus + * implies a different set of aspects, properties and associations. It is the calling codes + * responsibility to ensure that the node is in a approriate state after changing the type. + * + * @param nodeRef the node reference + * @param typeQName the type QName + * + * @since 1.1 + */ + public void setType(NodeRef nodeRef, QName typeQName) throws InvalidNodeRefException + { + throw new UnsupportedOperationException("AVM Types are immutable."); + } + + /** + * Applies an aspect to the given node. After this method has been called, + * the node with have all the aspect-related properties present + * + * @param nodeRef + * @param aspectTypeQName the aspect to apply to the node + * @param aspectProperties a minimum of the mandatory properties required for + * the aspect + * @throws InvalidNodeRefException + * @throws InvalidAspectException if the class reference is not to a valid aspect + * + * @see org.alfresco.service.cmr.dictionary.DictionaryService#getAspect(QName) + * @see org.alfresco.service.cmr.dictionary.ClassDefinition#getProperties() + */ + public void addAspect( + NodeRef nodeRef, + QName aspectTypeQName, + Map aspectProperties) + throws InvalidNodeRefException, InvalidAspectException + { + // Check that the aspect exists. + AspectDefinition aspectDef = this.dictionaryService.getAspect(aspectTypeQName); + if (aspectDef == null) + { + throw new InvalidAspectException("The aspect is invalid: " + aspectTypeQName, + aspectTypeQName); + } + // Invoke policy behaviors. +// invokeBeforeUpdateNode(nodeRef); +// invokeBeforeAddAspect(nodeRef, aspectTypeQName); + // Crack the nodeRef. + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + int version = avmVersionPath.getFirst(); + if (version >= 0) + { + throw new InvalidNodeRefException("Read Only node.", nodeRef); + } + String avmPath = avmVersionPath.getSecond(); + // Accumulate properties. + Map properties = new HashMap(); + // Add the supplied properties. + if (aspectProperties != null) + { + properties.putAll(aspectProperties); + } + // Now set any unspecified default properties for the aspect. + Map defaultProperties = getDefaultProperties(aspectDef); + properties.putAll(defaultProperties); + // Now add any cascading aspects. + addDefaultAspects(aspectDef, avmPath, properties); + // Set the property values on the AVM Node. + if (properties.size() != 0) + { + Map props = new HashMap(); + for (Map.Entry entry : properties.entrySet()) + { + QName propertyQName = entry.getKey(); + if (isBuiltInProperty(propertyQName)) + { + continue; + } + Serializable value = entry.getValue(); + PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); + PropertyValue propertyValue = makePropertyValue(propertyDef, value); + props.put(propertyQName, propertyValue); + } + if (props.size() != 0) + { + fAVMService.setNodeProperties(avmPath, props); + } + } + if (isBuiltinAspect(aspectTypeQName)) + { + // No more work to do in this case. + return; + } + try + { + fAVMService.addAspect(avmPath, aspectTypeQName); + // Invoke policy behaviors. +// invokeOnUpdateNode(nodeRef); +// invokeOnAddAspect(nodeRef, aspectTypeQName); + } + catch (AVMNotFoundException e) + { + throw new InvalidNodeRefException(nodeRef); + } + } + + /** + * Add any aspects that are mandatory for the ClassDefinition. + * @param classDef The ClassDefinition. + * @param path The path to the AVMNode. + * @param properties The in/out map of accumulated properties. + */ + private void addDefaultAspects(ClassDefinition classDef, String path, + Map properties) + { + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, path); + // Get mandatory aspects. + List defaultAspectDefs = classDef.getDefaultAspects(); + // add all the aspects (and there dependent aspects recursively). + for (AspectDefinition def : defaultAspectDefs) + { +// invokeBeforeAddAspect(nodeRef, def.getName()); + addAspect(nodeRef, def.getName(), Collections.emptyMap()); + properties.putAll(getDefaultProperties(def)); +// invokeOnAddAspect(nodeRef, def.getName()); + // recurse + addDefaultAspects(def, path, properties); + } + } + + /** + * Remove an aspect and all related properties from a node + * + * @param nodeRef + * @param aspectTypeQName the type of aspect to remove + * @throws InvalidNodeRefException if the node could not be found + * @throws InvalidAspectException if the the aspect is unknown or if the + * aspect is mandatory for the class of the node + */ + public void removeAspect(NodeRef nodeRef, QName aspectTypeQName) + throws InvalidNodeRefException, InvalidAspectException + { + // Invoke policy behaviors. +// invokeBeforeUpdateNode(nodeRef); +// invokeBeforeRemoveAspect(nodeRef, aspectTypeQName); + AspectDefinition def = dictionaryService.getAspect(aspectTypeQName); + if (def == null) + { + throw new InvalidAspectException(aspectTypeQName); + } + if (isBuiltinAspect(aspectTypeQName)) + { + // TODO shouldn't we be throwing some kind of exception here. + return; + } + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + int version = avmVersionPath.getFirst(); + if (version >= 0) + { + throw new InvalidNodeRefException("Read Only Node.", nodeRef); + } + String path = avmVersionPath.getSecond(); + try + { + if (fAVMService.hasAspect(-1, path, aspectTypeQName)) + { + fAVMService.removeAspect(path, aspectTypeQName); + Map propDefs = def.getProperties(); + for (QName propertyName : propDefs.keySet()) + { + fAVMService.deleteNodeProperty(path, propertyName); + } + } + // Invoke policy behaviors. +// invokeOnUpdateNode(nodeRef); +// invokeOnRemoveAspect(nodeRef, aspectTypeQName); + } + catch (AVMNotFoundException e) + { + throw new InvalidNodeRefException(nodeRef); + } + } + + /** + * Determines if a given aspect is present on a node. Aspects may only be + * removed if they are NOT mandatory. + * + * @param nodeRef + * @param aspectTypeQName + * @return Returns true if the aspect has been applied to the given node, + * otherwise false + * @throws InvalidNodeRefException if the node could not be found + * @throws InvalidAspectException if the aspect reference is invalid + */ + public boolean hasAspect(NodeRef nodeRef, QName aspectTypeQName) + throws InvalidNodeRefException, InvalidAspectException + { + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + int version = avmVersionPath.getFirst(); + String path = avmVersionPath.getSecond(); + if (isBuiltinAspect(aspectTypeQName)) + { + return true; + } + return fAVMService.hasAspect(version, path, aspectTypeQName); + } + + private static QName [] fgBuiltinAspects = new QName[] { ContentModel.ASPECT_AUDITABLE, + ContentModel.ASPECT_REFERENCEABLE }; + + private boolean isBuiltinAspect(QName aspectQName) + { + for (QName builtin : fgBuiltinAspects) + { + if (builtin.equals(aspectQName)) + { + return true; + } + } + return false; + } + + /** + * @param nodeRef + * @return Returns a set of all aspects applied to the node, including mandatory + * aspects + * @throws InvalidNodeRefException if the node could not be found + */ + public Set getAspects(NodeRef nodeRef) throws InvalidNodeRefException + { + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + int version = avmVersionPath.getFirst(); + String path = avmVersionPath.getSecond(); + Set result = new HashSet(); + // Add the builtin ones. + for (QName name : fgBuiltinAspects) + { + result.add(name); + } + try + { + for (QName name : fAVMService.getAspects(version, path)) + { + result.add(name); + } + return result; + } + catch (AVMNotFoundException e) + { + throw new InvalidNodeRefException(nodeRef); + } + } + + /** + * Deletes the given node. + *

+ * All associations (both children and regular node associations) + * will be deleted, and where the given node is the primary parent, + * the children will also be cascade deleted. + * + * @param nodeRef reference to a node within a store + * @throws InvalidNodeRefException if the reference given is invalid + */ + public void deleteNode(NodeRef nodeRef) throws InvalidNodeRefException + { + // Invoke policy behaviors. +// invokeBeforeDeleteNode(nodeRef); + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + if (avmVersionPath.getFirst() != -1) + { + throw new InvalidNodeRefException("Read only store.", nodeRef); + } + String [] avmPathBase = AVMNodeConverter.SplitBase(avmVersionPath.getSecond()); + if (avmPathBase[0] == null) + { + throw new InvalidNodeRefException("Cannot delete root node.", nodeRef); + } + try + { +// QName nodeTypeQName = getType(nodeRef); +// Set aspects = getAspects(nodeRef); + fAVMService.removeNode(avmPathBase[0], avmPathBase[1]); +// ChildAssociationRef childAssocRef = +// new ChildAssociationRef(ContentModel.ASSOC_CHILDREN, +// AVMNodeConverter.ToNodeRef(-1, avmPathBase[0]), +// QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, +// avmPathBase[1]), +// nodeRef); +// invokeOnDeleteNode(childAssocRef, nodeTypeQName, aspects, false); + } + catch (AVMNotFoundException e) + { + throw new InvalidNodeRefException(avmVersionPath.getSecond() +" not found.", nodeRef); + } + } + + /** + * Makes a parent-child association between the given nodes. Both nodes must belong to the same store. + *

+ * + * @param parentRef + * @param childRef + * @param assocTypeQName the qualified name of the association type as defined in the datadictionary + * @param qname the qualified name of the association + * @return Returns a reference to the newly created child association + * @throws InvalidNodeRefException if the parent or child nodes could not be found + * @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add + */ + public ChildAssociationRef addChild( + NodeRef parentRef, + NodeRef childRef, + QName assocTypeQName, + QName qname) throws InvalidNodeRefException + { + return addChild(Collections.singletonList(parentRef), childRef, assocTypeQName, qname).get(0); + } + + /** + * Associates a given child node with a given collection of parents. All nodes must belong to the same store. + *

+ * + * + * @param parentRefs + * @param childRef + * @param assocTypeQName the qualified name of the association type as defined in the datadictionary + * @param qname the qualified name of the association + * @return Returns a reference to the newly created child association + * @throws InvalidNodeRefException if the parent or child nodes could not be found + * @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add + */ + public List addChild( + Collection parentRefs, + NodeRef childRef, + QName assocTypeQName, + QName qname) throws InvalidNodeRefException + { + Pair childVersionPath = AVMNodeConverter.ToAVMVersionPath(childRef); + AVMNodeDescriptor child = fAVMService.lookup(childVersionPath.getFirst(), + childVersionPath.getSecond()); + if (child == null) + { + throw new InvalidNodeRefException(childVersionPath.getSecond() + " not found.", childRef); + } + + List childAssociationRefs = new ArrayList(parentRefs.size()); + for (NodeRef parentRef : parentRefs) + { + Pair parentVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef); + if (parentVersionPath.getFirst() >= 0) + { + throw new InvalidNodeRefException("Read Only.", parentRef); + } + try + { + fAVMService.link(parentVersionPath.getSecond(), qname.getLocalName(), child); + ChildAssociationRef newChild = new ChildAssociationRef(assocTypeQName, parentRef, qname, + AVMNodeConverter.ToNodeRef(-1, AVMNodeConverter.ExtendAVMPath(parentVersionPath.getSecond(), + qname.getLocalName()))); + childAssociationRefs.add(newChild); + } + catch (AVMException e) + { + throw new InvalidNodeRefException("Could not link.", childRef); + } + } + return childAssociationRefs; + } + + /** + * Severs all parent-child relationships between two nodes. + *

+ * The child node will be cascade deleted if one of the associations was the + * primary association, i.e. the one with which the child node was created. + * + * @param parentRef the parent end of the association + * @param childRef the child end of the association + * @throws InvalidNodeRefException if the parent or child nodes could not be found + */ + public void removeChild(NodeRef parentRef, NodeRef childRef) throws InvalidNodeRefException + { + Pair parentVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef); + if (parentVersionPath.getFirst() >= 0) + { + throw new InvalidNodeRefException("Read only store.", parentRef); + } + Pair childVersionPath = AVMNodeConverter.ToAVMVersionPath(childRef); + if (childVersionPath.getFirst() >= 0) + { + throw new InvalidNodeRefException("Read only store.", childRef); + } + String parentPath = parentVersionPath.getSecond(); + String childPath = childVersionPath.getSecond(); + String [] childPathBase = AVMNodeConverter.SplitBase(childPath); + if (childPathBase[0] == null || !childPathBase[0].equals(parentPath)) + { + throw new InvalidNodeRefException(childPath + " not a child of " + parentPath, childRef); + } + try + { +// ChildAssociationRef assocRef = +// new ChildAssociationRef(ContentModel.ASSOC_CHILDREN, +// AVMNodeConverter.ToNodeRef(-1, parentPath), +// QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, +// childPathBase[1]), +// AVMNodeConverter.ToNodeRef(-1, childPath)); +// invokeBeforeDeleteChildAssociation(assocRef); + fAVMService.removeNode(childPathBase[0], childPathBase[1]); +// invokeOnDeleteChildAssociation(assocRef); +// invokeOnUpdateNode(AVMNodeConverter.ToNodeRef(-1, parentPath)); + } + catch (AVMNotFoundException e) + { + throw new InvalidNodeRefException(childPathBase[1] + " not found in " + childPathBase[0], + childRef); + } + } + + /** + * TODO: Check implementation + */ + public boolean removeChildAssociation(ChildAssociationRef childAssocRef) + { + NodeRef parentRef = childAssocRef.getParentRef(); + NodeRef childRef = childAssocRef.getChildRef(); + Pair parentVersionPath = AVMNodeConverter.ToAVMVersionPath(parentRef); + if (parentVersionPath.getFirst() >= 0) + { + throw new InvalidNodeRefException("Read only store.", parentRef); + } + Pair childVersionPath = AVMNodeConverter.ToAVMVersionPath(childRef); + if (childVersionPath.getFirst() >= 0) + { + throw new InvalidNodeRefException("Read only store.", childRef); + } + String parentPath = parentVersionPath.getSecond(); + String childPath = childVersionPath.getSecond(); + String [] childPathBase = AVMNodeConverter.SplitBase(childPath); + if (childPathBase[0] == null || !childPathBase[0].equals(parentPath)) + { + return false; + } + try + { + fAVMService.removeNode(childPathBase[0], childPathBase[1]); + return true; + } + catch (AVMNotFoundException e) + { + throw new InvalidNodeRefException("Not found.", childRef); + } + } + + /** + * TODO: Implement + */ + public boolean removeSeconaryChildAssociation(ChildAssociationRef childAssocRef) + { + throw new UnsupportedOperationException(); + } + + /** + * @param nodeRef + * @return Returns all properties keyed by their qualified name + * @throws InvalidNodeRefException if the node could not be found + */ + public Map getProperties(NodeRef nodeRef) throws InvalidNodeRefException + { + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + Map props = null; + AVMNodeDescriptor desc = fAVMService.lookup(avmVersionPath.getFirst(), + avmVersionPath.getSecond()); + try + { + props = fAVMService.getNodeProperties(avmVersionPath.getFirst(), + avmVersionPath.getSecond()); + } + catch (AVMNotFoundException e) + { + throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); + } + Map result = new HashMap(); + for (QName qName : props.keySet()) + { + PropertyValue value = props.get(qName); + PropertyDefinition def = dictionaryService.getProperty(qName); + result.put(qName, makeSerializableValue(def, value)); + } + // Now spoof properties that are built in. + result.put(ContentModel.PROP_CREATED, new Date(desc.getCreateDate())); + result.put(ContentModel.PROP_CREATOR, desc.getCreator()); + result.put(ContentModel.PROP_MODIFIED, new Date(desc.getModDate())); + result.put(ContentModel.PROP_MODIFIER, desc.getLastModifier()); + result.put(ContentModel.PROP_OWNER, desc.getOwner()); + result.put(ContentModel.PROP_NAME, desc.getName()); + result.put(ContentModel.PROP_NODE_UUID, "UNKNOWN"); + result.put(ContentModel.PROP_NODE_DBID, new Long(desc.getId())); + result.put(ContentModel.PROP_STORE_PROTOCOL, "avm"); + result.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier()); + if (desc.isLayeredDirectory()) + { + result.put(WCMModel.PROP_AVM_DIR_INDIRECTION, + AVMNodeConverter.ToNodeRef(-1, desc.getIndirection())); + } + if (desc.isLayeredFile()) + { + result.put(WCMModel.PROP_AVM_FILE_INDIRECTION, + AVMNodeConverter.ToNodeRef(-1, desc.getIndirection())); + } + if (desc.isFile()) + { + try + { + ContentData contentData = fAVMService.getContentDataForRead(avmVersionPath.getFirst(), + avmVersionPath.getSecond()); + result.put(ContentModel.PROP_CONTENT, contentData); + } + catch (AVMException e) + { + // TODO For now ignore. + } + } + return result; + } + + /** + * @param nodeRef + * @param qname the qualified name of the property + * @return Returns the value of the property, or null if not yet set + * @throws InvalidNodeRefException if the node could not be found + */ + public Serializable getProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException + { + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + if (isBuiltInProperty(qname)) + { + return getBuiltInProperty(avmVersionPath, qname, nodeRef); + } + try + { + PropertyValue value = fAVMService.getNodeProperty(avmVersionPath.getFirst(), + avmVersionPath.getSecond(), + qname); + if (value == null) + { + return null; + } + PropertyDefinition def = this.dictionaryService.getProperty(qname); + return makeSerializableValue(def, value); + } + catch (AVMNotFoundException e) + { + throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); + } + } + + /** + * {@inheritDoc} + */ + public void removeProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException + { + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + if (isBuiltInProperty(qname)) + { + // Ignore + return; + } + try + { + fAVMService.deleteNodeProperty(avmVersionPath.getSecond(), qname); + } + catch (AVMNotFoundException e) + { + throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); + } + } + + /** + * A Helper to spoof built in properties. + * @param avmVersionPath The broken out version and path from a NodeRef. + * @param qName The name of the property to retrieve. + * @param nodeRef The original NodeRef (for error reporting). + * @return The property value. + */ + private Serializable getBuiltInProperty(Pair avmVersionPath, + QName qName, + NodeRef nodeRef) + { + if (qName.equals(ContentModel.PROP_CONTENT)) + { + try + { + ContentData contentData = + fAVMService.getContentDataForRead(avmVersionPath.getFirst(), + avmVersionPath.getSecond()); + return contentData; + } + catch (AVMException e) + { + // TODO This seems very wrong. Do something better + // sooner rather than later. + return null; + } + } + AVMNodeDescriptor desc = fAVMService.lookup(avmVersionPath.getFirst(), + avmVersionPath.getSecond()); + if (desc == null) + { + throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); + } + if (qName.equals(ContentModel.PROP_CREATED)) + { + return new Date(desc.getCreateDate()); + } + else if (qName.equals(ContentModel.PROP_CREATOR)) + { + return desc.getCreator(); + } + else if (qName.equals(ContentModel.PROP_MODIFIED)) + { + return new Date(desc.getModDate()); + } + else if (qName.equals(ContentModel.PROP_MODIFIER)) + { + return desc.getLastModifier(); + } + else if (qName.equals(ContentModel.PROP_OWNER)) + { + return desc.getOwner(); + } + else if (qName.equals(ContentModel.PROP_NAME)) + { + return desc.getName(); + } + else if (qName.equals(ContentModel.PROP_NODE_UUID)) + { + return "UNKNOWN"; + } + else if (qName.equals(ContentModel.PROP_NODE_DBID)) + { + return new Long(desc.getId()); + } + else if (qName.equals(ContentModel.PROP_STORE_PROTOCOL)) + { + return "avm"; + } + else if (qName.equals(ContentModel.PROP_STORE_IDENTIFIER)) + { + return nodeRef.getStoreRef().getIdentifier(); + } + else if (qName.equals(WCMModel.PROP_AVM_DIR_INDIRECTION)) + { + if (desc.isLayeredDirectory()) + { + return AVMNodeConverter.ToNodeRef(-1, desc.getIndirection()); + } + return null; + } + else if (qName.equals(WCMModel.PROP_AVM_FILE_INDIRECTION)) + { + if (desc.isLayeredFile()) + { + return AVMNodeConverter.ToNodeRef(-1, desc.getIndirection()); + } + return null; + } + else + { + logger.error("Invalid Built In Property: " + qName); + return null; + } + } + + /** + * Set the values of all properties to be an Serializable instances. + * The properties given must still fulfill the requirements of the class and + * aspects relevant to the node. + *

+ * NOTE: Null values are allowed. + * + * @param nodeRef + * @param properties all the properties of the node keyed by their qualified names + * @throws InvalidNodeRefException if the node could not be found + */ + public void setProperties(NodeRef nodeRef, Map properties) throws InvalidNodeRefException + { + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + if (avmVersionPath.getFirst() >= 0) + { + throw new InvalidNodeRefException("Read only store.", nodeRef); + } + // TODO Not sure this try block is necessary. + try + { + // Prepare fr policy invocation. + Map propsBefore = null; + if (fInvokePolicies) + { + propsBefore = getProperties(nodeRef); + } + // Remove all properties + fAVMService.deleteNodeProperties(avmVersionPath.getSecond()); + // Rebuild node properties + Map values = new HashMap(); + for (Map.Entry entry : properties.entrySet()) + { + QName propertyQName = entry.getKey(); + Serializable value = entry.getValue(); + // For AVM nodes is in place. + if (isBuiltInProperty(propertyQName)) + { + if (propertyQName.equals(ContentModel.PROP_CONTENT)) + { + AVMNodeDescriptor desc = fAVMService.lookup(-1, avmVersionPath.getSecond()); + if (desc == null) + { + throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); + } + if (desc.isPlainFile()) + { + fAVMService.setContentData(avmVersionPath.getSecond(), + (ContentData)properties.get(propertyQName)); + } + } + } + PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); + PropertyValue propertyValue = makePropertyValue(propertyDef, value); + values.put(propertyQName, propertyValue); + } + // Finally set node properties + fAVMService.setNodeProperties(avmVersionPath.getSecond(), values); + // Invoke policies + if (fInvokePolicies) + { + Map propsAfter = properties; + invokeOnUpdateProperties(nodeRef, propsBefore, propsAfter); + } + // Invoke policy behaviors. +// invokeOnUpdateNode(nodeRef); +// invokeOnUpdateProperties(nodeRef, oldProps, properties); + } + catch (AVMNotFoundException e) + { + throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); + } + } + + public void addProperties(NodeRef nodeRef, Map properties) + { + // Overwrite the current properties + Map currentProperties = getProperties(nodeRef); + currentProperties.putAll(properties); + setProperties(nodeRef, currentProperties); + } + + static QName [] fgBuiltinProperties = new QName [] + { + ContentModel.PROP_CREATED, + ContentModel.PROP_CREATOR, + ContentModel.PROP_MODIFIED, + ContentModel.PROP_MODIFIER, + ContentModel.PROP_OWNER, + ContentModel.PROP_CONTENT, + ContentModel.PROP_NAME, + ContentModel.PROP_NODE_UUID, + ContentModel.PROP_NODE_DBID, + ContentModel.PROP_STORE_PROTOCOL, + ContentModel.PROP_STORE_IDENTIFIER, + WCMModel.PROP_AVM_FILE_INDIRECTION, + WCMModel.PROP_AVM_DIR_INDIRECTION + }; + + /** + * Helper to distinguish built-in from generic properties. + * @param qName The name of the property to check. + * @return Whether qName is a built-in propety. + */ + private boolean isBuiltInProperty(QName qName) + { + for (QName name : fgBuiltinProperties) + { + if (name.equals(qName)) + { + return true; + } + } + return false; + } + + /** + * Sets the value of a property to be any Serializable instance. + * To remove a property value, use {@link #getProperties(NodeRef)}, remove the + * value and call {@link #setProperties(NodeRef, Map)}. + *

+ * NOTE: Null values are allowed. + * + * @param nodeRef + * @param qname the fully qualified name of the property + * @param propertyValue the value of the property - never null + * @throws InvalidNodeRefException if the node could not be found + */ + public void setProperty(NodeRef nodeRef, QName qname, Serializable value) throws InvalidNodeRefException + { + // Invoke policy behaviors. + // invokeBeforeUpdateNode(nodeRef); + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + if (avmVersionPath.getFirst() >= 0) + { + throw new InvalidNodeRefException("Read only store.", nodeRef); + } + + Map propsBefore = null; + if (fInvokePolicies) + { + propsBefore = getProperties(nodeRef); + } + + if (isBuiltInProperty(qname)) + { + if (qname.equals(ContentModel.PROP_CONTENT)) + { + try + { + fAVMService.setContentData(avmVersionPath.getSecond(), (ContentData)value); + if (fInvokePolicies) + { + Map propsAfter = new HashMap(propsBefore); + propsAfter.put(ContentModel.PROP_CONTENT, value); + invokeOnUpdateProperties(nodeRef, propsBefore, propsAfter); + } + } + catch (ClassCastException e) + { + throw new AVMException("Invalid ContentData.", e); + } + } + return; + } + try + { + + PropertyDefinition propertyDef = dictionaryService.getProperty(qname); + PropertyValue propertyValue = makePropertyValue(propertyDef, value); + fAVMService.setNodeProperty(avmVersionPath.getSecond(), qname, propertyValue); + if (fInvokePolicies) + { + Map propsAfter = new HashMap(propsBefore); + propsAfter.put(qname, value); + invokeOnUpdateProperties(nodeRef, propsBefore, propsAfter); + } + // Map propsAfter = getProperties(nodeRef); + // Invoke policy behaviors. + // invokeOnUpdateNode(nodeRef); + // invokeOnUpdateProperties(nodeRef, propsBefore, propsAfter); + } + catch (AVMNotFoundException e) + { + throw new InvalidNodeRefException(avmVersionPath.getSecond() + " not found.", nodeRef); + } + } + + /** + * @param nodeRef the child node + * @return Returns a list of all parent-child associations that exist where the given + * node is the child + * @throws InvalidNodeRefException if the node could not be found + * + * @see #getParentAssocs(NodeRef, QNamePattern, QNamePattern) + */ + public List getParentAssocs(NodeRef nodeRef) throws InvalidNodeRefException + { + // TODO OK, for now we'll simply return the single parent that corresponds + // to the path stuffed in the NodeRef. + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + String path = avmVersionPath.getSecond(); + List result = new ArrayList(); + String [] splitPath = AVMNodeConverter.SplitBase(path); + if (splitPath[0] == null) + { + return result; + } + result.add(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, + AVMNodeConverter.ToNodeRef(avmVersionPath.getFirst(), + splitPath[0]), + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, + splitPath[1]), + nodeRef, + true, + -1)); + return result; + } + + /** + * Gets all parent associations where the pattern of the association qualified + * name is a match + *

+ * The resultant list is ordered by (a) explicit index and (b) association creation time. + * + * @param nodeRef the child node + * @param typeQNamePattern the pattern that the type qualified name of the association must match + * @param qnamePattern the pattern that the qnames of the assocs must match + * @return Returns a list of all parent-child associations that exist where the given + * node is the child + * @throws InvalidNodeRefException if the node could not be found + * + * @see ChildAssociationRef#getNthSibling() + * @see #setChildAssociationIndex(ChildAssociationRef, int) + * @see QName + * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL + */ + public List getParentAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern) + throws InvalidNodeRefException + { + if (!typeQNamePattern.isMatch(ContentModel.ASSOC_CONTAINS)) + { + return new ArrayList(); + } + List result = getParentAssocs(nodeRef); + if (result.size() == 0) + { + return result; + } + if (qnamePattern.isMatch(result.get(0).getQName())) + { + return result; + } + return new ArrayList(); + } + + /** + * Get all child associations of the given node. + *

+ * The resultant list is ordered by (a) explicit index and (b) association creation time. + * + * @param nodeRef the parent node - usually a container + * @return Returns a collection of ChildAssocRef instances. If the + * node is not a container then the result will be empty. + * @throws InvalidNodeRefException if the node could not be found + * + * @see #getChildAssocs(NodeRef, QNamePattern, QNamePattern) + * @see #setChildAssociationIndex(ChildAssociationRef, int) + * @see ChildAssociationRef#getNthSibling() + */ + public List getChildAssocs(NodeRef nodeRef) throws InvalidNodeRefException + { + + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + int version = avmVersionPath.getFirst(); + String path = avmVersionPath.getSecond(); + List result = new ArrayList(); + SortedMap children = null; + try + { + children = + fAVMService.getDirectoryListing(version, + path); + } + catch (AVMNotFoundException e) + { + return result; + } + for (String name : children.keySet()) + { + result.add(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, + nodeRef, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, + name), + AVMNodeConverter.ToNodeRef( + version, + AVMNodeConverter.ExtendAVMPath(path, name)), + true, + -1)); + } + return result; + } + + /** + * Gets all child associations where the pattern of the association qualified + * name is a match. + * + * @param nodeRef the parent node - usually a container + * @param typeQNamePattern the pattern that the type qualified name of the association must match + * @param qnamePattern the pattern that the qnames of the assocs must match + * @return Returns a list of ChildAssocRef instances. If the + * node is not a container then the result will be empty. + * @throws InvalidNodeRefException if the node could not be found + * + * @see QName + * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL + */ + public List getChildAssocs( + NodeRef nodeRef, + QNamePattern typeQNamePattern, + QNamePattern qnamePattern) + throws InvalidNodeRefException + { + List result = new ArrayList(); + if (!typeQNamePattern.isMatch(ContentModel.ASSOC_CONTAINS)) + { + return result; + } + List all = getChildAssocs(nodeRef); + for (ChildAssociationRef child : all) + { + if (!qnamePattern.isMatch(child.getQName())) + { + continue; + } + result.add(child); + } + return result; + } + + + + public List getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, + QNamePattern qnamePattern, boolean preload) throws InvalidNodeRefException + { + return getChildAssocs(nodeRef, typeQNamePattern, qnamePattern); + } + + public List getChildAssocs(NodeRef nodeRef, Set childNodeTypes) + { + /* + * ETWOTWO-961 forced an implementation, but this is just a workaround. + * We do a listing and then keep files or folders looking specifically + * for cm:folder and cm:content types from childNodeTypes. + */ + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + int version = avmVersionPath.getFirst(); + String path = avmVersionPath.getSecond(); + List result = new ArrayList(); + SortedMap children = null; + try + { + children = + fAVMService.getDirectoryListing(version, + path); + } + catch (AVMNotFoundException e) + { + return result; + } + for (Map.Entry entry : children.entrySet()) + { + String name = entry.getKey(); + AVMNodeDescriptor descriptor = entry.getValue(); + if (descriptor.isFile()) + { + if (!childNodeTypes.contains(ContentModel.TYPE_CONTENT)) + { + continue; + } + } + else if (descriptor.isDirectory()) + { + if (!childNodeTypes.contains(ContentModel.TYPE_FOLDER)) + { + continue; + } + } + else + { + // Not a file or directory??? + continue; + } + result.add(new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, + nodeRef, + QName.createQName( + NamespaceService.CONTENT_MODEL_1_0_URI, + name), + AVMNodeConverter.ToNodeRef( + version, + AVMNodeConverter.ExtendAVMPath(path, name)), + true, + -1)); + } + return result; + } + + /** + * getChildrenByName + */ + public List getChildrenByName(NodeRef nodeRef, QName assocTypeQName, Collection childNames) + { + final List results = new ArrayList(100); + + if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS)) + { + throw new UnsupportedOperationException("AVM getChildrenByName only supports ASSOCS_CONTAINS."); + } + + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + try + { + for(String childName : childNames) + { + AVMNodeDescriptor child = fAVMService.lookup(avmVersionPath.getFirst(), + AVMUtil.extendAVMPath(avmVersionPath.getSecond(), childName)); + + if (child != null) + { + NodeRef childRef = AVMNodeConverter.ToNodeRef(avmVersionPath.getFirst(), + child.getPath()); + QName childQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, + childName); + ChildAssociationRef ref = new ChildAssociationRef(assocTypeQName, nodeRef, childQName, childRef); + + if(logger.isDebugEnabled()) + { + logger.debug("got a child node :" + ref); + } + results.add(ref); + } + } + return results; + } + catch (AVMException e) + { + logger.debug("exception in getChildrenByName ", e); + return results; + } + } + + + /** + * Get a child NodeRef by name. + * @param nodeRef The parent node. + * @param assocTypeQName The type of the Child Association. + * @param childName The name of the child to get. + */ + public NodeRef getChildByName(NodeRef nodeRef, QName assocTypeQName, String childName) + { + if (!assocTypeQName.equals(ContentModel.ASSOC_CONTAINS)) + { + return null; + } + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + try + { + AVMNodeDescriptor child = fAVMService.lookup(avmVersionPath.getFirst(), + AVMUtil.extendAVMPath(avmVersionPath.getSecond(), childName)); + if (child == null) + { + return null; + } + return AVMNodeConverter.ToNodeRef(avmVersionPath.getFirst(), + child.getPath()); + } + catch (AVMException e) + { + return null; + } + } + + /** + * Fetches the primary parent-child relationship. + *

+ * For a root node, the parent node reference will be null. + * + * @param nodeRef + * @return Returns the primary parent-child association of the node + * @throws InvalidNodeRefException if the node could not be found + */ + public ChildAssociationRef getPrimaryParent(NodeRef nodeRef) throws InvalidNodeRefException + { + List parents = getParentAssocs(nodeRef); + if (parents.size() == 0) + { + return new ChildAssociationRef(null, null, null, nodeRef); + } + return parents.get(0); + } + + /** + * + * @param sourceRef a reference to a real node + * @param targetRef a reference to a node + * @param assocTypeQName the qualified name of the association type + * @return Returns a reference to the new association + * @throws InvalidNodeRefException if either of the nodes could not be found + * @throws AssociationExistsException + */ + public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) + throws InvalidNodeRefException, AssociationExistsException + { + throw new UnsupportedOperationException("AVM does not support arbitrary associations."); + } + + /** + * + * @param sourceRef the associaton source node + * @param targetRef the association target node + * @param assocTypeQName the qualified name of the association type + * @throws InvalidNodeRefException if either of the nodes could not be found + */ + public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName) + throws InvalidNodeRefException + { + throw new UnsupportedOperationException("AVM does not support arbitrary associations."); + } + + /** + * Gets an association by ID. + * + * @param assocId + * the association id + * @return the association, or null if it does not exist + */ + public AssociationRef getAssoc(Long id) + { + return null; + } + + /** + * Fetches all associations from the given source where the associations' + * qualified names match the pattern provided. + * + * @param sourceRef the association source + * @param qnamePattern the association qname pattern to match against + * @return Returns a list of NodeAssocRef instances for which the + * given node is a source + * @throws InvalidNodeRefException if the source node could not be found + * + * @see QName + * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL + */ + public List getTargetAssocs(NodeRef sourceRef, QNamePattern qnamePattern) + throws InvalidNodeRefException + { + return new ArrayList(); + } + + /** + * Fetches all associations to the given target where the associations' + * qualified names match the pattern provided. + * + * @param targetRef the association target + * @param qnamePattern the association qname pattern to match against + * @return Returns a list of NodeAssocRef instances for which the + * given node is a target + * @throws InvalidNodeRefException + * + * @see QName + * @see org.alfresco.service.namespace.RegexQNamePattern#MATCH_ALL + */ + public List getSourceAssocs(NodeRef targetRef, QNamePattern qnamePattern) + throws InvalidNodeRefException + { + return new ArrayList(); + } + + /** + * The root node has an entry in the path(s) returned. For this reason, there + * will always be at least one path element in the returned path(s). + * The first element will have a null parent reference and qname. + * + * @param nodeRef + * @return Returns the path to the node along the primary node path + * @throws InvalidNodeRefException if the node could not be found + * + * @see #getPaths(NodeRef, boolean) + */ + public Path getPath(NodeRef nodeRef) throws InvalidNodeRefException + { + // TODO Review later. This may be wrong. + Path path = new Path(); + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + int version = avmVersionPath.getFirst(); + String currPath = avmVersionPath.getSecond(); + while (!currPath.endsWith("/")) + { + String [] splitPath = AVMNodeConverter.SplitBase(currPath); + String parentPath = splitPath[0]; + String name = splitPath[1]; + ChildAssociationRef caRef = + new ChildAssociationRef(ContentModel.ASSOC_CONTAINS, + AVMNodeConverter.ToNodeRef(version, parentPath), + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, + name), + AVMNodeConverter.ToNodeRef(version, currPath), + true, + -1); + path.prepend(new Path.ChildAssocElement(caRef)); + currPath = parentPath; + } + ChildAssociationRef caRef = new ChildAssociationRef(null, null, null, + AVMNodeConverter.ToNodeRef(version, + currPath)); + path.prepend(new Path.ChildAssocElement(caRef)); + return path; + } + + /** + * The root node has an entry in the path(s) returned. For this reason, there + * will always be at least one path element in the returned path(s). + * The first element will have a null parent reference and qname. + * + * @param nodeRef + * @param primaryOnly true if only the primary path must be retrieved. If true, the + * result will have exactly one entry. + * @return Returns a List of all possible paths to the given node + * @throws InvalidNodeRefException if the node could not be found + */ + public List getPaths(NodeRef nodeRef, boolean primaryOnly) throws InvalidNodeRefException + { + List result = new ArrayList(); + result.add(getPath(nodeRef)); + return result; + } + + /** + * Get the node where archived items will have gone when deleted from the given store. + * + * @param storeRef the store that items were deleted from + * @return Returns the archive node parent + */ + public NodeRef getStoreArchiveNode(StoreRef storeRef) + { + throw new UnsupportedOperationException("AVM does not support this operation."); + } + + /** + * Restore an individual node (along with its sub-tree nodes) to the target location. + * The archived node must have the {@link org.alfresco.model.ContentModel#ASPECT_ARCHIVED archived aspect} + * set against it. + * + * @param archivedNodeRef the archived node + * @param destinationParentNodeRef the parent to move the node into + * or null to use the original + * @param assocTypeQName the primary association type name to use in the new location + * or null to use the original + * @param assocQName the primary association name to use in the new location + * or null to use the original + * @return Returns the reference to the newly created node + */ + public NodeRef restoreNode( + NodeRef archivedNodeRef, + NodeRef destinationParentNodeRef, + QName assocTypeQName, + QName assocQName) + { + throw new UnsupportedOperationException("AVM does not support this operation."); + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.repository.NodeService#getChildAssocsWithoutParentAssocsOfType(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.namespace.QName) + */ + public Collection getChildAssocsWithoutParentAssocsOfType(NodeRef parent, QName assocTypeQName) + { + throw new UnsupportedOperationException("AVM does not support this operation."); + } +} diff --git a/source/java/org/alfresco/repo/avm/AVMRepository.java b/source/java/org/alfresco/repo/avm/AVMRepository.java index ec4b27d570..ac3f4a6f64 100644 --- a/source/java/org/alfresco/repo/avm/AVMRepository.java +++ b/source/java/org/alfresco/repo/avm/AVMRepository.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,3467 +14,3457 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . */ - -package org.alfresco.repo.avm; - -import java.io.File; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; - -import org.alfresco.model.WCMModel; -import org.alfresco.repo.avm.util.AVMUtil; -import org.alfresco.repo.content.ContentStore; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.avm.AVMStoreEntity; -import org.alfresco.repo.domain.qname.QNameDAO; -import org.alfresco.repo.security.permissions.ACLCopyMode; -import org.alfresco.repo.security.permissions.AccessDeniedException; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport; -import org.alfresco.service.cmr.avm.AVMBadArgumentException; -import org.alfresco.service.cmr.avm.AVMCycleException; -import org.alfresco.service.cmr.avm.AVMException; -import org.alfresco.service.cmr.avm.AVMExistsException; -import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.cmr.avm.AVMNotFoundException; -import org.alfresco.service.cmr.avm.AVMStoreDescriptor; -import org.alfresco.service.cmr.avm.AVMWrongTypeException; -import org.alfresco.service.cmr.avm.LayeringDescriptor; -import org.alfresco.service.cmr.avm.VersionDescriptor; -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.cmr.repository.ContentWriter; -import org.alfresco.service.cmr.security.AccessStatus; -import org.alfresco.service.cmr.security.PermissionContext; -import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.FileNameValidator; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.alfresco.util.Pair; - -/** - * This or AVMStore are the implementors of the operations specified by AVMService. - * - * @author britt - */ -public class AVMRepository -{ - private static Log fgLogger = LogFactory.getLog(AVMRepository.class); - - /** - * The single instance of AVMRepository. - */ - private static AVMRepository fgInstance; - - /** - * The current lookup count. - */ - private ThreadLocal fLookupCount; - - /** - * Reference to the ContentStoreImpl - */ - private ContentStore fContentStore; - - /** - * The Lookup Cache instance. - */ - private LookupCache fLookupCache; - - private QNameDAO qnameDAO; - - private AVMStoreDAO fAVMStoreDAO; - - private AVMNodeDAO fAVMNodeDAO; - - private VersionRootDAO fVersionRootDAO; - - private VersionLayeredNodeEntryDAO fVersionLayeredNodeEntryDAO; - - private AVMStorePropertyDAO fAVMStorePropertyDAO; - - private ChildEntryDAO fChildEntryDAO; - - private PermissionService fPermissionService; - - private DictionaryService fDictionaryService; - - // A bunch of TransactionListeners that do work for this. - - /** - * One for create store. - */ - private CreateStoreTxnListener fCreateStoreTxnListener; - - /** - * One for purge store. - */ - private PurgeStoreTxnListener fPurgeStoreTxnListener; - - /** - * One for create version. - */ - private CreateVersionTxnListener fCreateVersionTxnListener; - - /** - * One for purge version. - */ - private PurgeVersionTxnListener fPurgeVersionTxnListener; - - /** - * Create a new one. - */ - public AVMRepository() - { - fLookupCount = new ThreadLocal(); - fgInstance = this; - } - - /** - * Set the ContentService. - */ - public void setContentStore(ContentStore store) - { - fContentStore = store; - } - - /** - * Set the Lookup Cache instance. - * - * @param cache - * The instance to set. - */ - public void setLookupCache(LookupCache cache) - { - fLookupCache = cache; - } - - public void setCreateStoreTxnListener(CreateStoreTxnListener listener) - { - fCreateStoreTxnListener = listener; - } - - public void setPurgeStoreTxnListener(PurgeStoreTxnListener listener) - { - fPurgeStoreTxnListener = listener; - } - - public void setCreateVersionTxnListener(CreateVersionTxnListener listener) - { - fCreateVersionTxnListener = listener; - } - - public void setPurgeVersionTxnListener(PurgeVersionTxnListener listener) - { - fPurgeVersionTxnListener = listener; - } - - public void setQnameDAO(QNameDAO qnameDAO) - { - this.qnameDAO = qnameDAO; - } - - public void setAvmStoreDAO(AVMStoreDAO dao) - { - fAVMStoreDAO = dao; - } - - public void setAvmNodeDAO(AVMNodeDAO dao) - { - fAVMNodeDAO = dao; - } - - public void setVersionRootDAO(VersionRootDAO dao) - { - fVersionRootDAO = dao; - } - - public void setVersionLayeredNodeEntryDAO(VersionLayeredNodeEntryDAO dao) - { - fVersionLayeredNodeEntryDAO = dao; - } - - public void setAvmStorePropertyDAO(AVMStorePropertyDAO dao) - { - fAVMStorePropertyDAO = dao; - } - - public void setChildEntryDAO(ChildEntryDAO dao) - { - fChildEntryDAO = dao; - } - - public void setPermissionService(PermissionService service) - { - fPermissionService = service; - } - - public void setDictionaryService(DictionaryService service) - { - fDictionaryService = service; - } - - /** - * Create a file. - * - * @param path - * The path to the containing directory. - * @param name - * The name for the new file. - */ - public OutputStream createFile(String path, String name) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - OutputStream out = store.createFile(pathParts[1], name); - return out; - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Create a file with the given File as content. - * - * @param path - * The path to the containing directory. - * @param name - * The name to give the file. - * @param data - * The file contents. - */ - public void createFile(String path, String name, File data, List aspects, Map properties) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.createFile(pathParts[1], name, data, aspects, properties); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Create a new directory. - * - * @param path - * The path to the containing directory. - * @param name - * The name to give the directory. - */ - public void createDirectory(String path, String name, List aspects, Map properties) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.createDirectory(pathParts[1], name, aspects, properties); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Create a new directory. This assumes that the parent is already copied and therefore should only be used with - * great care. - * - * @param parent - * The parent node. - * @param name - * The name of the new directory. - * @return A descriptor for the newly created directory. - */ - public AVMNodeDescriptor createDirectory(AVMNodeDescriptor parent, String name) - { - AVMNode node = fAVMNodeDAO.getByID(parent.getId()); - if (node == null) - { - throw new AVMNotFoundException(parent.getId() + " not found."); - } - if (!(node instanceof DirectoryNode)) - { - throw new AVMWrongTypeException("Not a directory."); - } - if (!can(null, node, PermissionService.CREATE_CHILDREN, true)) - { - throw new AccessDeniedException("Not allowed to write in: " + parent); - } - // We need the store to do anything so... - String[] pathParts = SplitPath(parent.getPath()); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - DirectoryNode dir = (DirectoryNode) node; - DirectoryNode child = null; - Long parentAcl = dir.getAcl() == null ? null : dir.getAcl().getId(); - if (dir instanceof LayeredDirectoryNode) - { - // TODO - collapse save/update - child = new LayeredDirectoryNodeImpl((String) null, store, null, parentAcl, ACLCopyMode.INHERIT); - ((LayeredDirectoryNode) child).setPrimaryIndirection(false); - ((LayeredDirectoryNode) child).setLayerID(parent.getLayerID()); - - DbAccessControlList acl = dir.getAcl(); - child.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null); - - AVMDAOs.Instance().fAVMNodeDAO.update(child); - } - else - { - child = new PlainDirectoryNodeImpl(store); - - DbAccessControlList acl = dir.getAcl(); - child.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null); - - AVMDAOs.Instance().fAVMNodeDAO.save(child); - } - - dir.putChild(name, child); - - fLookupCache.onWrite(pathParts[0]); - AVMNodeDescriptor desc = child.getDescriptor(parent.getPath(), name, parent.getIndirection(), parent.getIndirectionVersion()); - return desc; - } - - /** - * Create a new layered directory. - * - * @param srcPath - * The target indirection for the new layered directory. - * @param dstPath - * The path to the containing directory. - * @param name - * The name for the new directory. - */ - public void createLayeredDirectory(String srcPath, String dstPath, String name) - { - if (dstPath.indexOf(srcPath) == 0) - { - throw new AVMCycleException("Cycle would be created."); - } - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(dstPath); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.createLayeredDirectory(srcPath, pathParts[1], name); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Create a new layered file. - * - * @param srcPath - * The target indirection for the new layered file. - * @param dstPath - * The path to the containing directory. - * @param name - * The name of the new layered file. - */ - public void createLayeredFile(String srcPath, String dstPath, String name) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(dstPath); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.createLayeredFile(srcPath, pathParts[1], name); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Create a new AVMStore. - * - * @param name - * The name to give the new AVMStore. - */ - public void createAVMStore(String name) - { - createAVMStore(name, null); - } - - public void createAVMStore(String name, Map props) - { - AlfrescoTransactionSupport.bindListener(fCreateStoreTxnListener); - if (getAVMStoreByName(name) != null) - { - throw new AVMExistsException("AVMStore exists: " + name); - } - // Newing up the object causes it to be written to the db. - AVMStore rep = new AVMStoreImpl(this, name); - - // Special handling for AVMStore creation. - AVMNode rootNode = rep.getRoot(); - rootNode.setStoreNew(null); - fAVMNodeDAO.update(rootNode); - - - if (props != null) - { - setStoreProperties(name, props); - } - - fCreateStoreTxnListener.storeCreated(name); - } - - /** - * Create a new branch. - * - * @param version - * The version to branch off. - * @param srcPath - * The path to make a branch from. - * @param dstPath - * The containing directory. - * @param name - * The name of the new branch. - */ - public void createBranch(int version, String srcPath, String dstPath, String name) - { - if (dstPath.indexOf(srcPath) == 0) - { - throw new AVMCycleException("Cycle would be created."); - } - // Lookup the src node. - fLookupCount.set(1); - String[] pathParts; - Lookup sPath; - List layeredEntries = null; - try - { - pathParts = SplitPath(srcPath); - AVMStore srcRepo = getAVMStoreByName(pathParts[0]); - if (srcRepo == null) - { - throw new AVMNotFoundException("Store not found."); - } - if (version < 0) - { - fLookupCache.onSnapshot(pathParts[0]); - version = srcRepo.createSnapshot("Branch Snapshot", null, new HashMap()).get(pathParts[0]); - } - sPath = srcRepo.lookup(version, pathParts[1], false, false); - if (sPath == null) - { - throw new AVMNotFoundException("Path not found."); - } - VersionRoot lastVersion = fVersionRootDAO.getByVersionID(srcRepo, version); - layeredEntries = fVersionLayeredNodeEntryDAO.get(lastVersion); - } - finally - { - fLookupCount.set(null); - } - // Lookup the destination directory. - fLookupCount.set(1); - try - { - pathParts = SplitPath(dstPath); - AVMStore dstRepo = getAVMStoreByName(pathParts[0]); - if (dstRepo == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true); - if (dPath == null) - { - throw new AVMNotFoundException("Path not found."); - } - DirectoryNode dirNode = (DirectoryNode) dPath.getCurrentNode(); - if (!can(dstRepo, dirNode, PermissionService.ADD_CHILDREN, dPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not permitted to add children: " + dstPath); - } - AVMNode srcNode = sPath.getCurrentNode(); - AVMNode dstNode = null; - // We do different things depending on what kind of thing we're - // branching from. I'd be considerably happier if we disallowed - // certain scenarios, but Jon won't let me :P (bhp). - - Long inheritAcl = srcNode.getAcl() == null ? null : srcNode.getAcl().getId(); - - if (srcNode.getType() == AVMNodeType.PLAIN_DIRECTORY) - { - dstNode = new PlainDirectoryNodeImpl((PlainDirectoryNode) srcNode, dstRepo, inheritAcl, ACLCopyMode.INHERIT); - } - else if (srcNode.getType() == AVMNodeType.LAYERED_DIRECTORY) - { - dstNode = new LayeredDirectoryNodeImpl((LayeredDirectoryNode) srcNode, dstRepo, sPath, false, inheritAcl, ACLCopyMode.INHERIT); - - // note: re-use generated node id as a layer id - ((LayeredDirectoryNode) dstNode).setLayerID(dstNode.getId()); - - AVMDAOs.Instance().fAVMNodeDAO.update(dstNode); - } - else if (srcNode.getType() == AVMNodeType.LAYERED_FILE) - { - dstNode = new LayeredFileNodeImpl((LayeredFileNode) srcNode, dstRepo, inheritAcl, ACLCopyMode.INHERIT); - } - else - // This is a plain file. - { - dstNode = new PlainFileNodeImpl((PlainFileNode) srcNode, dstRepo, inheritAcl, ACLCopyMode.INHERIT); - } - // dstNode.setVersionID(dstRepo.getNextVersionID()); - dstNode.setAncestor(srcNode); - dirNode.putChild(name, dstNode); - // dirNode.updateModTime(); - String beginingPath = AVMUtil.normalizePath(srcPath); - String finalPath = AVMUtil.extendAVMPath(dstPath, name); - finalPath = AVMUtil.normalizePath(finalPath); - VersionRoot latestVersion = fVersionRootDAO.getMaxVersion(dstRepo); - for (VersionLayeredNodeEntry entry : layeredEntries) - { - String path = entry.getPath(); - if (!path.startsWith(srcPath)) - { - continue; - } - String newPath = finalPath + path.substring(beginingPath.length()); - VersionLayeredNodeEntry newEntry = new VersionLayeredNodeEntryImpl(latestVersion, newPath); - fVersionLayeredNodeEntryDAO.save(newEntry); - } - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get an output stream to a file. - * - * @param path - * The full path to the file. - * @return An OutputStream. - */ - public OutputStream getOutputStream(String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - OutputStream out = store.getOutputStream(pathParts[1]); - return out; - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get a content reader from a file node. - * - * @param version - * The version of the file. - * @param path - * The path to the file. - * @return A ContentReader. - */ - public ContentReader getContentReader(int version, String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found: " + pathParts[0]); - } - return store.getContentReader(version, pathParts[1]); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get a ContentWriter to a file node. - * - * @param path - * The path to the file. - * @param update true if the property must be updated atomically when the content write - * stream is closed (attaches a listener to the stream); false if the client code - * will perform the updates itself. - * @return A ContentWriter. - */ - public ContentWriter createContentWriter(String path, boolean update) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found: " + pathParts[0]); - } - fLookupCache.onWrite(pathParts[0]); - ContentWriter writer = store.createContentWriter(pathParts[1], update); - return writer; - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Rename a node. - * - * @param srcPath - * Source containing directory. - * @param srcName - * Source name. - * @param dstPath - * Destination containing directory. - * @param dstName - * Destination name. - */ - public void rename(String srcPath, String srcName, String dstPath, String dstName) - { - // This is about as ugly as it gets. - if ((dstPath + "/").indexOf(srcPath + srcName + "/") == 0) - { - throw new AVMCycleException("Cyclic rename."); - } - fLookupCount.set(1); - String[] pathParts; - Lookup sPath; - DirectoryNode srcDir; - AVMNode srcNode; - try - { - pathParts = SplitPath(srcPath); - AVMStore srcRepo = getAVMStoreByName(pathParts[0]); - if (srcRepo == null) - { - throw new AVMNotFoundException("Store not found."); - } - sPath = srcRepo.lookupDirectory(-1, pathParts[1], true); - if (sPath == null) - { - throw new AVMNotFoundException("Path not found."); - } - srcDir = (DirectoryNode) sPath.getCurrentNode(); - - Pair temp = srcDir.lookupChild(sPath, srcName, false); - srcNode = (temp == null) ? null : temp.getFirst(); - if (srcNode == null) - { - throw new AVMNotFoundException("Not found: " + srcName); - } - if (!can(srcRepo, srcNode, PermissionService.DELETE_NODE, false)) - { - throw new AccessDeniedException("Not allowed to delete target: " + srcPath); - } - - fLookupCache.onDelete(pathParts[0]); - } - finally - { - fLookupCount.set(null); - } - fLookupCount.set(1); - try - { - pathParts = SplitPath(dstPath); - AVMStore dstRepo = getAVMStoreByName(pathParts[0]); - if (dstRepo == null) - { - throw new AVMNotFoundException("Store not found."); - } - Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true); - if (dPath == null) - { - throw new AVMNotFoundException("Path not found."); - } - DirectoryNode dstDir = (DirectoryNode) dPath.getCurrentNode(); - if (!can(dstRepo, dstDir, PermissionService.ADD_CHILDREN, dPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write: " + dstPath); - } - Pair temp = dstDir.lookupChild(dPath, dstName, true); - AVMNode child = (temp == null) ? null : temp.getFirst(); - - boolean renameCase = false; - if (child != null && child.getType() != AVMNodeType.DELETED_NODE) - { - String avmSrcPath = AVMUtil.extendAVMPath(srcPath, srcName); - String avmDstPath = AVMUtil.extendAVMPath(dstPath, dstName); - - if ((avmSrcPath.equalsIgnoreCase(avmDstPath)) && (! srcName.equals(dstName))) - { - // specific rename 'case' only (within a store) - if (fgLogger.isDebugEnabled()) - { - fgLogger.debug("rename: only change case: from "+avmSrcPath+" to "+avmDstPath); - } - renameCase = true; - } - else - { - throw new AVMExistsException("Node exists: " + dstName); - } - } - - if (! renameCase) - { - // general rename/move - - Long parentAcl = dstDir.getAcl() == null ? null : dstDir.getAcl().getId(); - - AVMNode dstNode = null; - // We've passed the check, so we can go ahead and do the rename. - if (srcNode.getType() == AVMNodeType.PLAIN_DIRECTORY) - { - // If the source is layered then the renamed thing needs to be layered also. - if (sPath.isLayered()) - { - // If this is a rename happening in the same layer we make a new - // OverlayedDirectoryNode that is not a primary indirection layer. - // Otherwise we do make the new OverlayedDirectoryNode a primary - // Indirection layer. This complexity begs the question of whether - // we should allow renames from within one layer to within another - // layer. Allowing it makes the logic absurdly complex. - if (dPath.isLayered() && dPath.getTopLayer().equals(sPath.getTopLayer())) - { - dstNode = new LayeredDirectoryNodeImpl((PlainDirectoryNode) srcNode, dstRepo, sPath, true, parentAcl, ACLCopyMode.COPY); - ((LayeredDirectoryNode) dstNode).setLayerID(sPath.getTopLayer().getLayerID()); - } - else - { - dstNode = new LayeredDirectoryNodeImpl((DirectoryNode) srcNode, dstRepo, sPath, srcName, parentAcl, ACLCopyMode.COPY); - - // note: re-use generated node id as a layer id - ((LayeredDirectoryNode) dstNode).setLayerID(dstNode.getId()); - } - - AVMDAOs.Instance().fAVMNodeDAO.update(dstNode); - } - else - { - dstNode = new PlainDirectoryNodeImpl((PlainDirectoryNode) srcNode, dstRepo, parentAcl, ACLCopyMode.COPY); - } - } - else if (srcNode.getType() == AVMNodeType.LAYERED_DIRECTORY) - { - if (!sPath.isLayered() || (sPath.isInThisLayer() && srcDir.getType() == AVMNodeType.LAYERED_DIRECTORY && ((LayeredDirectoryNode) srcDir).directlyContains(srcNode))) - { - Lookup srcLookup = lookup(-1, srcPath + "/" + srcName, true); - // Use the simple 'copy' constructor. - dstNode = new LayeredDirectoryNodeImpl((LayeredDirectoryNode) srcNode, dstRepo, srcLookup, true, parentAcl, ACLCopyMode.COPY); - ((LayeredDirectoryNode) dstNode).setLayerID(((LayeredDirectoryNode) srcNode).getLayerID()); - } - else - { - // If the source node is a primary indirection, then the 'copy' constructor - // is used. Otherwise the alternate constructor is called and its - // indirection is calculated from it's source context. - if (((LayeredDirectoryNode) srcNode).getPrimaryIndirection()) - { - Lookup srcLookup = lookup(-1, srcPath + "/" + srcName, true); - dstNode = new LayeredDirectoryNodeImpl((LayeredDirectoryNode) srcNode, dstRepo, srcLookup, true, parentAcl, ACLCopyMode.COPY); - } - else - { - dstNode = new LayeredDirectoryNodeImpl((DirectoryNode) srcNode, dstRepo, sPath, srcName, parentAcl, ACLCopyMode.COPY); - } - // What needs to be done here is dependent on whether the - // rename is to a layered context. If so then it should get the layer id - // of its destination parent. Otherwise it should get a new layer - // id. - if (dPath.isLayered()) - { - ((LayeredDirectoryNode) dstNode).setLayerID(dPath.getTopLayer().getLayerID()); - } - else - { - // note: re-use generated node id as a layer id - ((LayeredDirectoryNode) dstNode).setLayerID(dstNode.getId()); - } - } - - AVMDAOs.Instance().fAVMNodeDAO.update(dstNode); - } - else if (srcNode.getType() == AVMNodeType.LAYERED_FILE) - { - dstNode = new LayeredFileNodeImpl((LayeredFileNode) srcNode, dstRepo, parentAcl, ACLCopyMode.COPY); - } - else - // This is a plain file node. - { - dstNode = new PlainFileNodeImpl((PlainFileNode) srcNode, dstRepo, parentAcl, ACLCopyMode.COPY); - } - - srcDir.removeChild(sPath, srcName); - // srcDir.updateModTime(); - // dstNode.setVersionID(dstRepo.getNextVersionID()); - if (child != null) - { - dstNode.setAncestor(child); - } - - //dstDir.updateModTime(); - dstDir.putChild(dstName, dstNode); - if (child == null) - { - dstNode.setAncestor(srcNode); - } - } - else - { - // specific rename 'case' only (within a store) - - forceCopy(AVMUtil.extendAVMPath(srcPath, srcName)); - - Pair result = srcDir.lookupChildEntry(sPath, srcName, false); - if (result != null) - { - ChildKey key = result.getFirst().getKey(); - key.setName(srcName); - AVMDAOs.Instance().fChildEntryDAO.rename(key, dstName); - } - } - - fLookupCache.onWrite(pathParts[0]); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Uncover a deleted name in a layered directory. - * - * @param dirPath - * The path to the layered directory. - * @param name - * The name to uncover. - */ - public void uncover(String dirPath, String name) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(dirPath); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.uncover(pathParts[1], name); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Create a snapshot of a single AVMStore. - * - * @param store - * The name of the repository. - * @param tag - * The short description. - * @param description - * The thick description. - * @return The version id of the newly snapshotted repository. - */ - public Map createSnapshot(String storeName, String tag, String description) - { - try - { - fAVMNodeDAO.noCache(); - AlfrescoTransactionSupport.bindListener(fCreateVersionTxnListener); - AVMStore store = getAVMStoreByName(storeName); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - Map result = store.createSnapshot(tag, description, new HashMap()); - for (Map.Entry entry : result.entrySet()) - { - fLookupCache.onSnapshot(entry.getKey()); - fCreateVersionTxnListener.versionCreated(entry.getKey(), entry.getValue()); - } - return result; - } - finally - { - fAVMNodeDAO.yesCache(); - } - } - - /** - * Remove a node and everything underneath it. - * - * @param path - * The path to the containing directory. - * @param name - * The name of the node to remove. - */ - public void remove(String path, String name) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onDelete(pathParts[0]); - store.removeNode(pathParts[1], name); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get rid of all content that lives only in the given AVMStore. Also removes the AVMStore. - * - * @param name - * The name of the AVMStore to purge. - */ - public void purgeAVMStore(String name) - { - AlfrescoTransactionSupport.bindListener(fPurgeStoreTxnListener); - AVMStore store = getAVMStoreByName(name); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onDelete(name); - AVMNode root = store.getRoot(); - // TODO Probably a special PermissionService.PURGE is needed. - if (!can(store, root, PermissionService.DELETE_CHILDREN, true)) - { - throw new AccessDeniedException("Not allowed to purge: " + name); - } - - fAVMNodeDAO.update(root); - - List vRoots = fVersionRootDAO.getAllInAVMStore(store); - for (VersionRoot vr : vRoots) - { - AVMNode node = fAVMNodeDAO.getByID(vr.getRoot().getId()); - fAVMNodeDAO.update(node); - - fVersionLayeredNodeEntryDAO.delete(vr); - fVersionRootDAO.delete(vr); - } - List newGuys = fAVMNodeDAO.getNewInStore(store); - for (AVMNode newGuy : newGuys) - { - newGuy.setStoreNew(null); - - fAVMNodeDAO.update(newGuy); - } - fAVMStorePropertyDAO.delete(store); - fAVMStoreDAO.delete(store); - fAVMStoreDAO.invalidateCache(); - fPurgeStoreTxnListener.storePurged(name); - } - - /** - * Remove all content specific to a AVMRepository and version. - * - * @param name - * The name of the AVMStore. - * @param version - * The version to purge. - */ - public void purgeVersion(String name, int version) - { - AlfrescoTransactionSupport.bindListener(fPurgeVersionTxnListener); - AVMStore store = getAVMStoreByName(name); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onDelete(name); - store.purgeVersion(version); - fPurgeVersionTxnListener.versionPurged(name, version); - } - - /** - * Get an input stream from a file. - * - * @param version - * The version to look under. - * @param path - * The path to the file. - * @return An InputStream. - */ - public InputStream getInputStream(int version, String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getInputStream(version, pathParts[1]); - } - finally - { - fLookupCount.set(null); - } - } - - public InputStream getInputStream(AVMNodeDescriptor desc) - { - AVMNode node = fAVMNodeDAO.getByID(desc.getId()); - if (!(node instanceof FileNode)) - { - throw new AVMWrongTypeException(desc + " is not a File."); - } - if (!can(null, node, PermissionService.READ_CONTENT, false)) - { - throw new AccessDeniedException("Not allowed to read content: " + desc); - } - FileNode file = (FileNode) node; - ContentData data = file.getContentData(null); - if (data == null) - { - throw new AVMException(desc + " has no content."); - } - ContentReader reader = fContentStore.getReader(data.getContentUrl()); - return reader.getContentInputStream(); - } - - /** - * Get a listing of a directory. - * - * @param version - * The version to look under. - * @param path - * The path to the directory. - * @param includeDeleted - * Whether to see DeletedNodes. - * @return A List of FolderEntries. - */ - public SortedMap getListing(int version, String path, boolean includeDeleted) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getListing(version, pathParts[1], includeDeleted); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get the list of nodes directly contained in a directory. - * - * @param version - * The version to look under. - * @param path - * The path to the directory to list. - * @return A Map of names to descriptors. - */ - public SortedMap getListingDirect(int version, String path, boolean includeDeleted) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getListingDirect(version, pathParts[1], includeDeleted); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get the list of nodes directly contained in a directory. - * - * @param dir - * The descriptor to the directory node. - * @param includeDeleted - * Whether to include deleted children. - * @return A Map of names to descriptors. - */ - public SortedMap getListingDirect(AVMNodeDescriptor dir, boolean includeDeleted) - { - AVMNode node = fAVMNodeDAO.getByID(dir.getId()); - if (node == null) - { - throw new AVMBadArgumentException("Invalid Node."); - } - if (!can(null, node, PermissionService.READ_CHILDREN, false)) - { - throw new AccessDeniedException("Not allowed to read children: " + dir); - } - if (node.getType() == AVMNodeType.PLAIN_DIRECTORY) - { - return getListing(dir, includeDeleted); - } - if (node.getType() != AVMNodeType.LAYERED_DIRECTORY) - { - throw new AVMWrongTypeException("Not a directory."); - } - LayeredDirectoryNode dirNode = (LayeredDirectoryNode) node; - return dirNode.getListingDirect(dir, includeDeleted); - } - - /** - * Get a directory listing from a directory node descriptor. - * - * @param dir - * The directory node descriptor. - * @return A SortedMap listing. - */ - public SortedMap getListing(AVMNodeDescriptor dir, boolean includeDeleted) - { - fLookupCount.set(1); - try - { - AVMNode node = fAVMNodeDAO.getByID(dir.getId()); - if (node == null) - { - throw new AVMBadArgumentException("Invalid Node."); - } - if (node.getType() != AVMNodeType.LAYERED_DIRECTORY && node.getType() != AVMNodeType.PLAIN_DIRECTORY) - { - throw new AVMWrongTypeException("Not a directory."); - } - if (!can(null, node, PermissionService.READ_CHILDREN, false)) - { - throw new AccessDeniedException("Not allowed to read children: " + dir); - } - DirectoryNode dirNode = (DirectoryNode) node; - SortedMap listing = dirNode.getListing(dir, includeDeleted); - return listing; - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get a directory listing from a directory node descriptor fo children that match the given pattern - * - * @param dir - * The directory node descriptor. - * @return A SortedMap listing. - */ - public SortedMap getListing(AVMNodeDescriptor dir, String childNamePattern, boolean includeDeleted) - { - fLookupCount.set(1); - try - { - AVMNode node = fAVMNodeDAO.getByID(dir.getId()); - if (node == null) - { - throw new AVMBadArgumentException("Invalid Node."); - } - if (node.getType() != AVMNodeType.LAYERED_DIRECTORY && node.getType() != AVMNodeType.PLAIN_DIRECTORY) - { - throw new AVMWrongTypeException("Not a directory."); - } - if (!can(null, node, PermissionService.READ_CHILDREN, false)) - { - throw new AccessDeniedException("Not allowed to read children: " + dir); - } - DirectoryNode dirNode = (DirectoryNode) node; - SortedMap listing = dirNode.getListing(dir, childNamePattern, includeDeleted); - return listing; - } - finally - { - fLookupCount.set(null); - } - } - - - /** - * Get the names of deleted nodes in a directory. - * - * @param version - * The version to look under. - * @param path - * The path to the directory. - * @return A List of names. - */ - public List getDeleted(int version, String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getDeleted(version, pathParts[1]); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get descriptors of all AVMStores. - * - * @return A list of all descriptors. - */ - public List getAVMStores() - { - List storeEntities = AVMDAOs.Instance().newAVMStoreDAO.getAllStores(); - - List result = new ArrayList(storeEntities.size()); - for (AVMStoreEntity storeEntity : storeEntities) - { - AVMStoreImpl store = new AVMStoreImpl(); - store.setId(storeEntity.getId()); - store.setName(storeEntity.getName()); - result.add(store.getDescriptor()); - } - - return result; - } - - /** - * Get a descriptor for an AVMStore. - * - * @param name - * The name to get. - * @return The descriptor. - */ - public AVMStoreDescriptor getAVMStore(String name) - { - AVMStore store = getAVMStoreByName(name); - if (store == null) - { - return null; - } - return store.getDescriptor(); - } - - /** - * Get all version for a given AVMStore. - * - * @param name - * The name of the AVMStore. - * @return A Set will all the version ids. - */ - public List getAVMStoreVersions(String name) - { - AVMStore store = getAVMStoreByName(name); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getVersions(); - } - - /** - * Get the set of versions between (inclusive) of the given dates. From or to may be null but not both. - * - * @param name - * The name of the AVMRepository. - * @param from - * The earliest date. - * @param to - * The latest date. - * @return The Set of version IDs. - */ - public List getAVMStoreVersions(String name, Date from, Date to) - { - AVMStore store = getAVMStoreByName(name); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getVersions(from, to); - } - - /** - * Get the indirection path for a layered node. - * - * @param version - * The version to look under. - * @param path - * The path to the node. - * @return The indirection path. - */ - public String getIndirectionPath(int version, String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getIndirectionPath(version, pathParts[1]); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get the next version id for the given AVMStore. - * - * @param name - * The name of the AVMStore. - * @return The next version id. - */ - public int getLatestVersionID(String name) - { - AVMStore store = getAVMStoreByName(name); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getNextVersionID(); - } - - /** - * Get the latest extant snapshotted version id. - * - * @param name - * The store name. - */ - public int getLatestSnapshotID(String name) - { - AVMStore store = getAVMStoreByName(name); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getLastVersionID(); - } - - /** - * Get an AVMStore by name. - * - * @param name - * The name of the AVMStore. - * @return The AVMStore. - */ - private AVMStore getAVMStoreByName(String name) - { - AVMStore store = fAVMStoreDAO.getByName(name); - return store; - } - - /** - * Get a descriptor for an AVMStore root. - * - * @param version - * The version to get. - * @param name - * The name of the AVMStore. - * @return The descriptor for the root. - */ - public AVMNodeDescriptor getAVMStoreRoot(int version, String name) - { - AVMStore store = getAVMStoreByName(name); - if (store == null) - { - throw new AVMNotFoundException("Not found: " + name); - } - return store.getRoot(version); - } - - // TODO Fix this awful mess regarding cycle detection. - /** - * Lookup a node. - * - * @param version - * The version to look under. - * @param path - * The path to lookup. - * @param includeDeleted - * Whether to see DeletedNodes. - * @return A lookup object. - */ - public Lookup lookup(int version, String path, boolean includeDeleted) - { - Integer count = fLookupCount.get(); - try - { - if (count == null) - { - fLookupCount.set(1); - } - else - { - fLookupCount.set(count + 1); - } - if (fLookupCount.get() > 50) - { - throw new AVMCycleException("Cycle in lookup."); - } - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - return null; - } - return store.lookup(version, pathParts[1], false, includeDeleted); - } - finally - { - if (count == null) - { - fLookupCount.set(null); - } - } - } - - /** - * Lookup a descriptor from a directory descriptor. - * - * @param dir - * The directory descriptor. - * @param name - * The name of the child to lookup. - * @return The child's descriptor. - */ - public AVMNodeDescriptor lookup(AVMNodeDescriptor dir, String name, boolean includeDeleted) - { - fLookupCount.set(1); - try - { - AVMNode node = fAVMNodeDAO.getByID(dir.getId()); - if (node == null) - { - throw new AVMNotFoundException("Not found: " + dir.getId()); - } - if (node.getType() != AVMNodeType.LAYERED_DIRECTORY && node.getType() != AVMNodeType.PLAIN_DIRECTORY) - { - throw new AVMWrongTypeException("Not a directory."); - } - DirectoryNode dirNode = (DirectoryNode) node; - if (!can(null, dirNode, PermissionService.READ_CHILDREN, false)) - { - throw new AccessDeniedException("Not allowed to read children: " + dir); - } - return dirNode.lookupChild(dir, name, includeDeleted); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get all the paths to a particular node. - * - * @param desc - * The node descriptor. - * @return The list of version, paths. - */ - public List> getPaths(AVMNodeDescriptor desc) - { - AVMNode node = fAVMNodeDAO.getByID(desc.getId()); - if (node == null) - { - throw new AVMNotFoundException("Not found: " + desc); - } - List> paths = new ArrayList>(); - List components = new ArrayList(); - recursiveGetPaths(node, components, paths); - return paths; - } - - /** - * Get a single valid path for a node. - * - * @param desc - * The node descriptor. - * @return A version, path - */ - public Pair getAPath(AVMNodeDescriptor desc) - { - AVMNode node = fAVMNodeDAO.getByID(desc.getId()); - if (node == null) - { - throw new AVMNotFoundException("Could not find node: " + desc); - } - if (fgLogger.isDebugEnabled()) - { - fgLogger.debug("Getting A Path for: " + desc); - } - List components = new ArrayList(); - return recursiveGetAPath(node, components); - } - - /** - * Get all paths for a node reachable by HEAD. - * - * @param desc - * The node descriptor. - * @return A List of all the version, path Pairs that match. - */ - public List> getHeadPaths(AVMNodeDescriptor desc) - { - AVMNode node = fAVMNodeDAO.getByID(desc.getId()); - if (node == null) - { - throw new AVMNotFoundException("Not found: " + desc.getPath()); - } - List> paths = new ArrayList>(); - List components = new ArrayList(); - recursiveGetHeadPaths(node, components, paths); - return paths; - } - - /** - * Gets all the pass from to the given node starting from the give version root. - * - * @param version - * The version root. - * @param node - * The node to get the paths of. - * @return A list of all paths in the given version to the node. - */ - public List getVersionPaths(VersionRoot version, AVMNode node) - { - List paths = new ArrayList(); - List components = new ArrayList(); - recursiveGetVersionPaths(node, components, paths, version.getRoot(), version.getAvmStore().getName()); - return paths; - } - - /** - * Helper to get all version paths. - * - * @param node - * The current node we are examining. - * @param components - * The current path components. - * @param paths - * The list to contain found paths. - * @param root - * The root node of the version. - * @param storeName - * The name of the store. - */ - private void recursiveGetVersionPaths(AVMNode node, List components, List paths, DirectoryNode root, String storeName) - { - if (!can(null, node, PermissionService.READ_CHILDREN, false)) - { - return; - } - if (node.equals(root)) - { - paths.add(this.makePath(components, storeName)); - return; - } - List entries = fChildEntryDAO.getByChild(node); - for (ChildEntry entry : entries) - { - String name = entry.getKey().getName(); - components.add(name); - AVMNode parent = entry.getKey().getParent(); - recursiveGetVersionPaths(parent, components, paths, root, storeName); - components.remove(components.size() - 1); - } - } - - /** - * Get all paths in a particular store in the head version for a particular node. - * - * @param desc - * The node descriptor. - * @param store - * The name of the store. - * @return All matching paths. - */ - public List> getPathsInStoreHead(AVMNodeDescriptor desc, String store) - { - AVMStore st = getAVMStoreByName(store); - if (st == null) - { - throw new AVMNotFoundException("Store not found: " + store); - } - AVMNode node = fAVMNodeDAO.getByID(desc.getId()); - if (node == null) - { - throw new AVMNotFoundException("Not found: " + desc); - } - List> paths = new ArrayList>(); - List components = new ArrayList(); - recursiveGetPathsInStoreHead(node, components, paths, st.getRoot(), store); - return paths; - } - - /** - * Do the actual work. - * - * @param node - * The current node. - * @param components - * The currently accumulated path components. - * @param paths - * The list to put full paths in. - */ - private void recursiveGetPaths(AVMNode node, List components, List> paths) - { - if (!can(null, node, PermissionService.READ_CHILDREN, false)) - { - return; - } - if (node.getIsRoot()) - { - AVMStore store = fAVMStoreDAO.getByRoot(node); - if (store != null) - { - addPath(components, -1, store.getName(), paths); - } - VersionRoot vr = fVersionRootDAO.getByRoot(node); - if (vr != null) - { - addPath(components, vr.getVersionID(), vr.getAvmStore().getName(), paths); - } - return; - } - List entries = fChildEntryDAO.getByChild(node); - for (ChildEntry entry : entries) - { - String name = entry.getKey().getName(); - components.add(name); - AVMNode parent = entry.getKey().getParent(); - recursiveGetPaths(parent, components, paths); - components.remove(components.size() - 1); - } - } - - /** - * Do the work of getting one path for a node. - * - * @param node - * The node to get the path of. - * @param components - * The storage for path components. - * @return A path or null. - */ - private Pair recursiveGetAPath(AVMNode node, List components) - { - if (!can(null, node, PermissionService.READ_CHILDREN, false)) - { - return null; - } - if (node.getIsRoot()) - { - AVMStore store = fAVMStoreDAO.getByRoot(node); - if (store != null) - { - if (fgLogger.isDebugEnabled()) - { - fgLogger.debug("Found path in HEAD of: " + store.getName()); - } - return new Pair(-1, makePath(components, store.getName())); - } - VersionRoot vr = fVersionRootDAO.getByRoot(node); - if (vr != null) - { - if (fgLogger.isDebugEnabled()) - { - fgLogger.debug("Found path in version " + vr.getVersionID() + " in: " + vr.getAvmStore().getName()); - } - return new Pair(vr.getVersionID(), makePath(components, vr.getAvmStore().getName())); - } - return null; - } - List entries = fChildEntryDAO.getByChild(node); - for (ChildEntry entry : entries) - { - String name = entry.getKey().getName(); - if (fgLogger.isDebugEnabled()) - { - fgLogger.debug("Found component: " + name); - } - components.add(name); - Pair path = recursiveGetAPath(entry.getKey().getParent(), components); - if (path != null) - { - return path; - } - components.remove(components.size() - 1); - } - return null; - } - - /** - * Do the actual work. - * - * @param node - * The current node. - * @param components - * The currently accumulated path components. - * @param paths - * The list to put full paths in. - */ - private void recursiveGetHeadPaths(AVMNode node, List components, List> paths) - { - if (!can(null, node, PermissionService.READ_CHILDREN, false)) - { - return; - } - if (node.getIsRoot()) - { - AVMStore store = fAVMStoreDAO.getByRoot(node); - if (store != null) - { - addPath(components, -1, store.getName(), paths); - return; - } - return; - } - List entries = fChildEntryDAO.getByChild(node); - for (ChildEntry entry : entries) - { - String name = entry.getKey().getName(); - components.add(name); - AVMNode parent = entry.getKey().getParent(); - recursiveGetHeadPaths(parent, components, paths); - components.remove(components.size() - 1); - } - } - - /** - * Do the actual work. - * - * @param node - * The current node. - * @param components - * The currently accumulated path components. - * @param paths - * The list to put full paths in. - */ - private void recursiveGetPathsInStoreHead(AVMNode node, List components, List> paths, DirectoryNode root, String storeName) - { - if (!can(null, node, PermissionService.READ_CHILDREN, false)) - { - return; - } - if (node.equals(root)) - { - addPath(components, -1, storeName, paths); - return; - } - List entries = fChildEntryDAO.getByChild(node); - for (ChildEntry entry : entries) - { - String name = entry.getKey().getName(); - components.add(name); - AVMNode parent = entry.getKey().getParent(); - recursiveGetHeadPaths(parent, components, paths); - components.remove(components.size() - 1); - } - } - - /** - * Add a path to the list. - * - * @param components - * The path name components. - * @param version - * The version id. - * @param storeName - * The name of the - * @param paths - * The List to add to. - */ - private void addPath(List components, int version, String storeName, List> paths) - { - paths.add(new Pair(version, makePath(components, storeName))); - } - - /** - * Alternate version. - * - * @param components - * @param storeName - * @param paths - */ - private void addPath(List components, String storeName, List paths) - { - paths.add(makePath(components, storeName)); - } - - /** - * Helper for generating paths. - * - * @param components - * The path components. - * @param storeName - * The store that the path is in. - * @return The path. - */ - private String makePath(List components, String storeName) - { - StringBuilder pathBuilder = new StringBuilder(); - pathBuilder.append(storeName); - pathBuilder.append(":"); - if (components.size() == 0) - { - pathBuilder.append("/"); - return pathBuilder.toString(); - } - for (int i = components.size() - 1; i >= 0; i--) - { - pathBuilder.append("/"); - pathBuilder.append(components.get(i)); - } - return pathBuilder.toString(); - } - - /** - * Get information about layering of a path. - * - * @param version - * The version to look under. - * @param path - * The full avm path. - * @return A LayeringDescriptor. - */ - public LayeringDescriptor getLayeringInfo(int version, String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - Lookup lookup = store.lookup(version, pathParts[1], false, true); - if (lookup == null) - { - throw new AVMNotFoundException("Path not found."); - } - if (!can(store, lookup.getCurrentNode(), PermissionService.READ_PROPERTIES, false)) - { - throw new AccessDeniedException("Not allowed to read properties: " + path); - } - return new LayeringDescriptor(!lookup.getDirectlyContained(), lookup.getAVMStore().getDescriptor(), lookup.getFinalStore().getDescriptor()); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Lookup a directory specifically. - * - * @param version - * The version to look under. - * @param path - * The path to lookup. - * @return A lookup object. - */ - public Lookup lookupDirectory(int version, String path) - { - Integer count = fLookupCount.get(); - try - { - if (count == null) - { - fLookupCount.set(1); - } - fLookupCount.set(fLookupCount.get() + 1); - if (fLookupCount.get() > 50) - { - throw new AVMCycleException("Cycle in lookup."); - } - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - return null; - } - return store.lookupDirectory(version, pathParts[1], false); - } - finally - { - if (count == null) - { - fLookupCount.set(null); - } - } - } - - /** - * Utility to split a path, foo:bar/baz into its repository and path parts. - * - * @param path - * The fully qualified path. - * @return The repository name and the repository path. - */ - private String[] SplitPath(String path) - { - return AVMUtil.splitPath(path); - } - - /** - * Make a directory into a primary indirection. - * - * @param path - * The full path. - */ - public void makePrimary(String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.makePrimary(pathParts[1]); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Change what a layered directory points at. - * - * @param path - * The full path to the layered directory. - * @param target - * The new target path. - */ - public void retargetLayeredDirectory(String path, String target) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.retargetLayeredDirectory(pathParts[1], target); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get the history chain for a node. - * - * @param desc - * The node to get history of. - * @param count - * The maximum number of ancestors to traverse. Negative means all. - * @return A List of ancestors. - */ - public List getHistory(AVMNodeDescriptor desc, int count) - { - AVMNode node = fAVMNodeDAO.getByID(desc.getId()); - if (node == null) - { - throw new AVMNotFoundException("Not found."); - } - if (!can(null, node, PermissionService.READ_PROPERTIES, false)) - { - throw new AccessDeniedException("Not allowed to read properties: " + desc); - } - if (count < 0) - { - count = Integer.MAX_VALUE; - } - List history = new ArrayList(); - for (int i = 0; i < count; i++) - { - AVMNode ancNode = node.getAncestor(); - if (ancNode == null) + * along with Alfresco. If not, see . */ + +package org.alfresco.repo.avm; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; + +import org.alfresco.model.WCMModel; +import org.alfresco.repo.avm.util.AVMUtil; +import org.alfresco.repo.content.ContentStore; +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.domain.avm.AVMStoreEntity; +import org.alfresco.repo.domain.qname.QNameDAO; +import org.alfresco.repo.security.permissions.ACLCopyMode; +import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.service.cmr.avm.AVMBadArgumentException; +import org.alfresco.service.cmr.avm.AVMCycleException; +import org.alfresco.service.cmr.avm.AVMException; +import org.alfresco.service.cmr.avm.AVMExistsException; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.cmr.avm.AVMNotFoundException; +import org.alfresco.service.cmr.avm.AVMStoreDescriptor; +import org.alfresco.service.cmr.avm.AVMWrongTypeException; +import org.alfresco.service.cmr.avm.LayeringDescriptor; +import org.alfresco.service.cmr.avm.VersionDescriptor; +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.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.PermissionContext; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.FileNameValidator; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.alfresco.util.Pair; + +/** + * This or AVMStore are the implementors of the operations specified by AVMService. + * + * @author britt + */ +public class AVMRepository +{ + private static Log fgLogger = LogFactory.getLog(AVMRepository.class); + + /** + * The single instance of AVMRepository. + */ + private static AVMRepository fgInstance; + + /** + * The current lookup count. + */ + private ThreadLocal fLookupCount; + + /** + * Reference to the ContentStoreImpl + */ + private ContentStore fContentStore; + + /** + * The Lookup Cache instance. + */ + private LookupCache fLookupCache; + + private QNameDAO qnameDAO; + + private AVMStoreDAO fAVMStoreDAO; + + private AVMNodeDAO fAVMNodeDAO; + + private VersionRootDAO fVersionRootDAO; + + private VersionLayeredNodeEntryDAO fVersionLayeredNodeEntryDAO; + + private AVMStorePropertyDAO fAVMStorePropertyDAO; + + private ChildEntryDAO fChildEntryDAO; + + private PermissionService fPermissionService; + + private DictionaryService fDictionaryService; + + // A bunch of TransactionListeners that do work for this. + + /** + * One for create store. + */ + private CreateStoreTxnListener fCreateStoreTxnListener; + + /** + * One for purge store. + */ + private PurgeStoreTxnListener fPurgeStoreTxnListener; + + /** + * One for create version. + */ + private CreateVersionTxnListener fCreateVersionTxnListener; + + /** + * One for purge version. + */ + private PurgeVersionTxnListener fPurgeVersionTxnListener; + + /** + * Create a new one. + */ + public AVMRepository() + { + fLookupCount = new ThreadLocal(); + fgInstance = this; + } + + /** + * Set the ContentService. + */ + public void setContentStore(ContentStore store) + { + fContentStore = store; + } + + /** + * Set the Lookup Cache instance. + * + * @param cache + * The instance to set. + */ + public void setLookupCache(LookupCache cache) + { + fLookupCache = cache; + } + + public void setCreateStoreTxnListener(CreateStoreTxnListener listener) + { + fCreateStoreTxnListener = listener; + } + + public void setPurgeStoreTxnListener(PurgeStoreTxnListener listener) + { + fPurgeStoreTxnListener = listener; + } + + public void setCreateVersionTxnListener(CreateVersionTxnListener listener) + { + fCreateVersionTxnListener = listener; + } + + public void setPurgeVersionTxnListener(PurgeVersionTxnListener listener) + { + fPurgeVersionTxnListener = listener; + } + + public void setQnameDAO(QNameDAO qnameDAO) + { + this.qnameDAO = qnameDAO; + } + + public void setAvmStoreDAO(AVMStoreDAO dao) + { + fAVMStoreDAO = dao; + } + + public void setAvmNodeDAO(AVMNodeDAO dao) + { + fAVMNodeDAO = dao; + } + + public void setVersionRootDAO(VersionRootDAO dao) + { + fVersionRootDAO = dao; + } + + public void setVersionLayeredNodeEntryDAO(VersionLayeredNodeEntryDAO dao) + { + fVersionLayeredNodeEntryDAO = dao; + } + + public void setAvmStorePropertyDAO(AVMStorePropertyDAO dao) + { + fAVMStorePropertyDAO = dao; + } + + public void setChildEntryDAO(ChildEntryDAO dao) + { + fChildEntryDAO = dao; + } + + public void setPermissionService(PermissionService service) + { + fPermissionService = service; + } + + public void setDictionaryService(DictionaryService service) + { + fDictionaryService = service; + } + + /** + * Create a file. + * + * @param path + * The path to the containing directory. + * @param name + * The name for the new file. + */ + public OutputStream createFile(String path, String name) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + OutputStream out = store.createFile(pathParts[1], name); + return out; + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Create a file with the given File as content. + * + * @param path + * The path to the containing directory. + * @param name + * The name to give the file. + * @param data + * The file contents. + */ + public void createFile(String path, String name, File data, List aspects, Map properties) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.createFile(pathParts[1], name, data, aspects, properties); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Create a new directory. + * + * @param path + * The path to the containing directory. + * @param name + * The name to give the directory. + */ + public void createDirectory(String path, String name, List aspects, Map properties) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.createDirectory(pathParts[1], name, aspects, properties); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Create a new directory. This assumes that the parent is already copied and therefore should only be used with + * great care. + * + * @param parent + * The parent node. + * @param name + * The name of the new directory. + * @return A descriptor for the newly created directory. + */ + public AVMNodeDescriptor createDirectory(AVMNodeDescriptor parent, String name) + { + AVMNode node = fAVMNodeDAO.getByID(parent.getId()); + if (node == null) + { + throw new AVMNotFoundException(parent.getId() + " not found."); + } + if (!(node instanceof DirectoryNode)) + { + throw new AVMWrongTypeException("Not a directory."); + } + if (!can(null, node, PermissionService.CREATE_CHILDREN, true)) + { + throw new AccessDeniedException("Not allowed to write in: " + parent); + } + // We need the store to do anything so... + String[] pathParts = SplitPath(parent.getPath()); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + DirectoryNode dir = (DirectoryNode) node; + DirectoryNode child = null; + Long parentAcl = dir.getAcl() == null ? null : dir.getAcl().getId(); + if (dir instanceof LayeredDirectoryNode) + { + // TODO - collapse save/update + child = new LayeredDirectoryNodeImpl((String) null, store, null, parentAcl, ACLCopyMode.INHERIT); + ((LayeredDirectoryNode) child).setPrimaryIndirection(false); + ((LayeredDirectoryNode) child).setLayerID(parent.getLayerID()); + + child.copyACLs(dir, ACLCopyMode.INHERIT); + + AVMDAOs.Instance().fAVMNodeDAO.update(child); + } + else + { + child = new PlainDirectoryNodeImpl(store); + + child.copyACLs(dir, ACLCopyMode.INHERIT); + + AVMDAOs.Instance().fAVMNodeDAO.save(child); + } + + dir.putChild(name, child); + + fLookupCache.onWrite(pathParts[0]); + AVMNodeDescriptor desc = child.getDescriptor(parent.getPath(), name, parent.getIndirection(), parent.getIndirectionVersion()); + return desc; + } + + /** + * Create a new layered directory. + * + * @param srcPath + * The target indirection for the new layered directory. + * @param dstPath + * The path to the containing directory. + * @param name + * The name for the new directory. + */ + public void createLayeredDirectory(String srcPath, String dstPath, String name) + { + if (dstPath.indexOf(srcPath) == 0) + { + throw new AVMCycleException("Cycle would be created."); + } + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(dstPath); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.createLayeredDirectory(srcPath, pathParts[1], name); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Create a new layered file. + * + * @param srcPath + * The target indirection for the new layered file. + * @param dstPath + * The path to the containing directory. + * @param name + * The name of the new layered file. + */ + public void createLayeredFile(String srcPath, String dstPath, String name) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(dstPath); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.createLayeredFile(srcPath, pathParts[1], name); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Create a new AVMStore. + * + * @param name + * The name to give the new AVMStore. + */ + public void createAVMStore(String name) + { + createAVMStore(name, null); + } + + public void createAVMStore(String name, Map props) + { + AlfrescoTransactionSupport.bindListener(fCreateStoreTxnListener); + if (getAVMStoreByName(name) != null) + { + throw new AVMExistsException("AVMStore exists: " + name); + } + // Newing up the object causes it to be written to the db. + AVMStore rep = new AVMStoreImpl(this, name); + + // Special handling for AVMStore creation. + AVMNode rootNode = rep.getRoot(); + rootNode.setStoreNew(null); + fAVMNodeDAO.update(rootNode); + + + if (props != null) + { + setStoreProperties(name, props); + } + + fCreateStoreTxnListener.storeCreated(name); + } + + /** + * Create a new branch. + * + * @param version + * The version to branch off. + * @param srcPath + * The path to make a branch from. + * @param dstPath + * The containing directory. + * @param name + * The name of the new branch. + */ + public void createBranch(int version, String srcPath, String dstPath, String name) + { + if (dstPath.indexOf(srcPath) == 0) + { + throw new AVMCycleException("Cycle would be created."); + } + // Lookup the src node. + fLookupCount.set(1); + String[] pathParts; + Lookup sPath; + List layeredEntries = null; + try + { + pathParts = SplitPath(srcPath); + AVMStore srcRepo = getAVMStoreByName(pathParts[0]); + if (srcRepo == null) + { + throw new AVMNotFoundException("Store not found."); + } + if (version < 0) + { + fLookupCache.onSnapshot(pathParts[0]); + version = srcRepo.createSnapshot("Branch Snapshot", null, new HashMap()).get(pathParts[0]); + } + sPath = srcRepo.lookup(version, pathParts[1], false, false); + if (sPath == null) + { + throw new AVMNotFoundException("Path not found."); + } + VersionRoot lastVersion = fVersionRootDAO.getByVersionID(srcRepo, version); + layeredEntries = fVersionLayeredNodeEntryDAO.get(lastVersion); + } + finally + { + fLookupCount.set(null); + } + // Lookup the destination directory. + fLookupCount.set(1); + try + { + pathParts = SplitPath(dstPath); + AVMStore dstRepo = getAVMStoreByName(pathParts[0]); + if (dstRepo == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true); + if (dPath == null) + { + throw new AVMNotFoundException("Path not found."); + } + DirectoryNode dirNode = (DirectoryNode) dPath.getCurrentNode(); + if (!can(dstRepo, dirNode, PermissionService.ADD_CHILDREN, dPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not permitted to add children: " + dstPath); + } + AVMNode srcNode = sPath.getCurrentNode(); + AVMNode dstNode = null; + // We do different things depending on what kind of thing we're + // branching from. I'd be considerably happier if we disallowed + // certain scenarios, but Jon won't let me :P (bhp). + + Long inheritAcl = srcNode.getAcl() == null ? null : srcNode.getAcl().getId(); + + if (srcNode.getType() == AVMNodeType.PLAIN_DIRECTORY) + { + dstNode = new PlainDirectoryNodeImpl((PlainDirectoryNode) srcNode, dstRepo, inheritAcl, ACLCopyMode.INHERIT); + } + else if (srcNode.getType() == AVMNodeType.LAYERED_DIRECTORY) + { + dstNode = new LayeredDirectoryNodeImpl((LayeredDirectoryNode) srcNode, dstRepo, sPath, false, inheritAcl, ACLCopyMode.INHERIT); + + // note: re-use generated node id as a layer id + ((LayeredDirectoryNode) dstNode).setLayerID(dstNode.getId()); + + AVMDAOs.Instance().fAVMNodeDAO.update(dstNode); + } + else if (srcNode.getType() == AVMNodeType.LAYERED_FILE) + { + dstNode = new LayeredFileNodeImpl((LayeredFileNode) srcNode, dstRepo, inheritAcl, ACLCopyMode.INHERIT); + } + else + // This is a plain file. + { + dstNode = new PlainFileNodeImpl((PlainFileNode) srcNode, dstRepo, inheritAcl, ACLCopyMode.INHERIT); + } + // dstNode.setVersionID(dstRepo.getNextVersionID()); + dstNode.setAncestor(srcNode); + dirNode.putChild(name, dstNode); + // dirNode.updateModTime(); + String beginingPath = AVMUtil.normalizePath(srcPath); + String finalPath = AVMUtil.extendAVMPath(dstPath, name); + finalPath = AVMUtil.normalizePath(finalPath); + VersionRoot latestVersion = fVersionRootDAO.getMaxVersion(dstRepo); + for (VersionLayeredNodeEntry entry : layeredEntries) + { + String path = entry.getPath(); + if (!path.startsWith(srcPath)) + { + continue; + } + String newPath = finalPath + path.substring(beginingPath.length()); + VersionLayeredNodeEntry newEntry = new VersionLayeredNodeEntryImpl(latestVersion, newPath); + fVersionLayeredNodeEntryDAO.save(newEntry); + } + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get an output stream to a file. + * + * @param path + * The full path to the file. + * @return An OutputStream. + */ + public OutputStream getOutputStream(String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + OutputStream out = store.getOutputStream(pathParts[1]); + return out; + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get a content reader from a file node. + * + * @param version + * The version of the file. + * @param path + * The path to the file. + * @return A ContentReader. + */ + public ContentReader getContentReader(int version, String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found: " + pathParts[0]); + } + return store.getContentReader(version, pathParts[1]); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get a ContentWriter to a file node. + * + * @param path + * The path to the file. + * @param update true if the property must be updated atomically when the content write + * stream is closed (attaches a listener to the stream); false if the client code + * will perform the updates itself. + * @return A ContentWriter. + */ + public ContentWriter createContentWriter(String path, boolean update) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found: " + pathParts[0]); + } + fLookupCache.onWrite(pathParts[0]); + ContentWriter writer = store.createContentWriter(pathParts[1], update); + return writer; + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Rename a node. + * + * @param srcPath + * Source containing directory. + * @param srcName + * Source name. + * @param dstPath + * Destination containing directory. + * @param dstName + * Destination name. + */ + public void rename(String srcPath, String srcName, String dstPath, String dstName) + { + // This is about as ugly as it gets. + if ((dstPath + "/").indexOf(srcPath + srcName + "/") == 0) + { + throw new AVMCycleException("Cyclic rename."); + } + fLookupCount.set(1); + String[] pathParts; + Lookup sPath; + DirectoryNode srcDir; + AVMNode srcNode; + try + { + pathParts = SplitPath(srcPath); + AVMStore srcRepo = getAVMStoreByName(pathParts[0]); + if (srcRepo == null) + { + throw new AVMNotFoundException("Store not found."); + } + sPath = srcRepo.lookupDirectory(-1, pathParts[1], true); + if (sPath == null) + { + throw new AVMNotFoundException("Path not found."); + } + srcDir = (DirectoryNode) sPath.getCurrentNode(); + + Pair temp = srcDir.lookupChild(sPath, srcName, false); + srcNode = (temp == null) ? null : temp.getFirst(); + if (srcNode == null) + { + throw new AVMNotFoundException("Not found: " + srcName); + } + if (!can(srcRepo, srcNode, PermissionService.DELETE_NODE, false)) + { + throw new AccessDeniedException("Not allowed to delete target: " + srcPath); + } + + fLookupCache.onDelete(pathParts[0]); + } + finally + { + fLookupCount.set(null); + } + fLookupCount.set(1); + try + { + pathParts = SplitPath(dstPath); + AVMStore dstRepo = getAVMStoreByName(pathParts[0]); + if (dstRepo == null) + { + throw new AVMNotFoundException("Store not found."); + } + Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true); + if (dPath == null) + { + throw new AVMNotFoundException("Path not found."); + } + DirectoryNode dstDir = (DirectoryNode) dPath.getCurrentNode(); + if (!can(dstRepo, dstDir, PermissionService.ADD_CHILDREN, dPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write: " + dstPath); + } + Pair temp = dstDir.lookupChild(dPath, dstName, true); + AVMNode child = (temp == null) ? null : temp.getFirst(); + + boolean renameCase = false; + if (child != null && child.getType() != AVMNodeType.DELETED_NODE) + { + String avmSrcPath = AVMUtil.extendAVMPath(srcPath, srcName); + String avmDstPath = AVMUtil.extendAVMPath(dstPath, dstName); + + if ((avmSrcPath.equalsIgnoreCase(avmDstPath)) && (! srcName.equals(dstName))) + { + // specific rename 'case' only (within a store) + if (fgLogger.isDebugEnabled()) + { + fgLogger.debug("rename: only change case: from "+avmSrcPath+" to "+avmDstPath); + } + renameCase = true; + } + else + { + throw new AVMExistsException("Node exists: " + dstName); + } + } + + if (! renameCase) + { + // general rename/move + + Long parentAcl = dstDir.getAcl() == null ? null : dstDir.getAcl().getId(); + + AVMNode dstNode = null; + // We've passed the check, so we can go ahead and do the rename. + if (srcNode.getType() == AVMNodeType.PLAIN_DIRECTORY) + { + // If the source is layered then the renamed thing needs to be layered also. + if (sPath.isLayered()) + { + // If this is a rename happening in the same layer we make a new + // OverlayedDirectoryNode that is not a primary indirection layer. + // Otherwise we do make the new OverlayedDirectoryNode a primary + // Indirection layer. This complexity begs the question of whether + // we should allow renames from within one layer to within another + // layer. Allowing it makes the logic absurdly complex. + if (dPath.isLayered() && dPath.getTopLayer().equals(sPath.getTopLayer())) + { + dstNode = new LayeredDirectoryNodeImpl((PlainDirectoryNode) srcNode, dstRepo, sPath, true, parentAcl, ACLCopyMode.COPY); + ((LayeredDirectoryNode) dstNode).setLayerID(sPath.getTopLayer().getLayerID()); + } + else + { + dstNode = new LayeredDirectoryNodeImpl((DirectoryNode) srcNode, dstRepo, sPath, srcName, parentAcl, ACLCopyMode.COPY); + + // note: re-use generated node id as a layer id + ((LayeredDirectoryNode) dstNode).setLayerID(dstNode.getId()); + } + + AVMDAOs.Instance().fAVMNodeDAO.update(dstNode); + } + else + { + dstNode = new PlainDirectoryNodeImpl((PlainDirectoryNode) srcNode, dstRepo, parentAcl, ACLCopyMode.COPY); + } + } + else if (srcNode.getType() == AVMNodeType.LAYERED_DIRECTORY) + { + if (!sPath.isLayered() || (sPath.isInThisLayer() && srcDir.getType() == AVMNodeType.LAYERED_DIRECTORY && ((LayeredDirectoryNode) srcDir).directlyContains(srcNode))) + { + Lookup srcLookup = lookup(-1, srcPath + "/" + srcName, true); + // Use the simple 'copy' constructor. + dstNode = new LayeredDirectoryNodeImpl((LayeredDirectoryNode) srcNode, dstRepo, srcLookup, true, parentAcl, ACLCopyMode.COPY); + ((LayeredDirectoryNode) dstNode).setLayerID(((LayeredDirectoryNode) srcNode).getLayerID()); + } + else + { + // If the source node is a primary indirection, then the 'copy' constructor + // is used. Otherwise the alternate constructor is called and its + // indirection is calculated from it's source context. + if (((LayeredDirectoryNode) srcNode).getPrimaryIndirection()) + { + Lookup srcLookup = lookup(-1, srcPath + "/" + srcName, true); + dstNode = new LayeredDirectoryNodeImpl((LayeredDirectoryNode) srcNode, dstRepo, srcLookup, true, parentAcl, ACLCopyMode.COPY); + } + else + { + dstNode = new LayeredDirectoryNodeImpl((DirectoryNode) srcNode, dstRepo, sPath, srcName, parentAcl, ACLCopyMode.COPY); + } + // What needs to be done here is dependent on whether the + // rename is to a layered context. If so then it should get the layer id + // of its destination parent. Otherwise it should get a new layer + // id. + if (dPath.isLayered()) + { + ((LayeredDirectoryNode) dstNode).setLayerID(dPath.getTopLayer().getLayerID()); + } + else + { + // note: re-use generated node id as a layer id + ((LayeredDirectoryNode) dstNode).setLayerID(dstNode.getId()); + } + } + + AVMDAOs.Instance().fAVMNodeDAO.update(dstNode); + } + else if (srcNode.getType() == AVMNodeType.LAYERED_FILE) + { + dstNode = new LayeredFileNodeImpl((LayeredFileNode) srcNode, dstRepo, parentAcl, ACLCopyMode.COPY); + } + else + // This is a plain file node. + { + dstNode = new PlainFileNodeImpl((PlainFileNode) srcNode, dstRepo, parentAcl, ACLCopyMode.COPY); + } + + srcDir.removeChild(sPath, srcName); + // srcDir.updateModTime(); + // dstNode.setVersionID(dstRepo.getNextVersionID()); + if (child != null) + { + dstNode.setAncestor(child); + } + + //dstDir.updateModTime(); + dstDir.putChild(dstName, dstNode); + if (child == null) + { + dstNode.setAncestor(srcNode); + } + } + else + { + // specific rename 'case' only (within a store) + + forceCopy(AVMUtil.extendAVMPath(srcPath, srcName)); + + Pair result = srcDir.lookupChildEntry(sPath, srcName, false); + if (result != null) + { + ChildKey key = result.getFirst().getKey(); + key.setName(srcName); + AVMDAOs.Instance().fChildEntryDAO.rename(key, dstName); + } + } + + fLookupCache.onWrite(pathParts[0]); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Uncover a deleted name in a layered directory. + * + * @param dirPath + * The path to the layered directory. + * @param name + * The name to uncover. + */ + public void uncover(String dirPath, String name) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(dirPath); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.uncover(pathParts[1], name); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Create a snapshot of a single AVMStore. + * + * @param store + * The name of the repository. + * @param tag + * The short description. + * @param description + * The thick description. + * @return The version id of the newly snapshotted repository. + */ + public Map createSnapshot(String storeName, String tag, String description) + { + AlfrescoTransactionSupport.bindListener(fCreateVersionTxnListener); + AVMStore store = getAVMStoreByName(storeName); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + Map result = store.createSnapshot(tag, description, new HashMap()); + for (Map.Entry entry : result.entrySet()) + { + fLookupCache.onSnapshot(entry.getKey()); + fCreateVersionTxnListener.versionCreated(entry.getKey(), entry.getValue()); + } + return result; + } + + /** + * Remove a node and everything underneath it. + * + * @param path + * The path to the containing directory. + * @param name + * The name of the node to remove. + */ + public void remove(String path, String name) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onDelete(pathParts[0]); + store.removeNode(pathParts[1], name); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get rid of all content that lives only in the given AVMStore. Also removes the AVMStore. + * + * @param name + * The name of the AVMStore to purge. + */ + public void purgeAVMStore(String name) + { + AlfrescoTransactionSupport.bindListener(fPurgeStoreTxnListener); + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onDelete(name); + AVMNode root = store.getRoot(); + // TODO Probably a special PermissionService.PURGE is needed. + if (!can(store, root, PermissionService.DELETE_CHILDREN, true)) + { + throw new AccessDeniedException("Not allowed to purge: " + name); + } + + fAVMNodeDAO.update(root); + + List vRoots = fVersionRootDAO.getAllInAVMStore(store); + for (VersionRoot vr : vRoots) + { + AVMNode node = fAVMNodeDAO.getByID(vr.getRoot().getId()); + fAVMNodeDAO.update(node); + + fVersionLayeredNodeEntryDAO.delete(vr); + fVersionRootDAO.delete(vr); + } + List newGuys = fAVMNodeDAO.getNewInStore(store); + for (AVMNode newGuy : newGuys) + { + newGuy.setStoreNew(null); + + fAVMNodeDAO.update(newGuy); + } + fAVMStorePropertyDAO.delete(store); + fAVMStoreDAO.delete(store); + fAVMStoreDAO.invalidateCache(); + fPurgeStoreTxnListener.storePurged(name); + } + + /** + * Remove all content specific to a AVMRepository and version. + * + * @param name + * The name of the AVMStore. + * @param version + * The version to purge. + */ + public void purgeVersion(String name, int version) + { + AlfrescoTransactionSupport.bindListener(fPurgeVersionTxnListener); + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onDelete(name); + store.purgeVersion(version); + fPurgeVersionTxnListener.versionPurged(name, version); + } + + /** + * Get an input stream from a file. + * + * @param version + * The version to look under. + * @param path + * The path to the file. + * @return An InputStream. + */ + public InputStream getInputStream(int version, String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getInputStream(version, pathParts[1]); + } + finally + { + fLookupCount.set(null); + } + } + + public InputStream getInputStream(AVMNodeDescriptor desc) + { + AVMNode node = fAVMNodeDAO.getByID(desc.getId()); + if (!(node instanceof FileNode)) + { + throw new AVMWrongTypeException(desc + " is not a File."); + } + if (!can(null, node, PermissionService.READ_CONTENT, false)) + { + throw new AccessDeniedException("Not allowed to read content: " + desc); + } + FileNode file = (FileNode) node; + ContentData data = file.getContentData(null); + if (data == null) + { + throw new AVMException(desc + " has no content."); + } + ContentReader reader = fContentStore.getReader(data.getContentUrl()); + return reader.getContentInputStream(); + } + + /** + * Get a listing of a directory. + * + * @param version + * The version to look under. + * @param path + * The path to the directory. + * @param includeDeleted + * Whether to see DeletedNodes. + * @return A List of FolderEntries. + */ + public SortedMap getListing(int version, String path, boolean includeDeleted) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getListing(version, pathParts[1], includeDeleted); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get the list of nodes directly contained in a directory. + * + * @param version + * The version to look under. + * @param path + * The path to the directory to list. + * @return A Map of names to descriptors. + */ + public SortedMap getListingDirect(int version, String path, boolean includeDeleted) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getListingDirect(version, pathParts[1], includeDeleted); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get the list of nodes directly contained in a directory. + * + * @param dir + * The descriptor to the directory node. + * @param includeDeleted + * Whether to include deleted children. + * @return A Map of names to descriptors. + */ + public SortedMap getListingDirect(AVMNodeDescriptor dir, boolean includeDeleted) + { + AVMNode node = fAVMNodeDAO.getByID(dir.getId()); + if (node == null) + { + throw new AVMBadArgumentException("Invalid Node."); + } + if (!can(null, node, PermissionService.READ_CHILDREN, false)) + { + throw new AccessDeniedException("Not allowed to read children: " + dir); + } + if (node.getType() == AVMNodeType.PLAIN_DIRECTORY) + { + return getListing(dir, includeDeleted); + } + if (node.getType() != AVMNodeType.LAYERED_DIRECTORY) + { + throw new AVMWrongTypeException("Not a directory."); + } + LayeredDirectoryNode dirNode = (LayeredDirectoryNode) node; + return dirNode.getListingDirect(dir, includeDeleted); + } + + /** + * Get a directory listing from a directory node descriptor. + * + * @param dir + * The directory node descriptor. + * @return A SortedMap listing. + */ + public SortedMap getListing(AVMNodeDescriptor dir, boolean includeDeleted) + { + fLookupCount.set(1); + try + { + AVMNode node = fAVMNodeDAO.getByID(dir.getId()); + if (node == null) + { + throw new AVMBadArgumentException("Invalid Node."); + } + if (node.getType() != AVMNodeType.LAYERED_DIRECTORY && node.getType() != AVMNodeType.PLAIN_DIRECTORY) + { + throw new AVMWrongTypeException("Not a directory."); + } + if (!can(null, node, PermissionService.READ_CHILDREN, false)) + { + throw new AccessDeniedException("Not allowed to read children: " + dir); + } + DirectoryNode dirNode = (DirectoryNode) node; + SortedMap listing = dirNode.getListing(dir, includeDeleted); + return listing; + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get a directory listing from a directory node descriptor fo children that match the given pattern + * + * @param dir + * The directory node descriptor. + * @return A SortedMap listing. + */ + public SortedMap getListing(AVMNodeDescriptor dir, String childNamePattern, boolean includeDeleted) + { + fLookupCount.set(1); + try + { + AVMNode node = fAVMNodeDAO.getByID(dir.getId()); + if (node == null) + { + throw new AVMBadArgumentException("Invalid Node."); + } + if (node.getType() != AVMNodeType.LAYERED_DIRECTORY && node.getType() != AVMNodeType.PLAIN_DIRECTORY) + { + throw new AVMWrongTypeException("Not a directory."); + } + if (!can(null, node, PermissionService.READ_CHILDREN, false)) + { + throw new AccessDeniedException("Not allowed to read children: " + dir); + } + DirectoryNode dirNode = (DirectoryNode) node; + SortedMap listing = dirNode.getListing(dir, childNamePattern, includeDeleted); + return listing; + } + finally + { + fLookupCount.set(null); + } + } + + + /** + * Get the names of deleted nodes in a directory. + * + * @param version + * The version to look under. + * @param path + * The path to the directory. + * @return A List of names. + */ + public List getDeleted(int version, String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getDeleted(version, pathParts[1]); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get descriptors of all AVMStores. + * + * @return A list of all descriptors. + */ + public List getAVMStores() + { + List storeEntities = AVMDAOs.Instance().newAVMStoreDAO.getAllStores(); + + List result = new ArrayList(storeEntities.size()); + for (AVMStoreEntity storeEntity : storeEntities) + { + AVMStoreImpl store = new AVMStoreImpl(); + store.setId(storeEntity.getId()); + store.setName(storeEntity.getName()); + result.add(store.getDescriptor()); + } + + return result; + } + + /** + * Get a descriptor for an AVMStore. + * + * @param name + * The name to get. + * @return The descriptor. + */ + public AVMStoreDescriptor getAVMStore(String name) + { + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + return null; + } + return store.getDescriptor(); + } + + /** + * Get all version for a given AVMStore. + * + * @param name + * The name of the AVMStore. + * @return A Set will all the version ids. + */ + public List getAVMStoreVersions(String name) + { + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getVersions(); + } + + /** + * Get the set of versions between (inclusive) of the given dates. From or to may be null but not both. + * + * @param name + * The name of the AVMRepository. + * @param from + * The earliest date. + * @param to + * The latest date. + * @return The Set of version IDs. + */ + public List getAVMStoreVersions(String name, Date from, Date to) + { + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getVersions(from, to); + } + + /** + * Get the indirection path for a layered node. + * + * @param version + * The version to look under. + * @param path + * The path to the node. + * @return The indirection path. + */ + public String getIndirectionPath(int version, String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getIndirectionPath(version, pathParts[1]); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get the next version id for the given AVMStore. + * + * @param name + * The name of the AVMStore. + * @return The next version id. + */ + public int getLatestVersionID(String name) + { + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getNextVersionID(); + } + + /** + * Get the latest extant snapshotted version id. + * + * @param name + * The store name. + */ + public int getLatestSnapshotID(String name) + { + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getLastVersionID(); + } + + /** + * Get an AVMStore by name. + * + * @param name + * The name of the AVMStore. + * @return The AVMStore. + */ + private AVMStore getAVMStoreByName(String name) + { + AVMStore store = fAVMStoreDAO.getByName(name); + return store; + } + + /** + * Get a descriptor for an AVMStore root. + * + * @param version + * The version to get. + * @param name + * The name of the AVMStore. + * @return The descriptor for the root. + */ + public AVMNodeDescriptor getAVMStoreRoot(int version, String name) + { + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + throw new AVMNotFoundException("Not found: " + name); + } + return store.getRoot(version); + } + + // TODO Fix this awful mess regarding cycle detection. + /** + * Lookup a node. + * + * @param version + * The version to look under. + * @param path + * The path to lookup. + * @param includeDeleted + * Whether to see DeletedNodes. + * @return A lookup object. + */ + public Lookup lookup(int version, String path, boolean includeDeleted) + { + Integer count = fLookupCount.get(); + try + { + if (count == null) + { + fLookupCount.set(1); + } + else + { + fLookupCount.set(count + 1); + } + if (fLookupCount.get() > 50) + { + throw new AVMCycleException("Cycle in lookup."); + } + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + return null; + } + return store.lookup(version, pathParts[1], false, includeDeleted); + } + finally + { + if (count == null) + { + fLookupCount.set(null); + } + } + } + + /** + * Lookup a descriptor from a directory descriptor. + * + * @param dir + * The directory descriptor. + * @param name + * The name of the child to lookup. + * @return The child's descriptor. + */ + public AVMNodeDescriptor lookup(AVMNodeDescriptor dir, String name, boolean includeDeleted) + { + fLookupCount.set(1); + try + { + AVMNode node = fAVMNodeDAO.getByID(dir.getId()); + if (node == null) + { + throw new AVMNotFoundException("Not found: " + dir.getId()); + } + if (node.getType() != AVMNodeType.LAYERED_DIRECTORY && node.getType() != AVMNodeType.PLAIN_DIRECTORY) + { + throw new AVMWrongTypeException("Not a directory."); + } + DirectoryNode dirNode = (DirectoryNode) node; + if (!can(null, dirNode, PermissionService.READ_CHILDREN, false)) + { + throw new AccessDeniedException("Not allowed to read children: " + dir); + } + return dirNode.lookupChild(dir, name, includeDeleted); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get all the paths to a particular node. + * + * @param desc + * The node descriptor. + * @return The list of version, paths. + */ + public List> getPaths(AVMNodeDescriptor desc) + { + AVMNode node = fAVMNodeDAO.getByID(desc.getId()); + if (node == null) + { + throw new AVMNotFoundException("Not found: " + desc); + } + List> paths = new ArrayList>(); + List components = new ArrayList(); + recursiveGetPaths(node, components, paths); + return paths; + } + + /** + * Get a single valid path for a node. + * + * @param desc + * The node descriptor. + * @return A version, path + */ + public Pair getAPath(AVMNodeDescriptor desc) + { + AVMNode node = fAVMNodeDAO.getByID(desc.getId()); + if (node == null) + { + throw new AVMNotFoundException("Could not find node: " + desc); + } + if (fgLogger.isDebugEnabled()) + { + fgLogger.debug("Getting A Path for: " + desc); + } + List components = new ArrayList(); + return recursiveGetAPath(node, components); + } + + /** + * Get all paths for a node reachable by HEAD. + * + * @param desc + * The node descriptor. + * @return A List of all the version, path Pairs that match. + */ + public List> getHeadPaths(AVMNodeDescriptor desc) + { + AVMNode node = fAVMNodeDAO.getByID(desc.getId()); + if (node == null) + { + throw new AVMNotFoundException("Not found: " + desc.getPath()); + } + List> paths = new ArrayList>(); + List components = new ArrayList(); + recursiveGetHeadPaths(node, components, paths); + return paths; + } + + /** + * Gets all the pass from to the given node starting from the give version root. + * + * @param version + * The version root. + * @param node + * The node to get the paths of. + * @return A list of all paths in the given version to the node. + */ + public List getVersionPaths(VersionRoot version, AVMNode node) + { + List paths = new ArrayList(); + List components = new ArrayList(); + recursiveGetVersionPaths(node, components, paths, version.getRoot(), version.getAvmStore().getName()); + return paths; + } + + /** + * Helper to get all version paths. + * + * @param node + * The current node we are examining. + * @param components + * The current path components. + * @param paths + * The list to contain found paths. + * @param root + * The root node of the version. + * @param storeName + * The name of the store. + */ + private void recursiveGetVersionPaths(AVMNode node, List components, List paths, DirectoryNode root, String storeName) + { + if (!can(null, node, PermissionService.READ_CHILDREN, false)) + { + return; + } + if (node.equals(root)) + { + paths.add(this.makePath(components, storeName)); + return; + } + List entries = fChildEntryDAO.getByChild(node); + for (ChildEntry entry : entries) + { + String name = entry.getKey().getName(); + components.add(name); + AVMNode parent = entry.getKey().getParent(); + recursiveGetVersionPaths(parent, components, paths, root, storeName); + components.remove(components.size() - 1); + } + } + + /** + * Get all paths in a particular store in the head version for a particular node. + * + * @param desc + * The node descriptor. + * @param store + * The name of the store. + * @return All matching paths. + */ + public List> getPathsInStoreHead(AVMNodeDescriptor desc, String store) + { + AVMStore st = getAVMStoreByName(store); + if (st == null) + { + throw new AVMNotFoundException("Store not found: " + store); + } + AVMNode node = fAVMNodeDAO.getByID(desc.getId()); + if (node == null) + { + throw new AVMNotFoundException("Not found: " + desc); + } + List> paths = new ArrayList>(); + List components = new ArrayList(); + recursiveGetPathsInStoreHead(node, components, paths, st.getRoot(), store); + return paths; + } + + /** + * Do the actual work. + * + * @param node + * The current node. + * @param components + * The currently accumulated path components. + * @param paths + * The list to put full paths in. + */ + private void recursiveGetPaths(AVMNode node, List components, List> paths) + { + if (!can(null, node, PermissionService.READ_CHILDREN, false)) + { + return; + } + if (node.getIsRoot()) + { + AVMStore store = fAVMStoreDAO.getByRoot(node); + if (store != null) + { + addPath(components, -1, store.getName(), paths); + } + VersionRoot vr = fVersionRootDAO.getByRoot(node); + if (vr != null) + { + addPath(components, vr.getVersionID(), vr.getAvmStore().getName(), paths); + } + return; + } + List entries = fChildEntryDAO.getByChild(node); + for (ChildEntry entry : entries) + { + String name = entry.getKey().getName(); + components.add(name); + AVMNode parent = entry.getKey().getParent(); + recursiveGetPaths(parent, components, paths); + components.remove(components.size() - 1); + } + } + + /** + * Do the work of getting one path for a node. + * + * @param node + * The node to get the path of. + * @param components + * The storage for path components. + * @return A path or null. + */ + private Pair recursiveGetAPath(AVMNode node, List components) + { + if (!can(null, node, PermissionService.READ_CHILDREN, false)) + { + return null; + } + if (node.getIsRoot()) + { + AVMStore store = fAVMStoreDAO.getByRoot(node); + if (store != null) + { + if (fgLogger.isDebugEnabled()) + { + fgLogger.debug("Found path in HEAD of: " + store.getName()); + } + return new Pair(-1, makePath(components, store.getName())); + } + VersionRoot vr = fVersionRootDAO.getByRoot(node); + if (vr != null) + { + if (fgLogger.isDebugEnabled()) + { + fgLogger.debug("Found path in version " + vr.getVersionID() + " in: " + vr.getAvmStore().getName()); + } + return new Pair(vr.getVersionID(), makePath(components, vr.getAvmStore().getName())); + } + return null; + } + List entries = fChildEntryDAO.getByChild(node); + for (ChildEntry entry : entries) + { + String name = entry.getKey().getName(); + if (fgLogger.isDebugEnabled()) + { + fgLogger.debug("Found component: " + name); + } + components.add(name); + Pair path = recursiveGetAPath(entry.getKey().getParent(), components); + if (path != null) + { + return path; + } + components.remove(components.size() - 1); + } + return null; + } + + /** + * Do the actual work. + * + * @param node + * The current node. + * @param components + * The currently accumulated path components. + * @param paths + * The list to put full paths in. + */ + private void recursiveGetHeadPaths(AVMNode node, List components, List> paths) + { + if (!can(null, node, PermissionService.READ_CHILDREN, false)) + { + return; + } + if (node.getIsRoot()) + { + AVMStore store = fAVMStoreDAO.getByRoot(node); + if (store != null) + { + addPath(components, -1, store.getName(), paths); + return; + } + return; + } + List entries = fChildEntryDAO.getByChild(node); + for (ChildEntry entry : entries) + { + String name = entry.getKey().getName(); + components.add(name); + AVMNode parent = entry.getKey().getParent(); + recursiveGetHeadPaths(parent, components, paths); + components.remove(components.size() - 1); + } + } + + /** + * Do the actual work. + * + * @param node + * The current node. + * @param components + * The currently accumulated path components. + * @param paths + * The list to put full paths in. + */ + private void recursiveGetPathsInStoreHead(AVMNode node, List components, List> paths, DirectoryNode root, String storeName) + { + if (!can(null, node, PermissionService.READ_CHILDREN, false)) + { + return; + } + if (node.equals(root)) + { + addPath(components, -1, storeName, paths); + return; + } + List entries = fChildEntryDAO.getByChild(node); + for (ChildEntry entry : entries) + { + String name = entry.getKey().getName(); + components.add(name); + AVMNode parent = entry.getKey().getParent(); + recursiveGetHeadPaths(parent, components, paths); + components.remove(components.size() - 1); + } + } + + /** + * Add a path to the list. + * + * @param components + * The path name components. + * @param version + * The version id. + * @param storeName + * The name of the + * @param paths + * The List to add to. + */ + private void addPath(List components, int version, String storeName, List> paths) + { + paths.add(new Pair(version, makePath(components, storeName))); + } + + /** + * Alternate version. + * + * @param components + * @param storeName + * @param paths + */ + private void addPath(List components, String storeName, List paths) + { + paths.add(makePath(components, storeName)); + } + + /** + * Helper for generating paths. + * + * @param components + * The path components. + * @param storeName + * The store that the path is in. + * @return The path. + */ + private String makePath(List components, String storeName) + { + StringBuilder pathBuilder = new StringBuilder(); + pathBuilder.append(storeName); + pathBuilder.append(":"); + if (components.size() == 0) + { + pathBuilder.append("/"); + return pathBuilder.toString(); + } + for (int i = components.size() - 1; i >= 0; i--) + { + pathBuilder.append("/"); + pathBuilder.append(components.get(i)); + } + return pathBuilder.toString(); + } + + /** + * Get information about layering of a path. + * + * @param version + * The version to look under. + * @param path + * The full avm path. + * @return A LayeringDescriptor. + */ + public LayeringDescriptor getLayeringInfo(int version, String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + Lookup lookup = store.lookup(version, pathParts[1], false, true); + if (lookup == null) + { + throw new AVMNotFoundException("Path not found."); + } + if (!can(store, lookup.getCurrentNode(), PermissionService.READ_PROPERTIES, false)) + { + throw new AccessDeniedException("Not allowed to read properties: " + path); + } + return new LayeringDescriptor(!lookup.getDirectlyContained(), lookup.getAVMStore().getDescriptor(), lookup.getFinalStore().getDescriptor()); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Lookup a directory specifically. + * + * @param version + * The version to look under. + * @param path + * The path to lookup. + * @return A lookup object. + */ + public Lookup lookupDirectory(int version, String path) + { + Integer count = fLookupCount.get(); + try + { + if (count == null) + { + fLookupCount.set(1); + } + fLookupCount.set(fLookupCount.get() + 1); + if (fLookupCount.get() > 50) + { + throw new AVMCycleException("Cycle in lookup."); + } + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + return null; + } + return store.lookupDirectory(version, pathParts[1], false); + } + finally + { + if (count == null) + { + fLookupCount.set(null); + } + } + } + + /** + * Utility to split a path, foo:bar/baz into its repository and path parts. + * + * @param path + * The fully qualified path. + * @return The repository name and the repository path. + */ + private String[] SplitPath(String path) + { + return AVMUtil.splitPath(path); + } + + /** + * Make a directory into a primary indirection. + * + * @param path + * The full path. + */ + public void makePrimary(String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.makePrimary(pathParts[1]); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Change what a layered directory points at. + * + * @param path + * The full path to the layered directory. + * @param target + * The new target path. + */ + public void retargetLayeredDirectory(String path, String target) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.retargetLayeredDirectory(pathParts[1], target); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get the history chain for a node. + * + * @param desc + * The node to get history of. + * @param count + * The maximum number of ancestors to traverse. Negative means all. + * @return A List of ancestors. + */ + public List getHistory(AVMNodeDescriptor desc, int count) + { + AVMNode node = fAVMNodeDAO.getByID(desc.getId()); + if (node == null) + { + throw new AVMNotFoundException("Not found."); + } + if (!can(null, node, PermissionService.READ_PROPERTIES, false)) + { + throw new AccessDeniedException("Not allowed to read properties: " + desc); + } + if (count < 0) + { + count = Integer.MAX_VALUE; + } + List history = new ArrayList(); + for (int i = 0; i < count; i++) + { + AVMNode ancNode = node.getAncestor(); + if (ancNode == null) { break; } - if (!can(null, ancNode, PermissionService.READ_PROPERTIES, false)) - { - break; - } - if ((node.getType() == AVMNodeType.LAYERED_FILE) && (ancNode.getType() == AVMNodeType.PLAIN_FILE)) - { - break; - } - history.add(ancNode.getDescriptor("UNKNOWN", "UNKNOWN", "UNKNOWN", -1)); - node = ancNode; - } - return history; - } - - /** - * Set the opacity of a layered directory. An opaque directory hides the things it points to via indirection. - * - * @param path - * The path to the layered directory. - * @param opacity - * True is opaque; false is not. - */ - public void setOpacity(String path, boolean opacity) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.setOpacity(pathParts[1], opacity); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Set a property on a node. - * - * @param path - * The path to the node. - * @param name - * The name of the property. - * @param value - * The value of the property. - */ - public void setNodeProperty(String path, QName name, PropertyValue value) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.setNodeProperty(pathParts[1], name, value); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Set a collection of properties at once. - * - * @param path - * The path to the node. - * @param properties - * The Map of QNames to PropertyValues. - */ - public void setNodeProperties(String path, Map properties) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.setNodeProperties(pathParts[1], properties); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get a property by name for a node. - * - * @param version - * The version to look under. - * @param path - * The path to the node. - * @param name - * The name of the property. - * @return The PropertyValue or null if it does not exist. - */ - public PropertyValue getNodeProperty(int version, String path, QName name) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getNodeProperty(version, pathParts[1], name); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get a Map of all the properties of a node. - * - * @param version - * The version to look under. - * @param path - * The path to the node. - * @return A Map of QNames to PropertyValues. - */ - public Map getNodeProperties(int version, String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getNodeProperties(version, pathParts[1]); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Delete a single property from a node. - * - * @param path - * The path to the node. - * @param name - * The name of the property. - */ - public void deleteNodeProperty(String path, QName name) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.deleteNodeProperty(pathParts[1], name); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Delete all properties on a node. - * - * @param path - * The path to the node. - */ - public void deleteNodeProperties(String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.deleteNodeProperties(pathParts[1]); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Set a property on a store. Overwrites if property exists. - * - * @param store - * The AVMStore. - * @param name - * The QName. - * @param value - * The PropertyValue to set. - */ - public void setStoreProperty(String store, QName name, PropertyValue value) - { - AVMStore st = getAVMStoreByName(store); - if (st == null) - { - throw new AVMNotFoundException("Store not found."); - } - st.setProperty(name, value); - } - - /** - * Set a group of properties on a store. Overwrites any properties that exist. - * - * @param store - * The AVMStore. - * @param props - * The properties to set. - */ - public void setStoreProperties(String store, Map props) - { - AVMStore st = getAVMStoreByName(store); - if (st == null) - { - throw new AVMNotFoundException("Store not found."); - } - st.setProperties(props); - } - - /** - * Get a property from a store. - * - * @param store - * The name of the store. - * @param name - * The property - * @return The property value or null if non-existent. - */ - public PropertyValue getStoreProperty(String store, QName name) - { - if (store == null) - { - throw new AVMBadArgumentException("Null store name."); - } - AVMStore st = getAVMStoreByName(store); - if (st == null) - { - throw new AVMNotFoundException("Store not found."); - } - return st.getProperty(name); - } - - /** - * Queries a given store for properties with keys that match a given pattern. - * - * @param store - * The name of the store. - * @param keyPattern - * The sql 'like' pattern, inserted into a QName. - * @return A Map of the matching key value pairs. - */ - public Map queryStorePropertyKey(String store, QName keyPattern) - { - AVMStore st = getAVMStoreByName(store); - if (st == null) - { - throw new AVMNotFoundException("Store not found."); - } - - return fAVMStorePropertyDAO.queryByKeyPattern(st, keyPattern); - } - - /** - * Queries all AVM stores for properties with keys that match a given pattern. - * - * @param keyPattern - * The sql 'like' pattern, inserted into a QName. - * @return A List of Pairs of Store name, Map.Entry. - */ - public Map> queryStoresPropertyKeys(QName keyPattern) - { - return fAVMStorePropertyDAO.queryByKeyPattern(keyPattern); - } - - /** - * Get all the properties for a store. - * - * @param store - * The name of the Store. - * @return A Map of all the properties. - */ - public Map getStoreProperties(String store) - { - if (store == null) - { - throw new AVMBadArgumentException("Null store name."); - } - AVMStore st = getAVMStoreByName(store); - if (st == null) - { - throw new AVMNotFoundException("Store not found."); - } - return st.getProperties(); - } - - /** - * Delete a property from a store. - * - * @param store - * The name of the store. - * @param name - * The name of the property. - */ - public void deleteStoreProperty(String store, QName name) - { - AVMStore st = getAVMStoreByName(store); - if (st == null) - { - throw new AVMNotFoundException("Store not found."); - } - st.deleteProperty(name); - } - - /** - * Get the common ancestor of two nodes if one exists. Unfortunately this is a quadratic problem, taking time - * proportional to the product of the lengths of the left and right history chains. - * - * @param left - * The first node. - * @param right - * The second node. - * @return The common ancestor. There are four possible results. Null means that there is no common ancestor. Left - * returned means that left is strictly an ancestor of right. Right returned means that right is strictly an - * ancestor of left. Any other non null return is the common ancestor and indicates that left and right are - * in conflict. - */ - public AVMNodeDescriptor getCommonAncestor(AVMNodeDescriptor left, AVMNodeDescriptor right) - { - AVMNode lNode = fAVMNodeDAO.getByID(left.getId()); - AVMNode rNode = fAVMNodeDAO.getByID(right.getId()); - if (lNode == null || rNode == null) - { - throw new AVMNotFoundException("Node not found."); - } - if (!can(null, lNode, PermissionService.READ_PROPERTIES, false)) - { - throw new AccessDeniedException("Not allowed to read properties: " + left); - } - if (!can(null, rNode, PermissionService.READ_PROPERTIES, false)) - { - throw new AccessDeniedException("Not allowed to read properties: " + right); - } - // TODO Short changing the permissions checking here. I'm not sure - // if that's OK. - List leftHistory = new ArrayList(); - List rightHistory = new ArrayList(); - while (lNode != null || rNode != null) - { - boolean checkRight = false; - if (lNode != null) - { - leftHistory.add(lNode); - checkRight = true; - lNode = lNode.getAncestor(); - } - boolean checkLeft = false; - if (rNode != null) - { - rightHistory.add(rNode); - checkLeft = true; - rNode = rNode.getAncestor(); - } - if (checkRight) - { - AVMNode check = leftHistory.get(leftHistory.size() - 1); - for (AVMNode node : rightHistory) - { - if (node.equals(check)) - { - return node.getDescriptor("", "", "", -1); - } - } - } - if (checkLeft) - { - AVMNode check = rightHistory.get(rightHistory.size() - 1); - for (AVMNode node : leftHistory) - { - if (node.equals(check)) - { - return node.getDescriptor("", "", "", -1); - } - } - } - } - return null; - } - - /** - * Get the ContentData for a file. - * - * @param version - * The version to look under. - * @param path - * The path to the file. - * @return The ContentData for the file. - */ - public ContentData getContentDataForRead(int version, String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - return store.getContentDataForRead(version, pathParts[1]); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get the ContentData for a file for writing. - * - * @param path - * The path to the file. - * @return The ContentData object. - */ - public ContentData getContentDataForWrite(String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - ContentData result = store.getContentDataForWrite(pathParts[1]); - return result; - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Set the ContentData on a file. - * - * @param path - * The path to the file. - * @param data - * The content data to set. - */ - public void setContentData(String path, ContentData data) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.setContentData(pathParts[1], data); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get the single instance of AVMRepository. - * - * @return The single instance. - */ - public static AVMRepository GetInstance() - { - return fgInstance; - } - - public void setMetaDataFrom(String path, AVMNodeDescriptor from) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found: " + pathParts[0]); - } - AVMNode fromNode = fAVMNodeDAO.getByID(from.getId()); - if (fromNode == null) - { - throw new AVMNotFoundException("Node not found: " + from.getPath()); - } - fLookupCache.onWrite(pathParts[0]); - store.setMetaDataFrom(pathParts[1], fromNode); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Add an aspect to an AVM Node. - * - * @param path - * The path to the node. - * @param aspectName - * The name of the aspect. - */ - public void addAspect(String path, QName aspectName) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.addAspect(pathParts[1], aspectName); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get all the aspects on an AVM node. - * - * @param version - * The version to look under. - * @param path - * The path to the node. - * @return A List of the QNames of the Aspects. - */ - public Set getAspects(int version, String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getAspects(version, pathParts[1]); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Remove an aspect and all associated properties from a node. - * - * @param path - * The path to the node. - * @param aspectName - * The name of the aspect. - */ - public void removeAspect(String path, QName aspectName) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.removeAspect(pathParts[1], aspectName); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Does a node have a particular aspect. - * - * @param version - * The version to look under. - * @param path - * The path to the node. - * @param aspectName - * The name of the aspect. - * @return Whether the node has the aspect. - */ - public boolean hasAspect(int version, String path, QName aspectName) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.hasAspect(version, pathParts[1], aspectName); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Set the ACL on a node. - * - * @param path - * The path to the node. - * @param acl - * The ACL to set. - */ - public void setACL(String path, DbAccessControlList acl) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - store.setACL(pathParts[1], acl); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Get the ACL on a node. - * - * @param version - * The version to look under. - * @param path - * The path to the node. - * @return The ACL. - */ - public DbAccessControlList getACL(int version, String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getACL(version, pathParts[1]); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Link a node into a directory, directly. - * - * @param parentPath - * The path to the parent. - * @param name - * The name to give the node. - * @param toLink - * The node to link. - */ - public void link(String parentPath, String name, AVMNodeDescriptor toLink) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(parentPath); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - store.link(pathParts[1], name, toLink); - fLookupCache.onWrite(pathParts[0]); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Update a link, directly. - * - * @param parentPath - * The path to the parent. - * @param name - * The name to give the node. - * @param toLink - * The node to link. - */ - public void updateLink(String parentPath, String name, AVMNodeDescriptor toLink) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(parentPath); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - store.updateLink(pathParts[1], name, toLink); - fLookupCache.onWrite(pathParts[0]); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * This is the danger version of link. It must be called on a copied and unsnapshotted directory. It blithely - * inserts a child without checking if a child exists with a conflicting name. - * - * @param parent - * The parent directory. - * @param name - * The name to give the child. - * @param child - * The child to link in. - */ - public void link(AVMNodeDescriptor parent, String name, AVMNodeDescriptor child) - { - AVMNode node = fAVMNodeDAO.getByID(parent.getId()); - if (!(node instanceof DirectoryNode)) - { - throw new AVMWrongTypeException("Not a Directory."); - } - DirectoryNode dir = (DirectoryNode) node; - if (!dir.getIsNew()) - { - throw new AVMException("Directory has not already been copied."); - } - if (!can(null, dir, PermissionService.ADD_CHILDREN, false)) - { - throw new AccessDeniedException("Not allowed to write: " + parent); - } - dir.link(name, child); - } - - /** - * Remove name without leaving behind a deleted node. Dangerous if used unwisely. - * - * @param path - * The path to the layered directory. - * @param name - * The name of the child. - */ - public void flatten(String path, String name) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onDelete(pathParts[0]); - Lookup lPath = store.lookup(-1, pathParts[1], true, false); - AVMNode node = lPath.getCurrentNode(); - if (node == null) - { - throw new AVMNotFoundException("Path not found."); - } - if (!(node instanceof LayeredDirectoryNode)) - { - throw new AVMWrongTypeException("Not a Layered Directory."); - } - if (!can(store, node, PermissionService.FLATTEN, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write in: " + path); - } - LayeredDirectoryNode dir = (LayeredDirectoryNode) node; - dir.flatten(name); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Force a copy on write. - * - * @param path - * The path to force. - */ - public AVMNodeDescriptor forceCopy(String path) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - fLookupCache.onWrite(pathParts[0]); - // Just force a copy if needed by looking up in write mode. - Lookup lPath = store.lookup(-1, pathParts[1], true, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path not found."); - } - AVMNode node = lPath.getCurrentNode(); - AVMNodeDescriptor desc = node.getDescriptor(lPath); - return desc; - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Rename a store. - * - * @param sourceName - * The original name. - * @param destName - * The new name. - * @throws AVMNotFoundException - * @throws AVMExistsException - */ - public void renameStore(String sourceName, String destName) - { - AlfrescoTransactionSupport.bindListener(fPurgeStoreTxnListener); - AlfrescoTransactionSupport.bindListener(fCreateStoreTxnListener); - AVMStore store = getAVMStoreByName(sourceName); - if (store == null) - { - throw new AVMNotFoundException("Store Not Found: " + sourceName); - } - if (getAVMStoreByName(destName) != null) - { - throw new AVMExistsException("Store Already Exists: " + destName); - } + if (!can(null, ancNode, PermissionService.READ_PROPERTIES, false)) + { + break; + } + if ((node.getType() == AVMNodeType.LAYERED_FILE) && (ancNode.getType() == AVMNodeType.PLAIN_FILE)) + { + break; + } + history.add(ancNode.getDescriptor("UNKNOWN", "UNKNOWN", "UNKNOWN", -1)); + node = ancNode; + } + return history; + } + + /** + * Set the opacity of a layered directory. An opaque directory hides the things it points to via indirection. + * + * @param path + * The path to the layered directory. + * @param opacity + * True is opaque; false is not. + */ + public void setOpacity(String path, boolean opacity) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.setOpacity(pathParts[1], opacity); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Set a property on a node. + * + * @param path + * The path to the node. + * @param name + * The name of the property. + * @param value + * The value of the property. + */ + public void setNodeProperty(String path, QName name, PropertyValue value) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.setNodeProperty(pathParts[1], name, value); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Set a collection of properties at once. + * + * @param path + * The path to the node. + * @param properties + * The Map of QNames to PropertyValues. + */ + public void setNodeProperties(String path, Map properties) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.setNodeProperties(pathParts[1], properties); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get a property by name for a node. + * + * @param version + * The version to look under. + * @param path + * The path to the node. + * @param name + * The name of the property. + * @return The PropertyValue or null if it does not exist. + */ + public PropertyValue getNodeProperty(int version, String path, QName name) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getNodeProperty(version, pathParts[1], name); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get a Map of all the properties of a node. + * + * @param version + * The version to look under. + * @param path + * The path to the node. + * @return A Map of QNames to PropertyValues. + */ + public Map getNodeProperties(int version, String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getNodeProperties(version, pathParts[1]); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Delete a single property from a node. + * + * @param path + * The path to the node. + * @param name + * The name of the property. + */ + public void deleteNodeProperty(String path, QName name) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.deleteNodeProperty(pathParts[1], name); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Delete all properties on a node. + * + * @param path + * The path to the node. + */ + public void deleteNodeProperties(String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.deleteNodeProperties(pathParts[1]); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Set a property on a store. Overwrites if property exists. + * + * @param store + * The AVMStore. + * @param name + * The QName. + * @param value + * The PropertyValue to set. + */ + public void setStoreProperty(String store, QName name, PropertyValue value) + { + AVMStore st = getAVMStoreByName(store); + if (st == null) + { + throw new AVMNotFoundException("Store not found."); + } + st.setProperty(name, value); + } + + /** + * Set a group of properties on a store. Overwrites any properties that exist. + * + * @param store + * The AVMStore. + * @param props + * The properties to set. + */ + public void setStoreProperties(String store, Map props) + { + AVMStore st = getAVMStoreByName(store); + if (st == null) + { + throw new AVMNotFoundException("Store not found."); + } + st.setProperties(props); + } + + /** + * Get a property from a store. + * + * @param store + * The name of the store. + * @param name + * The property + * @return The property value or null if non-existent. + */ + public PropertyValue getStoreProperty(String store, QName name) + { + if (store == null) + { + throw new AVMBadArgumentException("Null store name."); + } + AVMStore st = getAVMStoreByName(store); + if (st == null) + { + throw new AVMNotFoundException("Store not found."); + } + return st.getProperty(name); + } + + /** + * Queries a given store for properties with keys that match a given pattern. + * + * @param store + * The name of the store. + * @param keyPattern + * The sql 'like' pattern, inserted into a QName. + * @return A Map of the matching key value pairs. + */ + public Map queryStorePropertyKey(String store, QName keyPattern) + { + AVMStore st = getAVMStoreByName(store); + if (st == null) + { + throw new AVMNotFoundException("Store not found."); + } + + return fAVMStorePropertyDAO.queryByKeyPattern(st, keyPattern); + } + + /** + * Queries all AVM stores for properties with keys that match a given pattern. + * + * @param keyPattern + * The sql 'like' pattern, inserted into a QName. + * @return A List of Pairs of Store name, Map.Entry. + */ + public Map> queryStoresPropertyKeys(QName keyPattern) + { + return fAVMStorePropertyDAO.queryByKeyPattern(keyPattern); + } + + /** + * Get all the properties for a store. + * + * @param store + * The name of the Store. + * @return A Map of all the properties. + */ + public Map getStoreProperties(String store) + { + if (store == null) + { + throw new AVMBadArgumentException("Null store name."); + } + AVMStore st = getAVMStoreByName(store); + if (st == null) + { + throw new AVMNotFoundException("Store not found."); + } + return st.getProperties(); + } + + /** + * Delete a property from a store. + * + * @param store + * The name of the store. + * @param name + * The name of the property. + */ + public void deleteStoreProperty(String store, QName name) + { + AVMStore st = getAVMStoreByName(store); + if (st == null) + { + throw new AVMNotFoundException("Store not found."); + } + st.deleteProperty(name); + } + + /** + * Get the common ancestor of two nodes if one exists. Unfortunately this is a quadratic problem, taking time + * proportional to the product of the lengths of the left and right history chains. + * + * @param left + * The first node. + * @param right + * The second node. + * @return The common ancestor. There are four possible results. Null means that there is no common ancestor. Left + * returned means that left is strictly an ancestor of right. Right returned means that right is strictly an + * ancestor of left. Any other non null return is the common ancestor and indicates that left and right are + * in conflict. + */ + public AVMNodeDescriptor getCommonAncestor(AVMNodeDescriptor left, AVMNodeDescriptor right) + { + AVMNode lNode = fAVMNodeDAO.getByID(left.getId()); + AVMNode rNode = fAVMNodeDAO.getByID(right.getId()); + if (lNode == null || rNode == null) + { + throw new AVMNotFoundException("Node not found."); + } + if (!can(null, lNode, PermissionService.READ_PROPERTIES, false)) + { + throw new AccessDeniedException("Not allowed to read properties: " + left); + } + if (!can(null, rNode, PermissionService.READ_PROPERTIES, false)) + { + throw new AccessDeniedException("Not allowed to read properties: " + right); + } + // TODO Short changing the permissions checking here. I'm not sure + // if that's OK. + List leftHistory = new ArrayList(); + List rightHistory = new ArrayList(); + while (lNode != null || rNode != null) + { + boolean checkRight = false; + if (lNode != null) + { + leftHistory.add(lNode); + checkRight = true; + lNode = lNode.getAncestor(); + } + boolean checkLeft = false; + if (rNode != null) + { + rightHistory.add(rNode); + checkLeft = true; + rNode = rNode.getAncestor(); + } + if (checkRight) + { + AVMNode check = leftHistory.get(leftHistory.size() - 1); + for (AVMNode node : rightHistory) + { + if (node.equals(check)) + { + return node.getDescriptor("", "", "", -1); + } + } + } + if (checkLeft) + { + AVMNode check = rightHistory.get(rightHistory.size() - 1); + for (AVMNode node : leftHistory) + { + if (node.equals(check)) + { + return node.getDescriptor("", "", "", -1); + } + } + } + } + return null; + } + + /** + * Get the ContentData for a file. + * + * @param version + * The version to look under. + * @param path + * The path to the file. + * @return The ContentData for the file. + */ + public ContentData getContentDataForRead(int version, String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + return store.getContentDataForRead(version, pathParts[1]); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get the ContentData for a file for writing. + * + * @param path + * The path to the file. + * @return The ContentData object. + */ + public ContentData getContentDataForWrite(String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + ContentData result = store.getContentDataForWrite(pathParts[1]); + return result; + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Set the ContentData on a file. + * + * @param path + * The path to the file. + * @param data + * The content data to set. + */ + public void setContentData(String path, ContentData data) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.setContentData(pathParts[1], data); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get the single instance of AVMRepository. + * + * @return The single instance. + */ + public static AVMRepository GetInstance() + { + return fgInstance; + } + + public void setMetaDataFrom(String path, AVMNodeDescriptor from) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found: " + pathParts[0]); + } + AVMNode fromNode = fAVMNodeDAO.getByID(from.getId()); + if (fromNode == null) + { + throw new AVMNotFoundException("Node not found: " + from.getPath()); + } + fLookupCache.onWrite(pathParts[0]); + store.setMetaDataFrom(pathParts[1], fromNode); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Add an aspect to an AVM Node. + * + * @param path + * The path to the node. + * @param aspectName + * The name of the aspect. + */ + public void addAspect(String path, QName aspectName) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.addAspect(pathParts[1], aspectName); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get all the aspects on an AVM node. + * + * @param version + * The version to look under. + * @param path + * The path to the node. + * @return A List of the QNames of the Aspects. + */ + public Set getAspects(int version, String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getAspects(version, pathParts[1]); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Remove an aspect and all associated properties from a node. + * + * @param path + * The path to the node. + * @param aspectName + * The name of the aspect. + */ + public void removeAspect(String path, QName aspectName) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.removeAspect(pathParts[1], aspectName); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Does a node have a particular aspect. + * + * @param version + * The version to look under. + * @param path + * The path to the node. + * @param aspectName + * The name of the aspect. + * @return Whether the node has the aspect. + */ + public boolean hasAspect(int version, String path, QName aspectName) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.hasAspect(version, pathParts[1], aspectName); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Set the ACL on a node. + * + * @param path + * The path to the node. + * @param acl + * The ACL to set. + */ + public void setACL(String path, DbAccessControlList acl) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + store.setACL(pathParts[1], acl); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Get the ACL on a node. + * + * @param version + * The version to look under. + * @param path + * The path to the node. + * @return The ACL. + */ + public DbAccessControlList getACL(int version, String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getACL(version, pathParts[1]); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Link a node into a directory, directly. + * + * @param parentPath + * The path to the parent. + * @param name + * The name to give the node. + * @param toLink + * The node to link. + */ + public void link(String parentPath, String name, AVMNodeDescriptor toLink) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(parentPath); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + store.link(pathParts[1], name, toLink); + fLookupCache.onWrite(pathParts[0]); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Update a link, directly. + * + * @param parentPath + * The path to the parent. + * @param name + * The name to give the node. + * @param toLink + * The node to link. + */ + public void updateLink(String parentPath, String name, AVMNodeDescriptor toLink) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(parentPath); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + store.updateLink(pathParts[1], name, toLink); + fLookupCache.onWrite(pathParts[0]); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * This is the danger version of link. It must be called on a copied and unsnapshotted directory. It blithely + * inserts a child without checking if a child exists with a conflicting name. + * + * @param parent + * The parent directory. + * @param name + * The name to give the child. + * @param child + * The child to link in. + */ + public void link(AVMNodeDescriptor parent, String name, AVMNodeDescriptor child) + { + AVMNode node = fAVMNodeDAO.getByID(parent.getId()); + if (!(node instanceof DirectoryNode)) + { + throw new AVMWrongTypeException("Not a Directory."); + } + DirectoryNode dir = (DirectoryNode) node; + if (!dir.getIsNew()) + { + throw new AVMException("Directory has not already been copied."); + } + if (!can(null, dir, PermissionService.ADD_CHILDREN, false)) + { + throw new AccessDeniedException("Not allowed to write: " + parent); + } + dir.link(name, child); + } + + /** + * Remove name without leaving behind a deleted node. Dangerous if used unwisely. + * + * @param path + * The path to the layered directory. + * @param name + * The name of the child. + */ + public void flatten(String path, String name) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onDelete(pathParts[0]); + Lookup lPath = store.lookup(-1, pathParts[1], true, false); + AVMNode node = lPath.getCurrentNode(); + if (node == null) + { + throw new AVMNotFoundException("Path not found."); + } + if (!(node instanceof LayeredDirectoryNode)) + { + throw new AVMWrongTypeException("Not a Layered Directory."); + } + if (!can(store, node, PermissionService.FLATTEN, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write in: " + path); + } + LayeredDirectoryNode dir = (LayeredDirectoryNode) node; + dir.flatten(name); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Force a copy on write. + * + * @param path + * The path to force. + */ + public AVMNodeDescriptor forceCopy(String path) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + fLookupCache.onWrite(pathParts[0]); + // Just force a copy if needed by looking up in write mode. + Lookup lPath = store.lookup(-1, pathParts[1], true, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path not found."); + } + AVMNode node = lPath.getCurrentNode(); + AVMNodeDescriptor desc = node.getDescriptor(lPath); + return desc; + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Rename a store. + * + * @param sourceName + * The original name. + * @param destName + * The new name. + * @throws AVMNotFoundException + * @throws AVMExistsException + */ + public void renameStore(String sourceName, String destName) + { + AlfrescoTransactionSupport.bindListener(fPurgeStoreTxnListener); + AlfrescoTransactionSupport.bindListener(fCreateStoreTxnListener); + AVMStore store = getAVMStoreByName(sourceName); + if (store == null) + { + throw new AVMNotFoundException("Store Not Found: " + sourceName); + } + if (getAVMStoreByName(destName) != null) + { + throw new AVMExistsException("Store Already Exists: " + destName); + } if (!FileNameValidator.isValid(destName)) - { - throw new AVMBadArgumentException("Bad store name: " + destName); - } - store.setName(destName); - - AVMDAOs.Instance().fAVMStoreDAO.update(store); - - store.createSnapshot("Rename Store", "Rename Store from " + sourceName + " to " + destName, new HashMap()); - fLookupCache.onDelete(sourceName); - fAVMStoreDAO.invalidateCache(); - fPurgeStoreTxnListener.storePurged(sourceName); - fCreateStoreTxnListener.storeCreated(destName); - } - - /** - * Revert a head path to a given version. This works by cloning the version to revert to, and then linking that new - * version into head. The reverted version will have the previous head version as ancestor. - * - * @param path - * The path to the parent directory. - * @param name - * The name of the node. - * @param toRevertTo - * The descriptor of the version to revert to. - */ - public void revert(String path, String name, AVMNodeDescriptor toRevertTo) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found: " + pathParts[0]); - } - fLookupCache.onWrite(pathParts[0]); - store.revert(pathParts[1], name, toRevertTo); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Set the GUID on a node. - * - * @param path - * @param guid - */ - public void setGuid(String path, String guid) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store not found:" + pathParts[0]); - } - fLookupCache.onWrite(pathParts[0]); - store.setGuid(pathParts[1], guid); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Set the encoding on a node. - * - * @param path - * @param encoding - */ - public void setEncoding(String path, String encoding) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store Not Found: " + pathParts[0]); - } - fLookupCache.onWrite(pathParts[0]); - store.setEncoding(pathParts[1], encoding); - } - finally - { - fLookupCount.set(null); - } - } - - /** - * Set the mime type on a node. - * - * @param path - * @param encoding - */ - public void setMimeType(String path, String mimeType) - { - fLookupCount.set(1); - try - { - String[] pathParts = SplitPath(path); - AVMStore store = getAVMStoreByName(pathParts[0]); - if (store == null) - { - throw new AVMNotFoundException("Store Not Found: " + pathParts[0]); - } - fLookupCache.onWrite(pathParts[0]); - store.setMimeType(pathParts[1], mimeType); - } - finally - { - fLookupCount.set(null); - } - } - - public List getPathsInStoreVersion(AVMNodeDescriptor desc, String store, int version) - { - AVMNode node = fAVMNodeDAO.getByID(desc.getId()); - if (node == null) - { - throw new AVMNotFoundException("Not found: " + desc); - } - List paths = new ArrayList(); - List components = new ArrayList(); - recursiveGetStoreVersionPaths(store, node, version, components, paths); - return paths; - } - - /** - * Do the actual work. - * - * @param node - * The current node. - * @param components - * The currently accumulated path components. - * @param paths - * The list to put full paths in. - */ - private void recursiveGetStoreVersionPaths(String storeName, AVMNode node, int version, List components, List paths) - { - if (!can(null, node, PermissionService.READ, false)) - { - return; - } - if (node.getIsRoot()) - { - VersionRoot versionRoot = fVersionRootDAO.getByRoot(node); - if (versionRoot.getAvmStore().getName().equals(storeName) && versionRoot.getVersionID() == version) - { - addPath(components, storeName, paths); - return; - } - return; - } - List entries = fChildEntryDAO.getByChild(node); - for (ChildEntry entry : entries) - { - String name = entry.getKey().getName(); - components.add(name); - AVMNode parent = entry.getKey().getParent(); - recursiveGetStoreVersionPaths(storeName, parent, version, components, paths); - components.remove(components.size() - 1); - } - } - - public Map getNodeProperties(AVMNodeDescriptor desc) - { - AVMNode node = fAVMNodeDAO.getByID(desc.getId()); - if (node == null) - { - throw new AVMNotFoundException("Node not found: " + desc); - } - if (!can(null, node, PermissionService.READ_PROPERTIES, false)) - { - throw new AccessDeniedException("Not allowed to read properties: " + desc); - } - return node.getProperties(); - } - - public ContentData getContentDataForRead(AVMNodeDescriptor desc) - { - AVMNode node = fAVMNodeDAO.getByID(desc.getId()); - if (node == null) - { - throw new AVMNotFoundException("Node not found: " + desc); - } - if (!can(null, node, PermissionService.READ_CONTENT, false)) - { - throw new AccessDeniedException("Not allowed to read: " + desc); - } - if (node.getType() == AVMNodeType.PLAIN_FILE) - { - PlainFileNode file = (PlainFileNode) node; - return file.getContentData(); - } - else if (node.getType() == AVMNodeType.LAYERED_FILE) - { - LayeredFileNode file = (LayeredFileNode) node; - return file.getContentData(null); - } - throw new AVMWrongTypeException("Not a file: " + desc); - } - - public Set getAspects(AVMNodeDescriptor desc) - { - AVMNode node = fAVMNodeDAO.getByID(desc.getId()); - if (node == null) - { - throw new AVMNotFoundException("Node not found: " + desc); - } - if (!can(null, node, PermissionService.READ_PROPERTIES, false)) - { - throw new AccessDeniedException("Not allowed to read properties: " + desc); - } - Set aspectQNames = node.getAspects(); - return aspectQNames; - } - - /** - * Evaluate permission on a node. I've got a bad feeling about this... - * - * @param store - * @param node - * @param permission - * @return - */ - public boolean can(AVMStore store, AVMNode node, String permission, boolean isDirectlyContained) - { - DbAccessControlList acl = node.getAcl(); - - QName type; - if (node.getType() == AVMNodeType.PLAIN_DIRECTORY) - { - type = WCMModel.TYPE_AVM_PLAIN_FOLDER; - } - else if (node.getType() == AVMNodeType.PLAIN_FILE) - { - type = WCMModel.TYPE_AVM_PLAIN_CONTENT; - } - else if (node.getType() == AVMNodeType.LAYERED_DIRECTORY) - { - type = WCMModel.TYPE_AVM_LAYERED_FOLDER; - } - else - { - type = WCMModel.TYPE_AVM_LAYERED_CONTENT; - } - PermissionContext context = new PermissionContext(type); - - context.addDynamicAuthorityAssignment(node.getBasicAttributes().getOwner(), PermissionService.OWNER_AUTHORITY); - - if ((store != null) && isDirectlyContained) - { - String storeOwner = getStoreUserName(store.getName()); - if (storeOwner != null) - { - // Special case: WCM author sandbox (author, author preview, author workflow, author workflow preview) - context.addDynamicAuthorityAssignment(storeOwner, PermissionService.WCM_STORE_OWNER_AUTHORITY); - } - - /* - StoreType storeType = StoreType.getStoreType(store.getName(), store.getDescriptor(), store.getProperties()); - switch (storeType) - { - case AUTHOR: - case AUTHOR_PREVIEW: - case AUTHOR_WORKFLOW: - case AUTHOR_WORKFLOW_PREVIEW: - String storeName = store.getName(); - int first = -1; - int second = -1; - first = storeName.indexOf("--"); - if (first >= 0) - { - second = storeName.indexOf("--", first + 2); - String storeOwner; - if (second >= 0) - { - storeOwner = storeName.substring(first + 2, second); - } - else - { - storeOwner = storeName.substring(first + 2); - } - context.addDynamicAuthorityAssignment(storeOwner, PermissionService.WCM_STORE_OWNER_AUTHORITY); - } - break; - case STAGING: - case STAGING_PREVIEW: - case UNKNOWN: - case WORKFLOW: - case WORKFLOW_PREVIEW: - default: - } - */ - } - - // Pass in node aspects - Set nodeAspectQNames = node.getAspects(); - Set contextQNames = context.getAspects(); - contextQNames.addAll(nodeAspectQNames); - - /* TODO review - PermissionContext.getProperties() not currently used ? - // Pass in node properties - Map nodeProperties = node.getProperties(); - Map contextProperties = new HashMap(5); - QNameDAO qnameDAO = AVMDAOs.Instance().fQNameDAO; - for (Map.Entry entry : nodeProperties.entrySet()) - { - QName qname = qnameDAO.getQName(entry.getKey()).getSecond(); - PropertyDefinition def = fDictionaryService.getProperty(qname); - if (def == null) - { - contextProperties.put(qname, entry.getValue().getValue(DataTypeDefinition.ANY)); - } - else - { - contextProperties.put(qname, entry.getValue().getValue(def.getDataType().getName())); - } - } - context.getProperties().putAll(contextProperties); - */ - - Long aclId = null; - if (acl != null) - { - aclId = acl.getId(); - } - if (store != null) - { - DbAccessControlList storeAcl = store.getStoreAcl(); - if (storeAcl != null) - { - Long storeAclID = storeAcl.getId(); - context.setStoreAcl(storeAclID); - } - } - return fPermissionService.hasPermission(aclId, context, permission) == AccessStatus.ALLOWED; - } - - private final static String WCM_STORE_SEPARATOR = "--"; - private final static String WCM_STORE_PREVIEW = "--preview"; - private final static String WCM_STORE_WORKFLOW = "--workflow-"; - - // TODO - merge with WCM 3.x utils - // - // Note: relies on WCM sandbox naming convention - // - // Staging: mystore - // Staging preview: mystore--preview - // Author: mystore--myuserid - // Author preview: mystore--myuserid--preview - // Author workflow: mystore--myuserid--workflow-guid - // Author workflow preview: mystore--myuserid--workflow-guid--preview - // Workflow: mystore--workflow-guid - // Workflow preview: mystore--worklow-guid--preview - // - private static String getStoreUserName(String storeName) - { - String storeOwner = null; - int preview = storeName.indexOf(WCM_STORE_PREVIEW); - if (preview >= 0) - { - // strip off "--preview" - storeName = storeName.substring(0, preview); - } - int workflow = storeName.indexOf(WCM_STORE_WORKFLOW); - if (workflow >= 0) - { - // strip off "--workflow-" - storeName = storeName.substring(0, workflow); - } - int author = storeName.indexOf(WCM_STORE_SEPARATOR); - if (author >= 0) - { - storeOwner = storeName.substring(author + 2); - } - return storeOwner; - } - - public boolean can(String storeName, int version, String path, String permission) - { - Lookup lookup = AVMRepository.GetInstance().lookup(version, path, true); - if (lookup != null) - { - AVMNode node = lookup.getCurrentNode(); - AVMStore store = getAVMStoreByName(storeName); - return can(store, node, permission, lookup.getDirectlyContained()); - } - else - { - // Does not exist => allowed - return true; - } - } - - /** - * Set the acl on a store. - * - * @param storeName - * @param acl - */ - public void setStoreAcl(String storeName, DbAccessControlList acl) - { - AVMStore store = getAVMStoreByName(storeName); - if (store == null) - { - throw new AVMNotFoundException("Store not found: " + storeName); - } - store.setStoreAcl(acl); - - AVMDAOs.Instance().fAVMStoreDAO.update(store); - } - - /** - * Get the ACL on a store. - * - * @param storeName - * @return - */ - public DbAccessControlList getStoreAcl(String storeName) - { - AVMStore store = getAVMStoreByName(storeName); - if (store == null) - { - throw new AVMNotFoundException("Store not found: " + storeName); - } - return store.getStoreAcl(); - } - - /** - * @param name - * @param version - * @return - */ - public List getAVMStoreVersionsTo(String name, int version) - { - AVMStore store = getAVMStoreByName(name); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getVersionsTo(version); - } - - /** - * @param name - * @param version - * @return - */ - public List getAVMStoreVersionsFrom(String name, int version) - { - AVMStore store = getAVMStoreByName(name); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getVersionsFrom(version); - } - - /** - * @param name - * @param startVersion - * @param endVersion - * @return - */ - public List getAVMStoreVersionsBetween(String name, int startVersion, int endVersion) - { - AVMStore store = getAVMStoreByName(name); - if (store == null) - { - throw new AVMNotFoundException("Store not found."); - } - return store.getVersionsBetween(startVersion, endVersion); - } -} + { + throw new AVMBadArgumentException("Bad store name: " + destName); + } + store.setName(destName); + + AVMDAOs.Instance().fAVMStoreDAO.update(store); + + store.createSnapshot("Rename Store", "Rename Store from " + sourceName + " to " + destName, new HashMap()); + fLookupCache.onDelete(sourceName); + fAVMStoreDAO.invalidateCache(); + fPurgeStoreTxnListener.storePurged(sourceName); + fCreateStoreTxnListener.storeCreated(destName); + } + + /** + * Revert a head path to a given version. This works by cloning the version to revert to, and then linking that new + * version into head. The reverted version will have the previous head version as ancestor. + * + * @param path + * The path to the parent directory. + * @param name + * The name of the node. + * @param toRevertTo + * The descriptor of the version to revert to. + */ + public void revert(String path, String name, AVMNodeDescriptor toRevertTo) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found: " + pathParts[0]); + } + fLookupCache.onWrite(pathParts[0]); + store.revert(pathParts[1], name, toRevertTo); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Set the GUID on a node. + * + * @param path + * @param guid + */ + public void setGuid(String path, String guid) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store not found:" + pathParts[0]); + } + fLookupCache.onWrite(pathParts[0]); + store.setGuid(pathParts[1], guid); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Set the encoding on a node. + * + * @param path + * @param encoding + */ + public void setEncoding(String path, String encoding) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store Not Found: " + pathParts[0]); + } + fLookupCache.onWrite(pathParts[0]); + store.setEncoding(pathParts[1], encoding); + } + finally + { + fLookupCount.set(null); + } + } + + /** + * Set the mime type on a node. + * + * @param path + * @param encoding + */ + public void setMimeType(String path, String mimeType) + { + fLookupCount.set(1); + try + { + String[] pathParts = SplitPath(path); + AVMStore store = getAVMStoreByName(pathParts[0]); + if (store == null) + { + throw new AVMNotFoundException("Store Not Found: " + pathParts[0]); + } + fLookupCache.onWrite(pathParts[0]); + store.setMimeType(pathParts[1], mimeType); + } + finally + { + fLookupCount.set(null); + } + } + + public List getPathsInStoreVersion(AVMNodeDescriptor desc, String store, int version) + { + AVMNode node = fAVMNodeDAO.getByID(desc.getId()); + if (node == null) + { + throw new AVMNotFoundException("Not found: " + desc); + } + List paths = new ArrayList(); + List components = new ArrayList(); + recursiveGetStoreVersionPaths(store, node, version, components, paths); + return paths; + } + + /** + * Do the actual work. + * + * @param node + * The current node. + * @param components + * The currently accumulated path components. + * @param paths + * The list to put full paths in. + */ + private void recursiveGetStoreVersionPaths(String storeName, AVMNode node, int version, List components, List paths) + { + if (!can(null, node, PermissionService.READ, false)) + { + return; + } + if (node.getIsRoot()) + { + VersionRoot versionRoot = fVersionRootDAO.getByRoot(node); + if (versionRoot.getAvmStore().getName().equals(storeName) && versionRoot.getVersionID() == version) + { + addPath(components, storeName, paths); + return; + } + return; + } + List entries = fChildEntryDAO.getByChild(node); + for (ChildEntry entry : entries) + { + String name = entry.getKey().getName(); + components.add(name); + AVMNode parent = entry.getKey().getParent(); + recursiveGetStoreVersionPaths(storeName, parent, version, components, paths); + components.remove(components.size() - 1); + } + } + + public Map getNodeProperties(AVMNodeDescriptor desc) + { + AVMNode node = fAVMNodeDAO.getByID(desc.getId()); + if (node == null) + { + throw new AVMNotFoundException("Node not found: " + desc); + } + if (!can(null, node, PermissionService.READ_PROPERTIES, false)) + { + throw new AccessDeniedException("Not allowed to read properties: " + desc); + } + return node.getProperties(); + } + + public ContentData getContentDataForRead(AVMNodeDescriptor desc) + { + AVMNode node = fAVMNodeDAO.getByID(desc.getId()); + if (node == null) + { + throw new AVMNotFoundException("Node not found: " + desc); + } + if (!can(null, node, PermissionService.READ_CONTENT, false)) + { + throw new AccessDeniedException("Not allowed to read: " + desc); + } + if (node.getType() == AVMNodeType.PLAIN_FILE) + { + PlainFileNode file = (PlainFileNode) node; + return file.getContentData(); + } + else if (node.getType() == AVMNodeType.LAYERED_FILE) + { + LayeredFileNode file = (LayeredFileNode) node; + return file.getContentData(null); + } + throw new AVMWrongTypeException("Not a file: " + desc); + } + + public Set getAspects(AVMNodeDescriptor desc) + { + AVMNode node = fAVMNodeDAO.getByID(desc.getId()); + if (node == null) + { + throw new AVMNotFoundException("Node not found: " + desc); + } + if (!can(null, node, PermissionService.READ_PROPERTIES, false)) + { + throw new AccessDeniedException("Not allowed to read properties: " + desc); + } + Set aspectQNames = node.getAspects(); + return aspectQNames; + } + + /** + * Evaluate permission on a node. I've got a bad feeling about this... + * + * @param store + * @param node + * @param permission + * @return + */ + public boolean can(AVMStore store, AVMNode node, String permission, boolean isDirectlyContained) + { + DbAccessControlList acl = node.getAcl(); + + QName type; + if (node.getType() == AVMNodeType.PLAIN_DIRECTORY) + { + type = WCMModel.TYPE_AVM_PLAIN_FOLDER; + } + else if (node.getType() == AVMNodeType.PLAIN_FILE) + { + type = WCMModel.TYPE_AVM_PLAIN_CONTENT; + } + else if (node.getType() == AVMNodeType.LAYERED_DIRECTORY) + { + type = WCMModel.TYPE_AVM_LAYERED_FOLDER; + } + else + { + type = WCMModel.TYPE_AVM_LAYERED_CONTENT; + } + PermissionContext context = new PermissionContext(type); + + context.addDynamicAuthorityAssignment(node.getBasicAttributes().getOwner(), PermissionService.OWNER_AUTHORITY); + + if ((store != null) && isDirectlyContained) + { + String storeOwner = getStoreUserName(store.getName()); + if (storeOwner != null) + { + // Special case: WCM author sandbox (author, author preview, author workflow, author workflow preview) + context.addDynamicAuthorityAssignment(storeOwner, PermissionService.WCM_STORE_OWNER_AUTHORITY); + } + + /* + StoreType storeType = StoreType.getStoreType(store.getName(), store.getDescriptor(), store.getProperties()); + switch (storeType) + { + case AUTHOR: + case AUTHOR_PREVIEW: + case AUTHOR_WORKFLOW: + case AUTHOR_WORKFLOW_PREVIEW: + String storeName = store.getName(); + int first = -1; + int second = -1; + first = storeName.indexOf("--"); + if (first >= 0) + { + second = storeName.indexOf("--", first + 2); + String storeOwner; + if (second >= 0) + { + storeOwner = storeName.substring(first + 2, second); + } + else + { + storeOwner = storeName.substring(first + 2); + } + context.addDynamicAuthorityAssignment(storeOwner, PermissionService.WCM_STORE_OWNER_AUTHORITY); + } + break; + case STAGING: + case STAGING_PREVIEW: + case UNKNOWN: + case WORKFLOW: + case WORKFLOW_PREVIEW: + default: + } + */ + } + + // Pass in node aspects + Set nodeAspectQNames = node.getAspects(); + Set contextQNames = context.getAspects(); + contextQNames.addAll(nodeAspectQNames); + + /* TODO review - PermissionContext.getProperties() not currently used ? + // Pass in node properties + Map nodeProperties = node.getProperties(); + Map contextProperties = new HashMap(5); + QNameDAO qnameDAO = AVMDAOs.Instance().fQNameDAO; + for (Map.Entry entry : nodeProperties.entrySet()) + { + QName qname = qnameDAO.getQName(entry.getKey()).getSecond(); + PropertyDefinition def = fDictionaryService.getProperty(qname); + if (def == null) + { + contextProperties.put(qname, entry.getValue().getValue(DataTypeDefinition.ANY)); + } + else + { + contextProperties.put(qname, entry.getValue().getValue(def.getDataType().getName())); + } + } + context.getProperties().putAll(contextProperties); + */ + + Long aclId = null; + if (acl != null) + { + aclId = acl.getId(); + } + if (store != null) + { + DbAccessControlList storeAcl = store.getStoreAcl(); + if (storeAcl != null) + { + Long storeAclID = storeAcl.getId(); + context.setStoreAcl(storeAclID); + } + } + return fPermissionService.hasPermission(aclId, context, permission) == AccessStatus.ALLOWED; + } + + private final static String WCM_STORE_SEPARATOR = "--"; + private final static String WCM_STORE_PREVIEW = "--preview"; + private final static String WCM_STORE_WORKFLOW = "--workflow-"; + + // TODO - merge with WCM 3.x utils + // + // Note: relies on WCM sandbox naming convention + // + // Staging: mystore + // Staging preview: mystore--preview + // Author: mystore--myuserid + // Author preview: mystore--myuserid--preview + // Author workflow: mystore--myuserid--workflow-guid + // Author workflow preview: mystore--myuserid--workflow-guid--preview + // Workflow: mystore--workflow-guid + // Workflow preview: mystore--worklow-guid--preview + // + private static String getStoreUserName(String storeName) + { + String storeOwner = null; + int preview = storeName.indexOf(WCM_STORE_PREVIEW); + if (preview >= 0) + { + // strip off "--preview" + storeName = storeName.substring(0, preview); + } + int workflow = storeName.indexOf(WCM_STORE_WORKFLOW); + if (workflow >= 0) + { + // strip off "--workflow-" + storeName = storeName.substring(0, workflow); + } + int author = storeName.indexOf(WCM_STORE_SEPARATOR); + if (author >= 0) + { + storeOwner = storeName.substring(author + 2); + } + return storeOwner; + } + + public boolean can(String storeName, int version, String path, String permission) + { + Lookup lookup = AVMRepository.GetInstance().lookup(version, path, true); + if (lookup != null) + { + AVMNode node = lookup.getCurrentNode(); + AVMStore store = getAVMStoreByName(storeName); + return can(store, node, permission, lookup.getDirectlyContained()); + } + else + { + // Does not exist => allowed + return true; + } + } + + /** + * Set the acl on a store. + * + * @param storeName + * @param acl + */ + public void setStoreAcl(String storeName, DbAccessControlList acl) + { + AVMStore store = getAVMStoreByName(storeName); + if (store == null) + { + throw new AVMNotFoundException("Store not found: " + storeName); + } + store.setStoreAcl(acl); + + AVMDAOs.Instance().fAVMStoreDAO.update(store); + } + + /** + * Get the ACL on a store. + * + * @param storeName + * @return + */ + public DbAccessControlList getStoreAcl(String storeName) + { + AVMStore store = getAVMStoreByName(storeName); + if (store == null) + { + throw new AVMNotFoundException("Store not found: " + storeName); + } + return store.getStoreAcl(); + } + + /** + * @param name + * @param version + * @return + */ + public List getAVMStoreVersionsTo(String name, int version) + { + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getVersionsTo(version); + } + + /** + * @param name + * @param version + * @return + */ + public List getAVMStoreVersionsFrom(String name, int version) + { + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getVersionsFrom(version); + } + + /** + * @param name + * @param startVersion + * @param endVersion + * @return + */ + public List getAVMStoreVersionsBetween(String name, int startVersion, int endVersion) + { + AVMStore store = getAVMStoreByName(name); + if (store == null) + { + throw new AVMNotFoundException("Store not found."); + } + return store.getVersionsBetween(startVersion, endVersion); + } +} diff --git a/source/java/org/alfresco/repo/avm/AVMServiceImpl.java b/source/java/org/alfresco/repo/avm/AVMServiceImpl.java index 0482972055..9594a646c7 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceImpl.java @@ -521,7 +521,7 @@ public class AVMServiceImpl implements AVMService } /** - * Create an AVMStore with the given name (it must not exist). + * Create an AVMStore with the given name (it must not exist). * @param name The name to give the AVMStore. */ public void createStore(String name) @@ -532,22 +532,22 @@ public class AVMServiceImpl implements AVMService } fAVMRepository.createAVMStore(name); } - + + /** + * Create an AVMStore with the given name (it must not exist) and set store properties. + * @param name The name to give the AVMStore. + * @param props A Map of the properties to set. + */ + public void createStore(String name, Map props) + { + if (name == null || !FileNameValidator.isValid(name)) + { + throw new AVMBadArgumentException("Bad Name."); + } + fAVMRepository.createAVMStore(name, props); + } + /** - * Create an AVMStore with the given name (it must not exist) and set store properties. - * @param name The name to give the AVMStore. - * @param props A Map of the properties to set. - */ - public void createStore(String name, Map props) - { - if (name == null || !FileNameValidator.isValid(name)) - { - throw new AVMBadArgumentException("Bad Name."); - } - fAVMRepository.createAVMStore(name, props); - } - - /** * Create a branch. * @param version The version to branch from. * @param srcPath The path to the thing to branch from. @@ -1552,7 +1552,7 @@ public class AVMServiceImpl implements AVMService createFile(path, name, in); if (acl != null) { - setAclAsSystem(newPath, acl.getCopy(parentAclId, ACLCopyMode.COPY)); + setAclAsSystem(newPath, AVMDAOs.Instance().fAclDAO.getDbAccessControlListCopy(acl.getId(), parentAclId, ACLCopyMode.COPY)); } ContentData cd = getContentDataForRead(version, desc.getPath()); setEncoding(newPath, cd.getEncoding()); @@ -1571,7 +1571,7 @@ public class AVMServiceImpl implements AVMService // Set acl before creating children as acls inherit :-) if (acl != null) { - setAclAsSystem(newPath, acl.getCopy(parentAclId, ACLCopyMode.COPY)); + setAclAsSystem(newPath, AVMDAOs.Instance().fAclDAO.getDbAccessControlListCopy(acl.getId(), parentAclId, ACLCopyMode.COPY)); } } Map listing = getDirectoryListing(desc); diff --git a/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java b/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java index 7b2bade48c..446ac87697 100644 --- a/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java @@ -34,12 +34,12 @@ import org.alfresco.config.JNDIConstants; import org.alfresco.model.ContentModel; import org.alfresco.repo.domain.AccessControlListDAO; import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.domain.permissions.AclDAO; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.MutableAuthenticationDao; import org.alfresco.repo.security.permissions.PermissionReference; import org.alfresco.repo.security.permissions.PermissionServiceSPI; -import org.alfresco.repo.security.permissions.impl.AclDaoComponent; import org.alfresco.repo.security.permissions.impl.ModelDAO; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; @@ -100,7 +100,7 @@ public class AVMServicePermissionsTest extends TestCase protected AuthorityService authorityService; - private AclDaoComponent aclDaoComponent; + private AclDAO aclDaoComponent; private UserTransaction testTX; @@ -119,14 +119,14 @@ public class AVMServicePermissionsTest extends TestCase super(); } - @Override - protected void setUp() throws Exception + @Override + protected void setUp() throws Exception { avmNodeDAO = (AVMNodeDAO) applicationContext.getBean("avmNodeDAO"); - avmACLDAO = (AccessControlListDAO) applicationContext.getBean("avmACLDAO"); + avmACLDAO = (AccessControlListDAO) applicationContext.getBean("avmNodeACLDAO"); - aclDaoComponent = (AclDaoComponent) applicationContext.getBean("aclDaoComponent"); + aclDaoComponent = (AclDAO) applicationContext.getBean("aclDAO"); avmService = (AVMService) applicationContext.getBean("avmService"); avmSyncService = (AVMSyncService) applicationContext.getBean("AVMSyncService"); @@ -208,14 +208,14 @@ public class AVMServicePermissionsTest extends TestCase authenticationService.createAuthentication("reviewer", "reviewer".toCharArray()); authenticationComponent.clearCurrentSecurityContext(); - - if (avmService.getStore("main") != null) - { - avmService.purgeStore("main"); - } + + if (avmService.getStore("main") != null) + { + avmService.purgeStore("main"); + } } - @Override + @Override protected void tearDown() throws Exception { @@ -402,7 +402,7 @@ public class AVMServicePermissionsTest extends TestCase public void testSetup() throws Exception { - // test setUp & tearDown + // test setUp & tearDown } public void testStoreAcls() throws Exception @@ -3937,7 +3937,7 @@ public class AVMServicePermissionsTest extends TestCase private static final String FILE_NAME = "fileForExport"; private static final String ROOT = "ROOT"; - private void createStagingWithSnapshots(String storeName) + private void createStagingWithSnapshots(String storeName) { if (avmService.getStore(storeName) != null) { @@ -3964,40 +3964,40 @@ public class AVMServicePermissionsTest extends TestCase private void removeStore(String storeName) { - if (avmService.getStore(storeName) != null) - { - avmService.purgeStore(storeName); - } + if (avmService.getStore(storeName) != null) + { + avmService.purgeStore(storeName); + } assertNull(avmService.getStore(storeName)); } - - public void testSetInheritParentPermissions() throws Exception + + public void testSetInheritParentPermissions() throws Exception { - runAs(AuthenticationUtil.getAdminUserName()); - String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); - try - { - createStagingWithSnapshots(storeName); - - AVMNodeDescriptor nodeDescriptor = avmService.lookup(-1, storeName + ":/" + JNDIConstants.DIR_DEFAULT_WWW + "/" + JNDIConstants.DIR_DEFAULT_APPBASE + "/" + ROOT + "/" - + FILE_NAME); - assertNotNull(nodeDescriptor); - NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, nodeDescriptor.getPath()); - assertNotNull(nodeRef); - - permissionService.setInheritParentPermissions(nodeRef, false); - assertFalse(permissionService.getInheritParentPermissions(nodeRef)); - permissionService.setInheritParentPermissions(nodeRef, true); - assertTrue(permissionService.getInheritParentPermissions(nodeRef)); - } - catch (Exception e) - { - e.printStackTrace(); - throw e; - } - finally - { - removeStore(storeName); - } + runAs(AuthenticationUtil.getAdminUserName()); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + createStagingWithSnapshots(storeName); + + AVMNodeDescriptor nodeDescriptor = avmService.lookup(-1, storeName + ":/" + JNDIConstants.DIR_DEFAULT_WWW + "/" + JNDIConstants.DIR_DEFAULT_APPBASE + "/" + ROOT + "/" + + FILE_NAME); + assertNotNull(nodeDescriptor); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, nodeDescriptor.getPath()); + assertNotNull(nodeRef); + + permissionService.setInheritParentPermissions(nodeRef, false); + assertFalse(permissionService.getInheritParentPermissions(nodeRef)); + permissionService.setInheritParentPermissions(nodeRef, true); + assertTrue(permissionService.getInheritParentPermissions(nodeRef)); + } + catch (Exception e) + { + e.printStackTrace(); + throw e; + } + finally + { + removeStore(storeName); + } } } diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java b/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java index cbbb5db0bd..154212f1ef 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceTestBase.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,568 +14,564 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . */ - -package org.alfresco.repo.avm; - -import java.io.IOException; -import java.util.Map; -import java.util.TreeMap; - -import junit.framework.TestCase; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.content.MimetypeMap; -import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor; -import org.alfresco.repo.search.IndexerAndSearcher; -import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; -import org.alfresco.repo.security.authentication.AuthenticationComponent; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.cmr.avm.AVMService; -import org.alfresco.service.cmr.avm.locking.AVMLockingService; -import org.alfresco.service.cmr.avmsync.AVMSyncService; -import org.alfresco.service.cmr.repository.ContentWriter; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.search.ResultSet; -import org.alfresco.service.cmr.search.ResultSetRow; -import org.alfresco.service.cmr.search.SearchService; -import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.service.transaction.TransactionService; -import org.springframework.context.ApplicationContext; - -/** - * Base class for AVMService tests. - * @author britt - */ -public class AVMServiceTestBase extends TestCase -{ - /** - * The AVMService we are testing. - */ - protected static AVMService fService; - - /** - * The reaper thread. - */ - protected static OrphanReaper fReaper; - - /** - * The AVMSyncService. - */ - protected static AVMSyncService fSyncService; - /** - * The application context. - */ - protected static ApplicationContext fContext; - - /** - * The start time of actual work for a test. - */ - private long fStartTime; - - protected static RetryingTransactionHelper fRetryingTransactionHelper; - - protected static AuthenticationComponent fAuthenticationComponent; - - protected static AVMSnapShotTriggeredIndexingMethodInterceptor fIndexingInterceptor; - - protected static TransactionService fTransactionService; - - protected static IndexerAndSearcher fIndexerAndSearcher; - - protected static AVMLockingService fLockingService; - - protected static AuthenticationService fAuthService; - - - public void testSetup() throws Exception - { - setupBasicTree(); - } - - /** - * Setup for AVM tests. Note that we set the polling - * interval for the reaper to 4 seconds so that tests will - * finish reasonably quickly. - */ - @Override - protected void setUp() throws Exception - { - if (fContext == null) - { - fContext = AVMTestSuite.getContext(); - - fService = (AVMService)fContext.getBean("AVMService"); - fReaper = (OrphanReaper)fContext.getBean("orphanReaper"); - fSyncService = (AVMSyncService)fContext.getBean("AVMSyncService"); - fIndexerAndSearcher = (IndexerAndSearcher)fContext.getBean("indexerAndSearcherFactory"); - fTransactionService = (TransactionService)fContext.getBean("transactionComponent"); - fLockingService = (AVMLockingService)fContext.getBean("AVMLockingService"); - fIndexingInterceptor = (AVMSnapShotTriggeredIndexingMethodInterceptor)fContext.getBean("avmSnapShotTriggeredIndexingMethodInterceptor"); - fAuthService = (AuthenticationService)fContext.getBean("AuthenticationService"); - fAuthenticationComponent = (AuthenticationComponent) fContext.getBean("authenticationComponent"); - fRetryingTransactionHelper = (RetryingTransactionHelper) fContext.getBean("retryingTransactionHelper"); - - CreateStoreTxnListener cstl = (CreateStoreTxnListener)fContext.getBean("createStoreTxnListener"); - cstl.addCallback( - new CreateStoreCallback() - { - public void storeCreated(String name) - { - System.err.println("Store created: " + name); - } - } - ); - PurgeStoreTxnListener pstl = (PurgeStoreTxnListener)fContext.getBean("purgeStoreTxnListener"); - pstl.addCallback( - new PurgeStoreCallback() - { - public void storePurged(String name) - { - System.err.println("Store purged: " + name); - } - } - ); - CreateVersionTxnListener cvtl = (CreateVersionTxnListener)fContext.getBean("createVersionTxnListener"); - cvtl.addCallback( - new CreateVersionCallback() - { - public void versionCreated(String name, int versionID) - { - System.err.println("Version created: " + name + " " + versionID); - } - } - ); - PurgeVersionTxnListener pvtl = (PurgeVersionTxnListener)fContext.getBean("purgeVersionTxnListener"); - pvtl.addCallback( - new PurgeVersionCallback() - { - public void versionPurged(String name, int versionID) - { - System.err.println("Version purged: " + name + " " + versionID); - } - } - ); - } - - fAuthService.authenticate(AuthenticationUtil.getAdminUserName(), "admin".toCharArray()); - - if (fService.getStore("main") != null) - { - fService.purgeStore("main"); - } - fService.createStore("main"); - - if (fService.getStore("layer") != null) - { - fService.purgeStore("layer"); - } - - if (!fLockingService.getWebProjects().contains("main")) - { - fLockingService.addWebProject("main"); - } - fStartTime = System.currentTimeMillis(); - } - - /** - * Cleanup after a test. Purge main store. - */ - @Override - protected void tearDown() throws Exception - { - long now = System.currentTimeMillis(); - System.out.println("Timing: " + (now - fStartTime) + "ms"); - - if (fService.getStore("main") != null) { fService.purgeStore("main"); } - - // Move alf_data directory aside. - // fContext.close(); - // File alfData = new File("alf_data"); - // File target = new File("alf_data" + now); - // alfData.renameTo(target); - - AuthenticationUtil.clearCurrentSecurityContext(); - } - - /** - * Get the recursive contents of the given path and version. - * @param path - * @param version - * @return A string representation of the contents. - */ - protected String recursiveContents(String path, int version, boolean followLinks) - { - String val = recursiveList(path, version, 0, followLinks); - return val.substring(val.indexOf('\n')); - } - - - /** - * Helper to write a recursive listing of an AVMStore at a given version. - * @param repoName The name of the AVMStore. - * @param version The version to look under. - */ - protected String recursiveList(String repoName, int version, boolean followLinks) - { - return recursiveList(repoName + ":/", version, 0, followLinks); - } - - /** - * Recursive list the given path. - * @param path The path. - * @param version The version. - * @param indent The current indent level. - */ - protected String recursiveList(String path, int version, int indent, boolean followLinks) - { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < indent; i++) - { - builder.append(' '); - } - builder.append(path.substring(path.lastIndexOf('/') + 1)); - builder.append(' '); - AVMNodeDescriptor desc = fService.lookup(version, path, true); - builder.append(desc.toString()); - builder.append('\n'); - if (desc.getType() == AVMNodeType.PLAIN_DIRECTORY || - (desc.getType() == AVMNodeType.LAYERED_DIRECTORY && followLinks)) - { - String basename = path.endsWith("/") ? path : path + "/"; - Map listing = fService.getDirectoryListing(version, path, true); - for (String name : listing.keySet()) - { - System.err.println(name); - builder.append(recursiveList(basename + name, version, indent + 2, followLinks)); - } - } - return builder.toString(); - } - - /** - * Setup a basic tree. - */ - protected void setupBasicTree0() - throws IOException - { - fService.createDirectory("main:/", "a"); - fService.createDirectory("main:/a", "b"); - fService.createDirectory("main:/a/b", "c"); - fService.createDirectory("main:/", "d"); - fService.createDirectory("main:/d", "e"); - fService.createDirectory("main:/d/e", "f"); - - fService.createFile("main:/a/b/c", "foo").close(); - ContentWriter writer = fService.getContentWriter("main:/a/b/c/foo", true); - writer.setEncoding("UTF-8"); - writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); - writer.putContent("I am main:/a/b/c/foo"); - - fService.createFile("main:/a/b/c", "bar").close(); - writer = fService.getContentWriter("main:/a/b/c/bar", true); - /* - // Force a conversion - writer.setEncoding("UTF-16"); - writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); - writer.putContent(new ByteArrayInputStream("I am main:/a/b/c/bar".getBytes("UTF-16"))); - */ - writer.setEncoding("UTF-8"); - writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); - writer.putContent("I am main:/a/b/c/bar"); - - fService.createSnapshot("main", null, null); - } - - protected void setupBasicTree() - throws IOException - { - setupBasicTree0(); - runQueriesAgainstBasicTree("main"); - } - - protected void runQueriesAgainstBasicTree(String store) - { - StoreRef storeRef = AVMNodeConverter.ToStoreRef(store); - - // Text index - SearchService searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef(store), true); - ResultSet results = searchService.query(storeRef, "lucene", "TEXT:\"I am main\""); - assertEquals(2, results.length()); - results.close(); - - // Basic properties - - // Note "a" is a stop word and therefore not findable ... - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NAME)+":\"foo\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NAME)+":foo"); - assertEquals(1, results.length()); - results.close(); - - // TODO: Fix auth in AVMDiskDriver and more?? - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_CREATOR)+":admin"); - - assertEquals(9, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_MODIFIER)+":admin"); - assertEquals(9, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_OWNER)+":admin"); - assertEquals(9, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NODE_UUID)+":unknown"); - assertEquals(9, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_STORE_PROTOCOL)+":avm"); - assertEquals(9, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_STORE_IDENTIFIER)+":"+store); - assertEquals(9, results.length()); - results.close(); - - // Basic paths - - results = searchService.query(storeRef, "lucene", "PATH:\"/\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a/b\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c/foo\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c/bar\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/d\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/d/e\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/d/e/f\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"//.\""); - assertEquals(9, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"//*\""); - assertEquals(8, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a//.\""); - assertEquals(5, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a//*\""); - assertEquals(4, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a/*\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"//c/*\""); - assertEquals(2, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/*\""); - assertEquals(2, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/*/*\""); - assertEquals(2, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*\""); - assertEquals(2, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*/*\""); - assertEquals(2, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*/*/*\""); - assertEquals(0, results.length()); - results.close(); - } - - protected void runQueriesAgainstBasicTreeWithAOnly(String store) - { - StoreRef storeRef = AVMNodeConverter.ToStoreRef(store); - - // Text index - SearchService searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef(store), true); - ResultSet results = searchService.query(storeRef, "lucene", "TEXT:\"I am main\""); - assertEquals(2, results.length()); - results.close(); - - // Basic properties - - // Note "a" is a stop word and therefore not findable ... - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NAME)+":\"foo\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NAME)+":foo"); - assertEquals(1, results.length()); - results.close(); - - // TODO: Fix auth in AVMDiskDriver and more?? - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_CREATOR)+":admin"); - if(results.length() == 10) - { - for (ResultSetRow row : results) - { - System.out.println(row.getNodeRef()); - } - } - assertEquals(6, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_MODIFIER)+":admin"); - assertEquals(6, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_OWNER)+":admin"); - assertEquals(6, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NODE_UUID)+":unknown"); - assertEquals(6, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_STORE_PROTOCOL)+":avm"); - assertEquals(6, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_STORE_IDENTIFIER)+":"+store); - assertEquals(6, results.length()); - results.close(); - - // Basic paths - - results = searchService.query(storeRef, "lucene", "PATH:\"/\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a/b\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c/foo\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c/bar\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/d\""); - assertEquals(0, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/d/e\""); - assertEquals(0, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/d/e/f\""); - assertEquals(0, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"//.\""); - assertEquals(6, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"//*\""); - assertEquals(5, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a//.\""); - assertEquals(5, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a//*\""); - assertEquals(4, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/a/*\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"//c/*\""); - assertEquals(2, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/*\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/*/*\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*\""); - assertEquals(1, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*/*\""); - assertEquals(2, results.length()); - results.close(); - - results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*/*/*\""); - assertEquals(0, results.length()); - results.close(); - } - - /** - * Check that history has not been screwed up. - */ - protected void checkHistory(TreeMap history, String repName) - { - for (Integer i : history.keySet()) - { - assertEquals(history.get(i), recursiveList(repName, i, false)); - } - int latest = fService.getNextVersionID(repName); - history.put(latest - 1, recursiveList(repName, -1, false)); - } -} + * along with Alfresco. If not, see . */ + +package org.alfresco.repo.avm; + +import java.io.IOException; +import java.util.Map; +import java.util.TreeMap; + +import junit.framework.TestCase; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor; +import org.alfresco.repo.search.IndexerAndSearcher; +import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; +import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avm.locking.AVMLockingService; +import org.alfresco.service.cmr.avmsync.AVMSyncService; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.ResultSetRow; +import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.transaction.TransactionService; +import org.springframework.context.ApplicationContext; + +/** + * Base class for AVMService tests. + * @author britt + */ +public class AVMServiceTestBase extends TestCase +{ + /** + * The AVMService we are testing. + */ + protected static AVMService fService; + + /** + * The reaper thread. + */ + protected static OrphanReaper fReaper; + + /** + * The AVMSyncService. + */ + protected static AVMSyncService fSyncService; + /** + * The application context. + */ + protected static ApplicationContext fContext; + + /** + * The start time of actual work for a test. + */ + private long fStartTime; + + protected static RetryingTransactionHelper fRetryingTransactionHelper; + + protected static AuthenticationComponent fAuthenticationComponent; + + protected static AVMSnapShotTriggeredIndexingMethodInterceptor fIndexingInterceptor; + + protected static TransactionService fTransactionService; + + protected static IndexerAndSearcher fIndexerAndSearcher; + + protected static AVMLockingService fLockingService; + + protected static AuthenticationService fAuthService; + + + public void testSetup() throws Exception + { + setupBasicTree(); + } + + /** + * Setup for AVM tests. Note that we set the polling + * interval for the reaper to 4 seconds so that tests will + * finish reasonably quickly. + */ + @Override + protected void setUp() throws Exception + { + if (fContext == null) + { + fContext = AVMTestSuite.getContext(); + + fService = (AVMService)fContext.getBean("AVMService"); + fReaper = (OrphanReaper)fContext.getBean("orphanReaper"); + fSyncService = (AVMSyncService)fContext.getBean("AVMSyncService"); + fIndexerAndSearcher = (IndexerAndSearcher)fContext.getBean("indexerAndSearcherFactory"); + fTransactionService = (TransactionService)fContext.getBean("transactionComponent"); + fLockingService = (AVMLockingService)fContext.getBean("AVMLockingService"); + fIndexingInterceptor = (AVMSnapShotTriggeredIndexingMethodInterceptor)fContext.getBean("avmSnapShotTriggeredIndexingMethodInterceptor"); + fAuthService = (AuthenticationService)fContext.getBean("AuthenticationService"); + fAuthenticationComponent = (AuthenticationComponent) fContext.getBean("authenticationComponent"); + fRetryingTransactionHelper = (RetryingTransactionHelper) fContext.getBean("retryingTransactionHelper"); + + CreateStoreTxnListener cstl = (CreateStoreTxnListener)fContext.getBean("createStoreTxnListener"); + cstl.addCallback( + new CreateStoreCallback() + { + public void storeCreated(String name) + { + System.err.println("Store created: " + name); + } + } + ); + PurgeStoreTxnListener pstl = (PurgeStoreTxnListener)fContext.getBean("purgeStoreTxnListener"); + pstl.addCallback( + new PurgeStoreCallback() + { + public void storePurged(String name) + { + System.err.println("Store purged: " + name); + } + } + ); + CreateVersionTxnListener cvtl = (CreateVersionTxnListener)fContext.getBean("createVersionTxnListener"); + cvtl.addCallback( + new CreateVersionCallback() + { + public void versionCreated(String name, int versionID) + { + System.err.println("Version created: " + name + " " + versionID); + } + } + ); + PurgeVersionTxnListener pvtl = (PurgeVersionTxnListener)fContext.getBean("purgeVersionTxnListener"); + pvtl.addCallback( + new PurgeVersionCallback() + { + public void versionPurged(String name, int versionID) + { + System.err.println("Version purged: " + name + " " + versionID); + } + } + ); + } + + fAuthService.authenticate(AuthenticationUtil.getAdminUserName(), "admin".toCharArray()); + + if (fService.getStore("main") != null) + { + fService.purgeStore("main"); + } + fService.createStore("main"); + + if (fService.getStore("layer") != null) + { + fService.purgeStore("layer"); + } + + fStartTime = System.currentTimeMillis(); + } + + /** + * Cleanup after a test. Purge main store. + */ + @Override + protected void tearDown() throws Exception + { + long now = System.currentTimeMillis(); + System.out.println("Timing: " + (now - fStartTime) + "ms"); + + if (fService.getStore("main") != null) { fService.purgeStore("main"); } + + // Move alf_data directory aside. + // fContext.close(); + // File alfData = new File("alf_data"); + // File target = new File("alf_data" + now); + // alfData.renameTo(target); + + AuthenticationUtil.clearCurrentSecurityContext(); + } + + /** + * Get the recursive contents of the given path and version. + * @param path + * @param version + * @return A string representation of the contents. + */ + protected String recursiveContents(String path, int version, boolean followLinks) + { + String val = recursiveList(path, version, 0, followLinks); + return val.substring(val.indexOf('\n')); + } + + + /** + * Helper to write a recursive listing of an AVMStore at a given version. + * @param repoName The name of the AVMStore. + * @param version The version to look under. + */ + protected String recursiveList(String repoName, int version, boolean followLinks) + { + return recursiveList(repoName + ":/", version, 0, followLinks); + } + + /** + * Recursive list the given path. + * @param path The path. + * @param version The version. + * @param indent The current indent level. + */ + protected String recursiveList(String path, int version, int indent, boolean followLinks) + { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < indent; i++) + { + builder.append(' '); + } + builder.append(path.substring(path.lastIndexOf('/') + 1)); + builder.append(' '); + AVMNodeDescriptor desc = fService.lookup(version, path, true); + builder.append(desc.toString()); + builder.append('\n'); + if (desc.getType() == AVMNodeType.PLAIN_DIRECTORY || + (desc.getType() == AVMNodeType.LAYERED_DIRECTORY && followLinks)) + { + String basename = path.endsWith("/") ? path : path + "/"; + Map listing = fService.getDirectoryListing(version, path, true); + for (String name : listing.keySet()) + { + System.err.println(name); + builder.append(recursiveList(basename + name, version, indent + 2, followLinks)); + } + } + return builder.toString(); + } + + /** + * Setup a basic tree. + */ + protected void setupBasicTree0() + throws IOException + { + fService.createDirectory("main:/", "a"); + fService.createDirectory("main:/a", "b"); + fService.createDirectory("main:/a/b", "c"); + fService.createDirectory("main:/", "d"); + fService.createDirectory("main:/d", "e"); + fService.createDirectory("main:/d/e", "f"); + + fService.createFile("main:/a/b/c", "foo").close(); + ContentWriter writer = fService.getContentWriter("main:/a/b/c/foo", true); + writer.setEncoding("UTF-8"); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.putContent("I am main:/a/b/c/foo"); + + fService.createFile("main:/a/b/c", "bar").close(); + writer = fService.getContentWriter("main:/a/b/c/bar", true); + /* + // Force a conversion + writer.setEncoding("UTF-16"); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.putContent(new ByteArrayInputStream("I am main:/a/b/c/bar".getBytes("UTF-16"))); + */ + writer.setEncoding("UTF-8"); + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.putContent("I am main:/a/b/c/bar"); + + fService.createSnapshot("main", null, null); + } + + protected void setupBasicTree() + throws IOException + { + setupBasicTree0(); + runQueriesAgainstBasicTree("main"); + } + + protected void runQueriesAgainstBasicTree(String store) + { + StoreRef storeRef = AVMNodeConverter.ToStoreRef(store); + + // Text index + SearchService searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef(store), true); + ResultSet results = searchService.query(storeRef, "lucene", "TEXT:\"I am main\""); + assertEquals(2, results.length()); + results.close(); + + // Basic properties + + // Note "a" is a stop word and therefore not findable ... + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NAME)+":\"foo\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NAME)+":foo"); + assertEquals(1, results.length()); + results.close(); + + // TODO: Fix auth in AVMDiskDriver and more?? + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_CREATOR)+":admin"); + + assertEquals(9, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_MODIFIER)+":admin"); + assertEquals(9, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_OWNER)+":admin"); + assertEquals(9, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NODE_UUID)+":unknown"); + assertEquals(9, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_STORE_PROTOCOL)+":avm"); + assertEquals(9, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_STORE_IDENTIFIER)+":"+store); + assertEquals(9, results.length()); + results.close(); + + // Basic paths + + results = searchService.query(storeRef, "lucene", "PATH:\"/\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a/b\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c/foo\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c/bar\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/d\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/d/e\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/d/e/f\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"//.\""); + assertEquals(9, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"//*\""); + assertEquals(8, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a//.\""); + assertEquals(5, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a//*\""); + assertEquals(4, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a/*\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"//c/*\""); + assertEquals(2, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/*\""); + assertEquals(2, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/*/*\""); + assertEquals(2, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*\""); + assertEquals(2, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*/*\""); + assertEquals(2, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*/*/*\""); + assertEquals(0, results.length()); + results.close(); + } + + protected void runQueriesAgainstBasicTreeWithAOnly(String store) + { + StoreRef storeRef = AVMNodeConverter.ToStoreRef(store); + + // Text index + SearchService searchService = fIndexerAndSearcher.getSearcher(AVMNodeConverter.ToStoreRef(store), true); + ResultSet results = searchService.query(storeRef, "lucene", "TEXT:\"I am main\""); + assertEquals(2, results.length()); + results.close(); + + // Basic properties + + // Note "a" is a stop word and therefore not findable ... + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NAME)+":\"foo\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NAME)+":foo"); + assertEquals(1, results.length()); + results.close(); + + // TODO: Fix auth in AVMDiskDriver and more?? + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_CREATOR)+":admin"); + if(results.length() == 10) + { + for (ResultSetRow row : results) + { + System.out.println(row.getNodeRef()); + } + } + assertEquals(6, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_MODIFIER)+":admin"); + assertEquals(6, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_OWNER)+":admin"); + assertEquals(6, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_NODE_UUID)+":unknown"); + assertEquals(6, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_STORE_PROTOCOL)+":avm"); + assertEquals(6, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", LuceneQueryParser.escape("@"+ContentModel.PROP_STORE_IDENTIFIER)+":"+store); + assertEquals(6, results.length()); + results.close(); + + // Basic paths + + results = searchService.query(storeRef, "lucene", "PATH:\"/\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a/b\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c/foo\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a/b/c/bar\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/d\""); + assertEquals(0, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/d/e\""); + assertEquals(0, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/d/e/f\""); + assertEquals(0, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"//.\""); + assertEquals(6, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"//*\""); + assertEquals(5, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a//.\""); + assertEquals(5, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a//*\""); + assertEquals(4, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/a/*\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"//c/*\""); + assertEquals(2, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/*\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/*/*\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*\""); + assertEquals(1, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*/*\""); + assertEquals(2, results.length()); + results.close(); + + results = searchService.query(storeRef, "lucene", "PATH:\"/*/*/*/*/*\""); + assertEquals(0, results.length()); + results.close(); + } + + /** + * Check that history has not been screwed up. + */ + protected void checkHistory(TreeMap history, String repName) + { + for (Integer i : history.keySet()) + { + assertEquals(history.get(i), recursiveList(repName, i, false)); + } + int latest = fService.getNextVersionID(repName); + history.put(latest - 1, recursiveList(repName, -1, false)); + } +} diff --git a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java index 3c0fa05f10..90e6b06ab1 100644 --- a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,665 +14,661 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . */ - -package org.alfresco.repo.avm; - -import java.io.File; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; - -import org.alfresco.model.ContentModel; -import org.alfresco.model.WCMModel; -import org.alfresco.repo.avm.util.AVMUtil; -import org.alfresco.repo.avm.util.RawServices; -import org.alfresco.repo.avm.util.SimplePath; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.permissions.ACLCopyMode; -import org.alfresco.repo.security.permissions.AccessDeniedException; -import org.alfresco.service.cmr.avm.AVMBadArgumentException; -import org.alfresco.service.cmr.avm.AVMException; -import org.alfresco.service.cmr.avm.AVMExistsException; -import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.cmr.avm.AVMNotFoundException; -import org.alfresco.service.cmr.avm.AVMStoreDescriptor; -import org.alfresco.service.cmr.avm.AVMWrongTypeException; -import org.alfresco.service.cmr.avm.VersionDescriptor; -import org.alfresco.service.cmr.dictionary.AspectDefinition; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -import org.alfresco.service.cmr.dictionary.PropertyDefinition; -import org.alfresco.service.cmr.repository.ContentData; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.cmr.repository.ContentWriter; + * along with Alfresco. If not, see . */ + +package org.alfresco.repo.avm; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.alfresco.model.ContentModel; +import org.alfresco.model.WCMModel; +import org.alfresco.repo.avm.util.AVMUtil; +import org.alfresco.repo.avm.util.RawServices; +import org.alfresco.repo.avm.util.SimplePath; +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.permissions.ACLCopyMode; +import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.service.cmr.avm.AVMBadArgumentException; +import org.alfresco.service.cmr.avm.AVMException; +import org.alfresco.service.cmr.avm.AVMExistsException; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.cmr.avm.AVMNotFoundException; +import org.alfresco.service.cmr.avm.AVMStoreDescriptor; +import org.alfresco.service.cmr.avm.AVMWrongTypeException; +import org.alfresco.service.cmr.avm.VersionDescriptor; +import org.alfresco.service.cmr.dictionary.AspectDefinition; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.InvalidNodeRefException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.GUID; -import org.alfresco.util.Pair; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * A Repository contains a current root directory and a list of - * root versions. Each root version corresponds to a separate snapshot - * operation. - * @author britt - */ -public class AVMStoreImpl implements AVMStore -{ - private static Log logger = LogFactory.getLog(AVMStoreImpl.class); - /** - * The primary key. - */ - private long fID; - - /** - * The name of this AVMStore. - */ - private String fName; - - /** - * The current root directory. - */ - private DirectoryNode fRoot; - - /** - * The next version id. - */ - private int fNextVersionID; - - /** - * The version (for concurrency control). - */ - private long fVers; - - /** - * Acl for this store. - */ - private DbAccessControlList fACL; - - /** - * The AVMRepository. - */ - transient private AVMRepository fAVMRepository; - - /** - * Default constructor. - */ - public AVMStoreImpl() - { - fAVMRepository = AVMRepository.GetInstance(); - } - - /** - * Make a brand new AVMStore. - * @param repo The AVMRepository. - * @param name The name of the AVMStore. - */ - public AVMStoreImpl(AVMRepository repo, String name) - { - // Make ourselves up and save. - fAVMRepository = repo; - - setName(name); - setNextVersionID(0); - setRoot(null); - - AVMDAOs.Instance().fAVMStoreDAO.save(this); - - String creator = RawServices.Instance().getAuthenticationContext().getCurrentUserName(); - if (creator == null) - { - creator = RawServices.Instance().getAuthenticationContext().getSystemUserName(); - } - setProperty(ContentModel.PROP_CREATOR, new PropertyValue(null, creator)); - setProperty(ContentModel.PROP_CREATED, new PropertyValue(null, new Date(System.currentTimeMillis()))); - - // Make up the initial version record and save. - long time = System.currentTimeMillis(); - - PlainDirectoryNode dir = new PlainDirectoryNodeImpl(this); - dir.setIsRoot(true); - AVMDAOs.Instance().fAVMNodeDAO.save(dir); - - setRoot(dir); - - VersionRoot versionRoot = new VersionRootImpl(this, - getRoot(), - getNextVersionID(), - time, - creator, - AVMUtil.INITIAL_SNAPSHOT, - AVMUtil.INITIAL_SNAPSHOT); - setNextVersionID(getNextVersionID()+1); - - AVMDAOs.Instance().fAVMStoreDAO.update(this); - AVMDAOs.Instance().fVersionRootDAO.save(versionRoot); - } - - /** - * Set the primary key - * @param id The primary key. - */ - public void setId(long id) - { - fID = id; - } - - /** - * Get the primary key. - * @return The primary key. - */ - public long getId() - { - return fID; - } - - /** - * Set a new root for this. - * @param root - */ - public void setNewRoot(DirectoryNode root) - { - fRoot = root; - } - - /** - * Snapshot this store. This creates a new version record. - * @return The version id of the new snapshot. - */ - public Map createSnapshot(String tag, String description, Map snapShotMap) - { - long start = System.currentTimeMillis(); - - long rootID = getRoot().getId(); - AVMStoreImpl me = (AVMStoreImpl)AVMDAOs.Instance().fAVMStoreDAO.getByID(getId()); - VersionRoot lastVersion = AVMDAOs.Instance().fVersionRootDAO.getMaxVersion(me); - List layeredEntries = - AVMDAOs.Instance().fVersionLayeredNodeEntryDAO.get(lastVersion); - // Is there no need for a snapshot? - DirectoryNode root = (DirectoryNode)AVMDAOs.Instance().fAVMNodeDAO.getByID(rootID); - if (!root.getIsNew() && layeredEntries.size() == 0) - { - if (logger.isTraceEnabled()) - { - logger.trace("createSnapshot: no snapshot required: "+me.getName()+" ["+me.getId()+"] - lastVersion = "+lastVersion.getVersionID() + "("+tag+", "+description+")"); - } - - // So, we set the tag and description fields of the latest version. - if (tag != null || description != null) - { - lastVersion.setTag(tag); - lastVersion.setDescription(description); - - AVMDAOs.Instance().fVersionRootDAO.update(lastVersion); - } - snapShotMap.put(getName(), lastVersion.getVersionID()); - - if (logger.isTraceEnabled()) - { - logger.trace("createSnapshot: no snapshot required: "+me.getName()+(tag != null ? "("+tag+")" : "")+" [lastVersion = "+lastVersion.getVersionID()+"]"); - } - - return snapShotMap; - } - if (logger.isTraceEnabled()) - { - logger.trace("createSnapshot: snapshot: "+me.getName()+" ["+me.getId()+"] - lastVersion="+lastVersion.getVersionID()+", layeredEntries="+layeredEntries.size()); - } - - snapShotMap.put(getName(), me.getNextVersionID()); - // Force copies on all the layered nodes from last snapshot. - for (VersionLayeredNodeEntry entry : layeredEntries) - { - String[] pathParts = AVMUtil.splitPath(entry.getPath()); - Lookup lookup = me.lookup(-1, pathParts[1], false, false); - if (lookup == null) - { - continue; - } - if (lookup.getCurrentNode().getType() != AVMNodeType.LAYERED_DIRECTORY && - lookup.getCurrentNode().getType() != AVMNodeType.LAYERED_FILE) - { - continue; - } - if (lookup.getCurrentNode().getIsNew()) - { - continue; - } - - if (lookup.getCurrentNode().getType() == AVMNodeType.LAYERED_DIRECTORY) - { - fAVMRepository.forceCopy(entry.getPath()); - me = (AVMStoreImpl)AVMDAOs.Instance().fAVMStoreDAO.getByID(getId()); - } - else if (lookup.getCurrentNode().getType() == AVMNodeType.LAYERED_FILE) - { - String parentName[] = AVMUtil.splitBase(entry.getPath()); - AVMNode child = lookup.getCurrentNode(); - DirectoryNode parent = lookup.getCurrentNodeDirectory(); - - AVMNode newChild = ((LayeredFileNode)child).copyLiterally(lookup); - newChild.setAncestor(child); - parent.putChild(parentName[1], newChild); - } - } - - if (logger.isTraceEnabled()) - { - logger.trace("createSnapshot: force copy: "+me.getName()+(tag != null ? "("+tag+")" : "")+" [lastVersion="+lastVersion.getVersionID()+", layeredEntriesCnt="+layeredEntries.size()+"] in " + (System.currentTimeMillis() - start) + " msecs"); - } - - // Clear out the new nodes. - List allLayeredNodeIDs = AVMDAOs.Instance().fAVMNodeDAO.getNewLayeredInStoreIDs(me); - - AVMDAOs.Instance().fAVMNodeDAO.clearNewInStore(me); - - AVMDAOs.Instance().fAVMNodeDAO.clear(); - List layeredNodeIDs = new ArrayList(); - for (Long layeredID : allLayeredNodeIDs) - { - Layered layered = (Layered)AVMDAOs.Instance().fAVMNodeDAO.getByID(layeredID); - - String indirection = null; - if (layered != null) - { - indirection = layered.getIndirection(); - } - - if (indirection == null) - { - continue; - } - layeredNodeIDs.add(layeredID); - String storeName = AVMUtil.getStoreName(indirection); - if (!snapShotMap.containsKey(storeName)) - { - AVMStore store = AVMDAOs.Instance().fAVMStoreDAO.getByName(storeName); - if (store == null) - { - layered.setIndirectionVersion(-1); - } - else - { - store.createSnapshot(null, null, snapShotMap); - layered = (Layered)AVMDAOs.Instance().fAVMNodeDAO.getByID(layeredID); - layered.setIndirectionVersion(snapShotMap.get(storeName)); - } - } - else - { - layered.setIndirectionVersion(snapShotMap.get(storeName)); - } - - AVMDAOs.Instance().fAVMNodeDAO.update(layered); - } - - // Make up a new version record. - String user = RawServices.Instance().getAuthenticationContext().getCurrentUserName(); - if (user == null) - { - user = RawServices.Instance().getAuthenticationContext().getSystemUserName(); - } - - me = (AVMStoreImpl)AVMDAOs.Instance().fAVMStoreDAO.getByID(getId()); - VersionRoot versionRoot = new VersionRootImpl(me, - me.getRoot(), - me.getNextVersionID(), - System.currentTimeMillis(), - user, - tag, - description); - - me.setNextVersionID(me.getNextVersionID()+1); - - AVMDAOs.Instance().fAVMStoreDAO.update(me); - +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.GUID; +import org.alfresco.util.Pair; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * A Repository contains a current root directory and a list of + * root versions. Each root version corresponds to a separate snapshot + * operation. + * @author britt + */ +public class AVMStoreImpl implements AVMStore +{ + private static Log logger = LogFactory.getLog(AVMStoreImpl.class); + /** + * The primary key. + */ + private long fID; + + /** + * The name of this AVMStore. + */ + private String fName; + + /** + * The current root directory. + */ + private DirectoryNode fRoot; + + /** + * The next version id. + */ + private int fNextVersionID; + + /** + * The version (for concurrency control). + */ + private long fVers; + + /** + * Acl for this store. + */ + private DbAccessControlList fACL; + + /** + * The AVMRepository. + */ + transient private AVMRepository fAVMRepository; + + /** + * Default constructor. + */ + public AVMStoreImpl() + { + fAVMRepository = AVMRepository.GetInstance(); + } + + /** + * Make a brand new AVMStore. + * @param repo The AVMRepository. + * @param name The name of the AVMStore. + */ + public AVMStoreImpl(AVMRepository repo, String name) + { + // Make ourselves up and save. + fAVMRepository = repo; + + setName(name); + setNextVersionID(0); + setRoot(null); + + AVMDAOs.Instance().fAVMStoreDAO.save(this); + + String creator = RawServices.Instance().getAuthenticationContext().getCurrentUserName(); + if (creator == null) + { + creator = RawServices.Instance().getAuthenticationContext().getSystemUserName(); + } + setProperty(ContentModel.PROP_CREATOR, new PropertyValue(null, creator)); + setProperty(ContentModel.PROP_CREATED, new PropertyValue(null, new Date(System.currentTimeMillis()))); + + // Make up the initial version record and save. + long time = System.currentTimeMillis(); + + PlainDirectoryNode dir = new PlainDirectoryNodeImpl(this); + dir.setIsRoot(true); + AVMDAOs.Instance().fAVMNodeDAO.save(dir); + + setRoot(dir); + + VersionRoot versionRoot = new VersionRootImpl(this, + getRoot(), + getNextVersionID(), + time, + creator, + AVMUtil.INITIAL_SNAPSHOT, + AVMUtil.INITIAL_SNAPSHOT); + setNextVersionID(getNextVersionID()+1); + + AVMDAOs.Instance().fAVMStoreDAO.update(this); AVMDAOs.Instance().fVersionRootDAO.save(versionRoot); - - int vlneCnt = 0; - - for (Long nodeID : layeredNodeIDs) - { - AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(nodeID); - List paths = fAVMRepository.getVersionPaths(versionRoot, node); - for (String path : paths) - { - VersionLayeredNodeEntry entry = - new VersionLayeredNodeEntryImpl(versionRoot, path); - AVMDAOs.Instance().fVersionLayeredNodeEntryDAO.save(entry); - } - - vlneCnt = vlneCnt+paths.size(); - } - - if (logger.isDebugEnabled()) - { - logger.debug("Raw snapshot: "+me.getName()+(tag != null ? "("+tag+")" : "")+" [versionRootId="+versionRoot.getId()+", layeredNodeIDsCnt="+layeredNodeIDs.size()+", versionLayeredNodeEntriesCnt="+vlneCnt+"] in " + (System.currentTimeMillis() - start) + " msecs"); - } - - return snapShotMap; - } - - /** - * Create a new directory. - * @param path The path to the containing directory. - * @param name The name of the new directory. - */ - public void createDirectory(String path, String name, List aspects, Map properties) - { - Lookup lPath = lookupDirectory(-1, path, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (!fAVMRepository.can(this, dir, PermissionService.ADD_CHILDREN, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write: " + path); - } - Pair temp = dir.lookupChild(lPath, name, true); - AVMNode child = (temp == null) ? null : temp.getFirst(); - if (child != null && child.getType() != AVMNodeType.DELETED_NODE) - { - throw new AVMExistsException("Child exists: " + name); - } - DirectoryNode newDir = null; - if (lPath.isLayered()) // Creating a directory in a layered context creates - // a LayeredDirectoryNode that gets its indirection from - // its parent. - { - // TODO - collapse save/update - newDir = new LayeredDirectoryNodeImpl((String)null, this, null, null, ACLCopyMode.INHERIT); - ((LayeredDirectoryNodeImpl)newDir).setPrimaryIndirection(false); - ((LayeredDirectoryNodeImpl)newDir).setLayerID(lPath.getTopLayer().getLayerID()); - - DbAccessControlList acl = dir.getAcl(); - newDir.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null); - - AVMDAOs.Instance().fAVMNodeDAO.update(newDir); - } - else - { - newDir = new PlainDirectoryNodeImpl(this); - - DbAccessControlList acl = dir.getAcl(); - newDir.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null); - - AVMDAOs.Instance().fAVMNodeDAO.save(newDir); - } - - // newDir.setVersionID(getNextVersionID()); - if (child != null) - { - newDir.setAncestor(child); - } - //dir.updateModTime(); - dir.putChild(name, newDir); - if (aspects != null) - { - Set aspectQNames = new HashSet(newDir.getAspects()); - aspectQNames.addAll(aspects); - ((DirectoryNodeImpl)newDir).setAspects(aspectQNames); - } - if (properties != null) - { - Map props = new HashMap(newDir.getProperties()); - props.putAll(properties); - ((DirectoryNodeImpl)newDir).setProperties(props); - } - } - - /** - * Create a new layered directory. - * @param srcPath The target indirection for a layered node. - * @param dstPath The containing directory for the new node. - * @param name The name of the new node. - */ - public void createLayeredDirectory(String srcPath, String dstPath, - String name) - { - Lookup lPath = lookupDirectory(-1, dstPath, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + dstPath + " not found."); - } - DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - Pair temp = dir.lookupChild(lPath, name, true); - AVMNode child = (temp == null) ? null : temp.getFirst(); - if (child != null && child.getType() != AVMNodeType.DELETED_NODE) - { - throw new AVMExistsException("Child exists: " + name); - } - Long parentAcl = dir.getAcl() == null ? null : dir.getAcl().getId(); - - LayeredDirectoryNode newDir = - new LayeredDirectoryNodeImpl(srcPath, this, null, parentAcl, ACLCopyMode.INHERIT); - - if (lPath.isLayered()) - { - // When a layered directory is made inside of a layered context, - // it gets its layer id from the topmost layer in its lookup - // path. - LayeredDirectoryNode top = lPath.getTopLayer(); - newDir.setLayerID(top.getLayerID()); - } - else - { - // Otherwise we issue a brand new layer id. - - // note: re-use generated node id as a layer id - newDir.setLayerID(newDir.getId()); - } - - AVMDAOs.Instance().fAVMNodeDAO.update(newDir); - - if (child != null) - { - newDir.setAncestor(child); - } - - // newDir.setVersionID(getNextVersionID()); - //dir.updateModTime(); - dir.putChild(name, newDir); - } - - /** - * Create a new file. - * @param path The path to the directory to contain the new file. - * @param name The name to give the new file. - * initial content. - */ - public OutputStream createFile(String path, String name) - { - return createFile(path, name, null, null).getContentOutputStream(); - } - - /** - * Create a file with the given contents. - * @param path The path to the containing directory. - * @param name The name to give the new file. - * @param data The contents. - */ - public void createFile(String path, String name, File data, List aspects, Map properties) - { - createFile(path, name, aspects, properties).putContent(data); - } - - private ContentWriter createFile(String path, String name, List aspects, Map properties) - { - Lookup lPath = lookupDirectory(-1, path, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (!fAVMRepository.can(this, dir, PermissionService.ADD_CHILDREN, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write: " + path); - } - Pair temp = dir.lookupChild(lPath, name, true); - AVMNode child = (temp == null) ? null : temp.getFirst(); - if (child != null && child.getType() != AVMNodeType.DELETED_NODE) - { - throw new AVMExistsException("Child exists: " + name); - } - - PlainFileNodeImpl file = new PlainFileNodeImpl(this); - - file.setContentData(new ContentData(null, - RawServices.Instance().getMimetypeService().guessMimetype(name), - -1, - "UTF-8")); - - DbAccessControlList acl = dir.getAcl(); - file.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null); - - AVMDAOs.Instance().fAVMNodeDAO.save(file); - - // file.setVersionID(getNextVersionID()); - //dir.updateModTime(); - dir.putChild(name, file); - if (child != null) - { - file.setAncestor(child); - } - - if (aspects != null) - { - Set aspectQNames = new HashSet(aspects.size()); - aspectQNames.addAll(aspects); - file.setAspects(aspectQNames); - } - if (properties != null) - { - Map props = new HashMap(properties.size()); - props.putAll(properties); - file.setProperties(props); - } - + } + + /** + * Set the primary key + * @param id The primary key. + */ + public void setId(long id) + { + fID = id; + } + + /** + * Get the primary key. + * @return The primary key. + */ + public long getId() + { + return fID; + } + + /** + * Set a new root for this. + * @param root + */ + public void setNewRoot(DirectoryNode root) + { + fRoot = root; + } + + /** + * Snapshot this store. This creates a new version record. + * @return The version id of the new snapshot. + */ + public Map createSnapshot(String tag, String description, Map snapShotMap) + { + long start = System.currentTimeMillis(); + + long rootID = getRoot().getId(); + AVMStoreImpl me = (AVMStoreImpl)AVMDAOs.Instance().fAVMStoreDAO.getByID(getId()); + VersionRoot lastVersion = AVMDAOs.Instance().fVersionRootDAO.getMaxVersion(me); + List layeredEntries = + AVMDAOs.Instance().fVersionLayeredNodeEntryDAO.get(lastVersion); + // Is there no need for a snapshot? + DirectoryNode root = (DirectoryNode)AVMDAOs.Instance().fAVMNodeDAO.getByID(rootID); + if (!root.getIsNew() && layeredEntries.size() == 0) + { + if (logger.isTraceEnabled()) + { + logger.trace("createSnapshot: no snapshot required: "+me.getName()+" ["+me.getId()+"] - lastVersion = "+lastVersion.getVersionID() + "("+tag+", "+description+")"); + } + + // So, we set the tag and description fields of the latest version. + if (tag != null || description != null) + { + lastVersion.setTag(tag); + lastVersion.setDescription(description); + + AVMDAOs.Instance().fVersionRootDAO.update(lastVersion); + } + snapShotMap.put(getName(), lastVersion.getVersionID()); + + if (logger.isTraceEnabled()) + { + logger.trace("createSnapshot: no snapshot required: "+me.getName()+(tag != null ? "("+tag+")" : "")+" [lastVersion = "+lastVersion.getVersionID()+"]"); + } + + return snapShotMap; + } + if (logger.isTraceEnabled()) + { + logger.trace("createSnapshot: snapshot: "+me.getName()+" ["+me.getId()+"] - lastVersion="+lastVersion.getVersionID()+", layeredEntries="+layeredEntries.size()); + } + + snapShotMap.put(getName(), me.getNextVersionID()); + // Force copies on all the layered nodes from last snapshot. + for (VersionLayeredNodeEntry entry : layeredEntries) + { + String[] pathParts = AVMUtil.splitPath(entry.getPath()); + Lookup lookup = me.lookup(-1, pathParts[1], false, false); + if (lookup == null) + { + continue; + } + if (lookup.getCurrentNode().getType() != AVMNodeType.LAYERED_DIRECTORY && + lookup.getCurrentNode().getType() != AVMNodeType.LAYERED_FILE) + { + continue; + } + if (lookup.getCurrentNode().getIsNew()) + { + continue; + } + + if (lookup.getCurrentNode().getType() == AVMNodeType.LAYERED_DIRECTORY) + { + fAVMRepository.forceCopy(entry.getPath()); + me = (AVMStoreImpl)AVMDAOs.Instance().fAVMStoreDAO.getByID(getId()); + } + else if (lookup.getCurrentNode().getType() == AVMNodeType.LAYERED_FILE) + { + String parentName[] = AVMUtil.splitBase(entry.getPath()); + AVMNode child = lookup.getCurrentNode(); + DirectoryNode parent = lookup.getCurrentNodeDirectory(); + + AVMNode newChild = ((LayeredFileNode)child).copyLiterally(lookup); + newChild.setAncestor(child); + parent.putChild(parentName[1], newChild); + } + } + + if (logger.isTraceEnabled()) + { + logger.trace("createSnapshot: force copy: "+me.getName()+(tag != null ? "("+tag+")" : "")+" [lastVersion="+lastVersion.getVersionID()+", layeredEntriesCnt="+layeredEntries.size()+"] in " + (System.currentTimeMillis() - start) + " msecs"); + } + + // Clear out the new nodes. + List allLayeredNodeIDs = AVMDAOs.Instance().fAVMNodeDAO.getNewLayeredInStoreIDs(me); + + AVMDAOs.Instance().fAVMNodeDAO.clearNewInStore(me); + + AVMDAOs.Instance().fAVMNodeDAO.clear(); + List layeredNodeIDs = new ArrayList(); + for (Long layeredID : allLayeredNodeIDs) + { + Layered layered = (Layered)AVMDAOs.Instance().fAVMNodeDAO.getByID(layeredID); + + String indirection = null; + if (layered != null) + { + indirection = layered.getIndirection(); + } + + if (indirection == null) + { + continue; + } + layeredNodeIDs.add(layeredID); + String storeName = AVMUtil.getStoreName(indirection); + if (!snapShotMap.containsKey(storeName)) + { + AVMStore store = AVMDAOs.Instance().fAVMStoreDAO.getByName(storeName); + if (store == null) + { + layered.setIndirectionVersion(-1); + } + else + { + store.createSnapshot(null, null, snapShotMap); + layered = (Layered)AVMDAOs.Instance().fAVMNodeDAO.getByID(layeredID); + layered.setIndirectionVersion(snapShotMap.get(storeName)); + } + } + else + { + layered.setIndirectionVersion(snapShotMap.get(storeName)); + } + + AVMDAOs.Instance().fAVMNodeDAO.update(layered); + } + + // Make up a new version record. + String user = RawServices.Instance().getAuthenticationContext().getCurrentUserName(); + if (user == null) + { + user = RawServices.Instance().getAuthenticationContext().getSystemUserName(); + } + + me = (AVMStoreImpl)AVMDAOs.Instance().fAVMStoreDAO.getByID(getId()); + VersionRoot versionRoot = new VersionRootImpl(me, + me.getRoot(), + me.getNextVersionID(), + System.currentTimeMillis(), + user, + tag, + description); + + me.setNextVersionID(me.getNextVersionID()+1); + + AVMDAOs.Instance().fAVMStoreDAO.update(me); + + AVMDAOs.Instance().fVersionRootDAO.save(versionRoot); + + int vlneCnt = 0; + + for (Long nodeID : layeredNodeIDs) + { + AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(nodeID); + List paths = fAVMRepository.getVersionPaths(versionRoot, node); + for (String path : paths) + { + VersionLayeredNodeEntry entry = + new VersionLayeredNodeEntryImpl(versionRoot, path); + AVMDAOs.Instance().fVersionLayeredNodeEntryDAO.save(entry); + } + + vlneCnt = vlneCnt+paths.size(); + } + + if (logger.isDebugEnabled()) + { + logger.debug("Raw snapshot: "+me.getName()+(tag != null ? "("+tag+")" : "")+" [versionRootId="+versionRoot.getId()+", layeredNodeIDsCnt="+layeredNodeIDs.size()+", versionLayeredNodeEntriesCnt="+vlneCnt+"] in " + (System.currentTimeMillis() - start) + " msecs"); + } + + return snapShotMap; + } + + /** + * Create a new directory. + * @param path The path to the containing directory. + * @param name The name of the new directory. + */ + public void createDirectory(String path, String name, List aspects, Map properties) + { + Lookup lPath = lookupDirectory(-1, path, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); + if (!fAVMRepository.can(this, dir, PermissionService.ADD_CHILDREN, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write: " + path); + } + Pair temp = dir.lookupChild(lPath, name, true); + AVMNode child = (temp == null) ? null : temp.getFirst(); + if (child != null && child.getType() != AVMNodeType.DELETED_NODE) + { + throw new AVMExistsException("Child exists: " + name); + } + DirectoryNode newDir = null; + if (lPath.isLayered()) // Creating a directory in a layered context creates + // a LayeredDirectoryNode that gets its indirection from + // its parent. + { + // TODO - collapse save/update + newDir = new LayeredDirectoryNodeImpl((String)null, this, null, null, ACLCopyMode.INHERIT); + ((LayeredDirectoryNodeImpl)newDir).setPrimaryIndirection(false); + ((LayeredDirectoryNodeImpl)newDir).setLayerID(lPath.getTopLayer().getLayerID()); + + newDir.copyACLs(dir, ACLCopyMode.INHERIT); + + AVMDAOs.Instance().fAVMNodeDAO.update(newDir); + } + else + { + newDir = new PlainDirectoryNodeImpl(this); + + newDir.copyACLs(dir, ACLCopyMode.INHERIT); + + AVMDAOs.Instance().fAVMNodeDAO.save(newDir); + } + + // newDir.setVersionID(getNextVersionID()); + if (child != null) + { + newDir.setAncestor(child); + } + //dir.updateModTime(); + dir.putChild(name, newDir); + if (aspects != null) + { + Set aspectQNames = new HashSet(newDir.getAspects()); + aspectQNames.addAll(aspects); + ((DirectoryNodeImpl)newDir).setAspects(aspectQNames); + } + if (properties != null) + { + Map props = new HashMap(newDir.getProperties()); + props.putAll(properties); + ((DirectoryNodeImpl)newDir).setProperties(props); + } + } + + /** + * Create a new layered directory. + * @param srcPath The target indirection for a layered node. + * @param dstPath The containing directory for the new node. + * @param name The name of the new node. + */ + public void createLayeredDirectory(String srcPath, String dstPath, + String name) + { + Lookup lPath = lookupDirectory(-1, dstPath, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + dstPath + " not found."); + } + DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); + Pair temp = dir.lookupChild(lPath, name, true); + AVMNode child = (temp == null) ? null : temp.getFirst(); + if (child != null && child.getType() != AVMNodeType.DELETED_NODE) + { + throw new AVMExistsException("Child exists: " + name); + } + Long parentAcl = dir.getAcl() == null ? null : dir.getAcl().getId(); + + LayeredDirectoryNode newDir = + new LayeredDirectoryNodeImpl(srcPath, this, null, parentAcl, ACLCopyMode.INHERIT); + + if (lPath.isLayered()) + { + // When a layered directory is made inside of a layered context, + // it gets its layer id from the topmost layer in its lookup + // path. + LayeredDirectoryNode top = lPath.getTopLayer(); + newDir.setLayerID(top.getLayerID()); + } + else + { + // Otherwise we issue a brand new layer id. + + // note: re-use generated node id as a layer id + newDir.setLayerID(newDir.getId()); + } + + AVMDAOs.Instance().fAVMNodeDAO.update(newDir); + + if (child != null) + { + newDir.setAncestor(child); + } + + // newDir.setVersionID(getNextVersionID()); + //dir.updateModTime(); + dir.putChild(name, newDir); + } + + /** + * Create a new file. + * @param path The path to the directory to contain the new file. + * @param name The name to give the new file. + * initial content. + */ + public OutputStream createFile(String path, String name) + { + return createFile(path, name, null, null).getContentOutputStream(); + } + + /** + * Create a file with the given contents. + * @param path The path to the containing directory. + * @param name The name to give the new file. + * @param data The contents. + */ + public void createFile(String path, String name, File data, List aspects, Map properties) + { + createFile(path, name, aspects, properties).putContent(data); + } + + private ContentWriter createFile(String path, String name, List aspects, Map properties) + { + Lookup lPath = lookupDirectory(-1, path, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); + if (!fAVMRepository.can(this, dir, PermissionService.ADD_CHILDREN, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write: " + path); + } + Pair temp = dir.lookupChild(lPath, name, true); + AVMNode child = (temp == null) ? null : temp.getFirst(); + if (child != null && child.getType() != AVMNodeType.DELETED_NODE) + { + throw new AVMExistsException("Child exists: " + name); + } + + PlainFileNodeImpl file = new PlainFileNodeImpl(this); + + file.setContentData(new ContentData(null, + RawServices.Instance().getMimetypeService().guessMimetype(name), + -1, + "UTF-8")); + + file.copyACLs(dir, ACLCopyMode.INHERIT); + + AVMDAOs.Instance().fAVMNodeDAO.save(file); + + // file.setVersionID(getNextVersionID()); + //dir.updateModTime(); + dir.putChild(name, file); + if (child != null) + { + file.setAncestor(child); + } + + if (aspects != null) + { + Set aspectQNames = new HashSet(aspects.size()); + aspectQNames.addAll(aspects); + file.setAspects(aspectQNames); + } + if (properties != null) + { + Map props = new HashMap(properties.size()); + props.putAll(properties); + file.setProperties(props); + } + return createContentWriter(AVMNodeConverter.ExtendAVMPath(path, name), true); - } - - /** - * Create a new layered file. - * @param srcPath The target indirection for the layered file. - * @param dstPath The path to the directory to contain the new file. - * @param name The name of the new file. - */ - public void createLayeredFile(String srcPath, String dstPath, String name) - { - Lookup lPath = lookupDirectory(-1, dstPath, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + dstPath + " not found."); - } - DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (!fAVMRepository.can(this, dir, PermissionService.ADD_CHILDREN, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write: " + dstPath); - } - Pair temp = dir.lookupChild(lPath, name, true); - AVMNode child = (temp == null) ? null : temp.getFirst(); - if (child != null && child.getType() != AVMNodeType.DELETED_NODE) - { - throw new AVMExistsException("Child exists: " + name); - } - // TODO Reexamine decision to not check validity of srcPath. Warning for now. - String[] srcPathParts = srcPath.split(":"); - String[] dstPathParts = dstPath.split(":"); - - Lookup lPathSrc = null; - if (srcPathParts[0].equals(dstPathParts[0])) - { - lPathSrc = lookup(-1, srcPathParts[1], false, false); - } - else - { - AVMStore srcStore = AVMDAOs.Instance().fAVMStoreDAO.getByName(srcPathParts[0]); - if (srcStore != null) - { - lPathSrc = srcStore.lookup(-1, srcPathParts[1], false, false); - } - } - - AVMNode srcNode = null; - if (lPathSrc == null) - { - logger.warn("CreateLayeredFile: srcPath not found: "+srcPath); - } - else - { - srcNode = (AVMNode)lPathSrc.getCurrentNode(); - if (! (srcNode instanceof FileNode)) - { - logger.warn("CreateLayeredFile: srcPath is not a file: "+srcPath); - } - } - - LayeredFileNodeImpl newFile = - new LayeredFileNodeImpl(srcPath, this, null); - - DbAccessControlList acl = dir.getAcl(); - newFile.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null); - - AVMDAOs.Instance().fAVMNodeDAO.save(newFile); - - if (child != null) - { - newFile.setAncestor(child); - } - else - { - if ((srcNode != null) && (srcNode instanceof FileNode)) - { - newFile.setAncestor((FileNode)srcNode); - } - } - - // newFile.setVersionID(getNextVersionID()); - //dir.updateModTime(); - dir.putChild(name, newFile); - } - - /** - * Get an input stream from a file. - * @param version The version id to look under. - * @param path The path to the file. - * @return An InputStream. - */ - public InputStream getInputStream(int version, String path) - { - ContentReader reader = getContentReader(version, path); - if (reader == null) - { - // TODO This is wrong, wrong, wrong. Do something about it - // sooner rather than later. - throw new AVMNotFoundException(path + " has no content."); - } - return reader.getContentInputStream(); - } - - /** - * Get a ContentReader from a file. - * @param version The version to look under. - * @param path The path to the file. - * @return A ContentReader. - */ - public ContentReader getContentReader(int version, String path) - { + } + + /** + * Create a new layered file. + * @param srcPath The target indirection for the layered file. + * @param dstPath The path to the directory to contain the new file. + * @param name The name of the new file. + */ + public void createLayeredFile(String srcPath, String dstPath, String name) + { + Lookup lPath = lookupDirectory(-1, dstPath, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + dstPath + " not found."); + } + DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); + if (!fAVMRepository.can(this, dir, PermissionService.ADD_CHILDREN, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write: " + dstPath); + } + Pair temp = dir.lookupChild(lPath, name, true); + AVMNode child = (temp == null) ? null : temp.getFirst(); + if (child != null && child.getType() != AVMNodeType.DELETED_NODE) + { + throw new AVMExistsException("Child exists: " + name); + } + // TODO Reexamine decision to not check validity of srcPath. Warning for now. + String[] srcPathParts = srcPath.split(":"); + String[] dstPathParts = dstPath.split(":"); + + Lookup lPathSrc = null; + if (srcPathParts[0].equals(dstPathParts[0])) + { + lPathSrc = lookup(-1, srcPathParts[1], false, false); + } + else + { + AVMStore srcStore = AVMDAOs.Instance().fAVMStoreDAO.getByName(srcPathParts[0]); + if (srcStore != null) + { + lPathSrc = srcStore.lookup(-1, srcPathParts[1], false, false); + } + } + + AVMNode srcNode = null; + if (lPathSrc == null) + { + logger.warn("CreateLayeredFile: srcPath not found: "+srcPath); + } + else + { + srcNode = (AVMNode)lPathSrc.getCurrentNode(); + if (! (srcNode instanceof FileNode)) + { + logger.warn("CreateLayeredFile: srcPath is not a file: "+srcPath); + } + } + + LayeredFileNodeImpl newFile = + new LayeredFileNodeImpl(srcPath, this, null); + + newFile.copyACLs(dir, ACLCopyMode.INHERIT); + + AVMDAOs.Instance().fAVMNodeDAO.save(newFile); + + if (child != null) + { + newFile.setAncestor(child); + } + else + { + if ((srcNode != null) && (srcNode instanceof FileNode)) + { + newFile.setAncestor((FileNode)srcNode); + } + } + + // newFile.setVersionID(getNextVersionID()); + //dir.updateModTime(); + dir.putChild(name, newFile); + } + + /** + * Get an input stream from a file. + * @param version The version id to look under. + * @param path The path to the file. + * @return An InputStream. + */ + public InputStream getInputStream(int version, String path) + { + ContentReader reader = getContentReader(version, path); + if (reader == null) + { + // TODO This is wrong, wrong, wrong. Do something about it + // sooner rather than later. + throw new AVMNotFoundException(path + " has no content."); + } + return reader.getContentInputStream(); + } + + /** + * Get a ContentReader from a file. + * @param version The version to look under. + * @param path The path to the file. + * @return A ContentReader. + */ + public ContentReader getContentReader(int version, String path) + { try { NodeRef nodeRef = AVMNodeConverter.ToNodeRef(version, getName() + ":" + path); @@ -682,18 +678,18 @@ public class AVMStoreImpl implements AVMStore { throw new AVMNotFoundException("Path " + path + " not found."); } - } - - /** - * Get a ContentWriter to a file. - * @param path The path to the file. - * @return A ContentWriter. + } + + /** + * Get a ContentWriter to a file. + * @param path The path to the file. + * @return A ContentWriter. * @param update true if the property must be updated atomically when the content write * stream is closed (attaches a listener to the stream); false if the client code * will perform the updates itself. - */ + */ public ContentWriter createContentWriter(String path, boolean update) - { + { try { NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, getName() + ":" + path); @@ -705,1313 +701,1313 @@ public class AVMStoreImpl implements AVMStore { throw new AVMNotFoundException("Path " + path + " not found."); } - } - - /** - * Get a listing from a directory. - * @param version The version to look under. - * @param path The path to the directory. - * @return A List of FolderEntries. - */ - public SortedMap getListing(int version, String path, - boolean includeDeleted) - { - Lookup lPath = lookupDirectory(version, path, false); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (!fAVMRepository.can(this, dir, PermissionService.READ_CHILDREN, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to read: " + path); - } - Map listing = dir.getListing(lPath, includeDeleted); - return translateListing(listing, lPath); - } - - /** - * Get the list of nodes directly contained in a directory. - * @param version The version to look under. - * @param path The path to the directory. - * @return A Map of names to descriptors. - */ - public SortedMap getListingDirect(int version, String path, - boolean includeDeleted) - { - Lookup lPath = lookupDirectory(version, path, false); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (!fAVMRepository.can(this, dir, PermissionService.READ_CHILDREN, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to read: " + path); - } - if (lPath.isLayered() && dir.getType() != AVMNodeType.LAYERED_DIRECTORY) - { - return new TreeMap(); - } - Map listing = dir.getListingDirect(lPath, includeDeleted); - return translateListing(listing, lPath); - } - - /** - * Helper to convert an internal representation of a directory listing - * to an external representation. - * @param listing The internal listing, a Map of names to nodes. - * @param lPath The Lookup for the directory. - * @return A Map of names to descriptors. - */ - private SortedMap - translateListing(Map listing, Lookup lPath) - { - SortedMap results = new TreeMap(String.CASE_INSENSITIVE_ORDER); - for (String name : listing.keySet()) - { - // TODO consider doing this at a lower level. - AVMNode child = listing.get(name); - AVMNodeDescriptor desc = child.getDescriptor(lPath, name); - results.put(name, desc); - } - return results; - } - - /** - * Get the names of the deleted nodes in a directory. - * @param version The version to look under. - * @param path The path to the directory. - * @return A List of names. - */ - public List getDeleted(int version, String path) - { - Lookup lPath = lookupDirectory(version, path, false); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (!fAVMRepository.can(this, dir, PermissionService.READ_CHILDREN, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to read: " + path); - } - List deleted = dir.getDeletedNames(); - return deleted; - } - - /** - * Get an output stream to a file. - * @param path The path to the file. - * @return An OutputStream. - */ - public OutputStream getOutputStream(String path) - { + } + + /** + * Get a listing from a directory. + * @param version The version to look under. + * @param path The path to the directory. + * @return A List of FolderEntries. + */ + public SortedMap getListing(int version, String path, + boolean includeDeleted) + { + Lookup lPath = lookupDirectory(version, path, false); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); + if (!fAVMRepository.can(this, dir, PermissionService.READ_CHILDREN, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to read: " + path); + } + Map listing = dir.getListing(lPath, includeDeleted); + return translateListing(listing, lPath); + } + + /** + * Get the list of nodes directly contained in a directory. + * @param version The version to look under. + * @param path The path to the directory. + * @return A Map of names to descriptors. + */ + public SortedMap getListingDirect(int version, String path, + boolean includeDeleted) + { + Lookup lPath = lookupDirectory(version, path, false); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); + if (!fAVMRepository.can(this, dir, PermissionService.READ_CHILDREN, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to read: " + path); + } + if (lPath.isLayered() && dir.getType() != AVMNodeType.LAYERED_DIRECTORY) + { + return new TreeMap(); + } + Map listing = dir.getListingDirect(lPath, includeDeleted); + return translateListing(listing, lPath); + } + + /** + * Helper to convert an internal representation of a directory listing + * to an external representation. + * @param listing The internal listing, a Map of names to nodes. + * @param lPath The Lookup for the directory. + * @return A Map of names to descriptors. + */ + private SortedMap + translateListing(Map listing, Lookup lPath) + { + SortedMap results = new TreeMap(String.CASE_INSENSITIVE_ORDER); + for (String name : listing.keySet()) + { + // TODO consider doing this at a lower level. + AVMNode child = listing.get(name); + AVMNodeDescriptor desc = child.getDescriptor(lPath, name); + results.put(name, desc); + } + return results; + } + + /** + * Get the names of the deleted nodes in a directory. + * @param version The version to look under. + * @param path The path to the directory. + * @return A List of names. + */ + public List getDeleted(int version, String path) + { + Lookup lPath = lookupDirectory(version, path, false); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); + if (!fAVMRepository.can(this, dir, PermissionService.READ_CHILDREN, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to read: " + path); + } + List deleted = dir.getDeletedNames(); + return deleted; + } + + /** + * Get an output stream to a file. + * @param path The path to the file. + * @return An OutputStream. + */ + public OutputStream getOutputStream(String path) + { ContentWriter writer = createContentWriter(path, true); - return writer.getContentOutputStream(); - } - - /** - * Remove a node and everything underneath it. - * @param path The path to the containing directory. - * @param name The name of the node to remove. - */ - public void removeNode(String path, String name) - { - Lookup lPath = lookupDirectory(-1, path, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - - DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - Pair temp = dir.lookupChild(lPath, name, false); - AVMNode child = (temp == null) ? null : temp.getFirst(); - if (child == null) - { - Lookup lPathToChild = lookup(-1, path+"/"+name, true, false); - if (lPathToChild != null) - { - // ETHREEOH-2297 - child = lPathToChild.getCurrentNode(); - } - if (child == null) - { - throw new AVMNotFoundException("Does not exist: " + name); - } - - dir = lPathToChild.getCurrentNodeDirectory(); - } - - if (!fAVMRepository.can(this, child, PermissionService.DELETE_NODE, false)) - { - throw new AVMNotFoundException("Not allowed to delete in store : " + getName() +" at " + path); - } - - dir.removeChild(lPath, name); - //dir.updateModTime(); - } - - /** - * Allow a name which has been deleted to be visible through that layer. - * @param dirPath The path to the containing directory. - * @param name The name to uncover. - */ - public void uncover(String dirPath, String name) - { - Lookup lPath = lookupDirectory(-1, dirPath, true); - if (lPath == null) - { - throw new AVMNotFoundException("Directory path " + dirPath + " not found."); - } - DirectoryNode node = (DirectoryNode)lPath.getCurrentNode(); - if (node.getType() != AVMNodeType.LAYERED_DIRECTORY) - { - throw new AVMWrongTypeException("Not a layered directory: " + dirPath); - } - Pair temp = node.lookupChild(lPath, name, true); - AVMNode child = (temp == null) ? null : temp.getFirst(); - if(child == null) - { - throw new AVMNotFoundException("No child to recover at "+dirPath+" called "+name); - } - if (!fAVMRepository.can(this, child, PermissionService.DELETE_NODE, false)) - { - throw new AccessDeniedException("Not allowed to uncover: " + dirPath + " -> "+name); - } - ((LayeredDirectoryNode)node).uncover(lPath, name); - node.updateModTime(); - - AVMDAOs.Instance().fAVMNodeDAO.update(node); - } - - /** - * Get the set of all extant versions for this AVMStore. - * @return A Set of version ids. - */ - public List getVersions() - { - List versions = AVMDAOs.Instance().fVersionRootDAO.getAllInAVMStore(this); - List descs = new ArrayList(); - for (VersionRoot vr : versions) - { - VersionDescriptor desc = - new VersionDescriptor(getName(), - vr.getVersionID(), - vr.getCreator(), - vr.getCreateDate(), - vr.getTag(), - vr.getDescription()); - descs.add(desc); - } - return descs; - } - - /** - * Get the versions between the given dates (inclusive). From or - * to may be null but not both. - * @param from The earliest date. - * @param to The latest date. - * @return The Set of matching version IDs. - */ - public List getVersions(Date from, Date to) - { - List versions = AVMDAOs.Instance().fVersionRootDAO.getByDates(this, from, to); - List descs = new ArrayList(); - for (VersionRoot vr : versions) - { - VersionDescriptor desc = - new VersionDescriptor(getName(), - vr.getVersionID(), - vr.getCreator(), - vr.getCreateDate(), - vr.getTag(), - vr.getDescription()); - descs.add(desc); - } - return descs; - } - - - - public List getVersionsTo(int version) - { - List versions = AVMDAOs.Instance().fVersionRootDAO.getByVersionsTo(this, version); - List descs = new ArrayList(); - for (VersionRoot vr : versions) - { - VersionDescriptor desc = - new VersionDescriptor(getName(), - vr.getVersionID(), - vr.getCreator(), - vr.getCreateDate(), - vr.getTag(), - vr.getDescription()); - descs.add(desc); - } - return descs; - } - - public List getVersionsFrom(int version) - { - List versions = AVMDAOs.Instance().fVersionRootDAO.getByVersionsFrom(this, version); - List descs = new ArrayList(); - for (VersionRoot vr : versions) - { - VersionDescriptor desc = - new VersionDescriptor(getName(), - vr.getVersionID(), - vr.getCreator(), - vr.getCreateDate(), - vr.getTag(), - vr.getDescription()); - descs.add(desc); - } - return descs; - } - - - - - public List getVersionsBetween(int startVersion, int endVersion) - { - List versions = AVMDAOs.Instance().fVersionRootDAO.getByVersionsBetween(this, startVersion, endVersion); - List descs = new ArrayList(); - for (VersionRoot vr : versions) - { - VersionDescriptor desc = - new VersionDescriptor(getName(), - vr.getVersionID(), - vr.getCreator(), - vr.getCreateDate(), - vr.getTag(), - vr.getDescription()); - descs.add(desc); - } - return descs; - } - - /** - * Get the AVMRepository. - * @return The AVMRepository - */ - public AVMRepository getAVMRepository() - { - return fAVMRepository; - } - - /** - * Lookup up a path. - * @param version The version to look in. - * @param path The path to look up. - * @param write Whether this is in the context of a write. - * @return A Lookup object. - */ - public Lookup lookup(int version, String path, boolean write, boolean includeDeleted) - { - SimplePath sPath = new SimplePath(path); - return RawServices.Instance().getLookupCache().lookup(this, version, sPath, write, includeDeleted); - } - - /** - * Get the root node descriptor. - * @param version The version to get. - * @return The descriptor. - */ - public AVMNodeDescriptor getRoot(int version) - { - AVMNode root = null; - if (version < 0) - { - root = getRoot(); - } - else - { - root = AVMDAOs.Instance().fAVMNodeDAO.getAVMStoreRoot(this, version); - } - if (!fAVMRepository.can(this, root, PermissionService.READ_CHILDREN, true)) - { - throw new AccessDeniedException("Not allowed to read: " + getName() + "@" + version); - } - return root.getDescriptor(getName() + ":", "", null, -1); - } - - /** - * Lookup a node and insist that it is a directory. - * @param version The version to look under. - * @param path The path to the directory. - * @param write Whether this is in a write context. - * @return A Lookup object. - */ - public Lookup lookupDirectory(int version, String path, boolean write) - { - // Just do a regular lookup and assert that the last element - // is a directory. - Lookup lPath = lookup(version, path, write, false); - if (lPath == null) - { - return null; - } - if (lPath.getCurrentNode().getType() != AVMNodeType.PLAIN_DIRECTORY && - lPath.getCurrentNode().getType() != AVMNodeType.LAYERED_DIRECTORY) - { - return null; - } - return lPath; - } - - /** - * Get the effective indirection path for a layered node. - * @param version The version to look under. - * @param path The path to the node. - * @return The effective indirection. - */ - public String getIndirectionPath(int version, String path) - { - Lookup lPath = lookup(version, path, false, false); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - if (!lPath.isLayered()) - { - return null; - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to read: " + path); - } - if (node.getType() == AVMNodeType.LAYERED_DIRECTORY) - { - LayeredDirectoryNode dir = (LayeredDirectoryNode)node; - return dir.getUnderlying(lPath); - } - else if (node.getType() == AVMNodeType.LAYERED_FILE) - { - LayeredFileNode file = (LayeredFileNode)node; - return file.getUnderlying(lPath); - } - return lPath.getIndirectionPath(); - } - - /** - * Make the indicated node a primary indirection. - * @param path The path to the node. - */ - public void makePrimary(String path) - { - Lookup lPath = lookupDirectory(-1, path, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (!lPath.isLayered()) - { - throw new AVMException("Not in a layered context: " + path); - } - if (!fAVMRepository.can(this, dir, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write: " + path); - } - dir.turnPrimary(lPath); - dir.updateModTime(); - - AVMDAOs.Instance().fAVMNodeDAO.update(dir); - } - - /** - * Change the indirection of a layered directory. - * @param path The path to the layered directory. - * @param target The target indirection to set. - */ - public void retargetLayeredDirectory(String path, String target) - { - Lookup lPath = lookupDirectory(-1, path, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (!lPath.isLayered()) - { - throw new AVMException("Not in a layered context: " + path); - } - if (!fAVMRepository.can(this, dir, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write: " + path); - } - dir.retarget(lPath, target); - dir.updateModTime(); - - AVMDAOs.Instance().fAVMNodeDAO.update(dir); - } - - /** - * Set the name of this AVMStore. - * @param name - */ - public void setName(String name) - { - fName = name; - } - - /** - * Get the name of this AVMStore. - * @return The name. - */ - public String getName() - { - return fName; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.AVMStore#getAcl() - */ - public DbAccessControlList getStoreAcl() - { - return fACL; - } - - public void setStoreAcl(DbAccessControlList acl) - { - fACL = acl; - } - - /** - * Set the next version id. - * @param nextVersionID - */ - public void setNextVersionID(int nextVersionID) - { - fNextVersionID = nextVersionID; - } - - /** - * Get the next version id. - * @return The next version id. - */ - public int getNextVersionID() - { - return fNextVersionID; - } - - /** - * This gets the last extant version id. - */ - public int getLastVersionID() - { - Integer lastVersionId = AVMDAOs.Instance().fVersionRootDAO.getMaxVersionID(this); - if (lastVersionId == null) - { - return 0; - } - else - { - return lastVersionId.intValue(); - } - } - - /** - * Set the root directory. - * @param root - */ - public void setRoot(DirectoryNode root) - { - fRoot = root; - } - - /** - * Get the root directory. - * @return The root directory. - */ - public DirectoryNode getRoot() - { - return fRoot; - } - - /** - * Set the version (for concurrency control). - * @param vers The version for optimistic locks. - */ - public void setVers(long vers) - { - fVers = vers; - } - - /** - * Get the version (for concurrency control). - * @return The version for optimistic locks. - */ - public long getVers() - { - return fVers; - } - - /** - * Equals override. - * @param obj - * @return Equality. - */ - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (!(obj instanceof AVMStore)) - { - return false; - } - return getId() == ((AVMStore)obj).getId(); - } - - /** - * Get a hash code. - * @return The hash code. - */ - @Override - public int hashCode() - { - return (int)getId(); - } - - /** - * Purge all nodes reachable only via this version and repository. - * @param version - */ - public void purgeVersion(int version) - { - if (version == 0) - { - throw new AVMBadArgumentException("Cannot purge initial version"); - } - VersionRoot vRoot = AVMDAOs.Instance().fVersionRootDAO.getByVersionID(this, version); - if (vRoot == null) - { - throw new AVMNotFoundException("Version not found."); - } - AVMDAOs.Instance().fVersionLayeredNodeEntryDAO.delete(vRoot); - AVMNode root = vRoot.getRoot(); - if (!fAVMRepository.can(null, root, PermissionService.DELETE_CHILDREN, true)) - { - throw new AccessDeniedException("Not allowed to purge: " + getName() + "@" + version); - } - root.setIsRoot(false); - AVMDAOs.Instance().fAVMNodeDAO.update(root); - AVMDAOs.Instance().fVersionRootDAO.delete(vRoot); - if (root.equals(getRoot())) - { - // We have to set a new current root. - vRoot = AVMDAOs.Instance().fVersionRootDAO.getMaxVersion(this); - setRoot(vRoot.getRoot()); - AVMDAOs.Instance().fAVMStoreDAO.update(this); - } - } - - // TODO permissions? - /** - * Get the descriptor for this. - * @return An AVMStoreDescriptor - */ - public AVMStoreDescriptor getDescriptor() - { - // Get the creator ensuring that nulls are not hit - PropertyValue creatorValue = getProperty(ContentModel.PROP_CREATOR); - String creator = (creatorValue == null ? AuthenticationUtil.SYSTEM_USER_NAME : (String) creatorValue.getValue(DataTypeDefinition.TEXT)); - creator = (creator == null ? AuthenticationUtil.SYSTEM_USER_NAME : creator); - // Get the created date ensuring that nulls are not hit - PropertyValue createdValue = getProperty(ContentModel.PROP_CREATED); - Date created = createdValue == null ? (new Date()) : (Date) createdValue.getValue(DataTypeDefinition.DATE); - created = (created == null) ? (new Date()) : created; + return writer.getContentOutputStream(); + } + + /** + * Remove a node and everything underneath it. + * @param path The path to the containing directory. + * @param name The name of the node to remove. + */ + public void removeNode(String path, String name) + { + Lookup lPath = lookupDirectory(-1, path, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + + DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); + Pair temp = dir.lookupChild(lPath, name, false); + AVMNode child = (temp == null) ? null : temp.getFirst(); + if (child == null) + { + Lookup lPathToChild = lookup(-1, path+"/"+name, true, false); + if (lPathToChild != null) + { + // ETHREEOH-2297 + child = lPathToChild.getCurrentNode(); + } + if (child == null) + { + throw new AVMNotFoundException("Does not exist: " + name); + } + + dir = lPathToChild.getCurrentNodeDirectory(); + } + + if (!fAVMRepository.can(this, child, PermissionService.DELETE_NODE, false)) + { + throw new AVMNotFoundException("Not allowed to delete in store : " + getName() +" at " + path); + } + + dir.removeChild(lPath, name); + //dir.updateModTime(); + } + + /** + * Allow a name which has been deleted to be visible through that layer. + * @param dirPath The path to the containing directory. + * @param name The name to uncover. + */ + public void uncover(String dirPath, String name) + { + Lookup lPath = lookupDirectory(-1, dirPath, true); + if (lPath == null) + { + throw new AVMNotFoundException("Directory path " + dirPath + " not found."); + } + DirectoryNode node = (DirectoryNode)lPath.getCurrentNode(); + if (node.getType() != AVMNodeType.LAYERED_DIRECTORY) + { + throw new AVMWrongTypeException("Not a layered directory: " + dirPath); + } + Pair temp = node.lookupChild(lPath, name, true); + AVMNode child = (temp == null) ? null : temp.getFirst(); + if(child == null) + { + throw new AVMNotFoundException("No child to recover at "+dirPath+" called "+name); + } + if (!fAVMRepository.can(this, child, PermissionService.DELETE_NODE, false)) + { + throw new AccessDeniedException("Not allowed to uncover: " + dirPath + " -> "+name); + } + ((LayeredDirectoryNode)node).uncover(lPath, name); + node.updateModTime(); + + AVMDAOs.Instance().fAVMNodeDAO.update(node); + } + + /** + * Get the set of all extant versions for this AVMStore. + * @return A Set of version ids. + */ + public List getVersions() + { + List versions = AVMDAOs.Instance().fVersionRootDAO.getAllInAVMStore(this); + List descs = new ArrayList(); + for (VersionRoot vr : versions) + { + VersionDescriptor desc = + new VersionDescriptor(getName(), + vr.getVersionID(), + vr.getCreator(), + vr.getCreateDate(), + vr.getTag(), + vr.getDescription()); + descs.add(desc); + } + return descs; + } + + /** + * Get the versions between the given dates (inclusive). From or + * to may be null but not both. + * @param from The earliest date. + * @param to The latest date. + * @return The Set of matching version IDs. + */ + public List getVersions(Date from, Date to) + { + List versions = AVMDAOs.Instance().fVersionRootDAO.getByDates(this, from, to); + List descs = new ArrayList(); + for (VersionRoot vr : versions) + { + VersionDescriptor desc = + new VersionDescriptor(getName(), + vr.getVersionID(), + vr.getCreator(), + vr.getCreateDate(), + vr.getTag(), + vr.getDescription()); + descs.add(desc); + } + return descs; + } + + + + public List getVersionsTo(int version) + { + List versions = AVMDAOs.Instance().fVersionRootDAO.getByVersionsTo(this, version); + List descs = new ArrayList(); + for (VersionRoot vr : versions) + { + VersionDescriptor desc = + new VersionDescriptor(getName(), + vr.getVersionID(), + vr.getCreator(), + vr.getCreateDate(), + vr.getTag(), + vr.getDescription()); + descs.add(desc); + } + return descs; + } + + public List getVersionsFrom(int version) + { + List versions = AVMDAOs.Instance().fVersionRootDAO.getByVersionsFrom(this, version); + List descs = new ArrayList(); + for (VersionRoot vr : versions) + { + VersionDescriptor desc = + new VersionDescriptor(getName(), + vr.getVersionID(), + vr.getCreator(), + vr.getCreateDate(), + vr.getTag(), + vr.getDescription()); + descs.add(desc); + } + return descs; + } + + + + + public List getVersionsBetween(int startVersion, int endVersion) + { + List versions = AVMDAOs.Instance().fVersionRootDAO.getByVersionsBetween(this, startVersion, endVersion); + List descs = new ArrayList(); + for (VersionRoot vr : versions) + { + VersionDescriptor desc = + new VersionDescriptor(getName(), + vr.getVersionID(), + vr.getCreator(), + vr.getCreateDate(), + vr.getTag(), + vr.getDescription()); + descs.add(desc); + } + return descs; + } + + /** + * Get the AVMRepository. + * @return The AVMRepository + */ + public AVMRepository getAVMRepository() + { + return fAVMRepository; + } + + /** + * Lookup up a path. + * @param version The version to look in. + * @param path The path to look up. + * @param write Whether this is in the context of a write. + * @return A Lookup object. + */ + public Lookup lookup(int version, String path, boolean write, boolean includeDeleted) + { + SimplePath sPath = new SimplePath(path); + return RawServices.Instance().getLookupCache().lookup(this, version, sPath, write, includeDeleted); + } + + /** + * Get the root node descriptor. + * @param version The version to get. + * @return The descriptor. + */ + public AVMNodeDescriptor getRoot(int version) + { + AVMNode root = null; + if (version < 0) + { + root = getRoot(); + } + else + { + root = AVMDAOs.Instance().fAVMNodeDAO.getAVMStoreRoot(this, version); + } + if (!fAVMRepository.can(this, root, PermissionService.READ_CHILDREN, true)) + { + throw new AccessDeniedException("Not allowed to read: " + getName() + "@" + version); + } + return root.getDescriptor(getName() + ":", "", null, -1); + } + + /** + * Lookup a node and insist that it is a directory. + * @param version The version to look under. + * @param path The path to the directory. + * @param write Whether this is in a write context. + * @return A Lookup object. + */ + public Lookup lookupDirectory(int version, String path, boolean write) + { + // Just do a regular lookup and assert that the last element + // is a directory. + Lookup lPath = lookup(version, path, write, false); + if (lPath == null) + { + return null; + } + if (lPath.getCurrentNode().getType() != AVMNodeType.PLAIN_DIRECTORY && + lPath.getCurrentNode().getType() != AVMNodeType.LAYERED_DIRECTORY) + { + return null; + } + return lPath; + } + + /** + * Get the effective indirection path for a layered node. + * @param version The version to look under. + * @param path The path to the node. + * @return The effective indirection. + */ + public String getIndirectionPath(int version, String path) + { + Lookup lPath = lookup(version, path, false, false); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + if (!lPath.isLayered()) + { + return null; + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to read: " + path); + } + if (node.getType() == AVMNodeType.LAYERED_DIRECTORY) + { + LayeredDirectoryNode dir = (LayeredDirectoryNode)node; + return dir.getUnderlying(lPath); + } + else if (node.getType() == AVMNodeType.LAYERED_FILE) + { + LayeredFileNode file = (LayeredFileNode)node; + return file.getUnderlying(lPath); + } + return lPath.getIndirectionPath(); + } + + /** + * Make the indicated node a primary indirection. + * @param path The path to the node. + */ + public void makePrimary(String path) + { + Lookup lPath = lookupDirectory(-1, path, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); + if (!lPath.isLayered()) + { + throw new AVMException("Not in a layered context: " + path); + } + if (!fAVMRepository.can(this, dir, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write: " + path); + } + dir.turnPrimary(lPath); + dir.updateModTime(); + + AVMDAOs.Instance().fAVMNodeDAO.update(dir); + } + + /** + * Change the indirection of a layered directory. + * @param path The path to the layered directory. + * @param target The target indirection to set. + */ + public void retargetLayeredDirectory(String path, String target) + { + Lookup lPath = lookupDirectory(-1, path, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); + if (!lPath.isLayered()) + { + throw new AVMException("Not in a layered context: " + path); + } + if (!fAVMRepository.can(this, dir, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write: " + path); + } + dir.retarget(lPath, target); + dir.updateModTime(); + + AVMDAOs.Instance().fAVMNodeDAO.update(dir); + } + + /** + * Set the name of this AVMStore. + * @param name + */ + public void setName(String name) + { + fName = name; + } + + /** + * Get the name of this AVMStore. + * @return The name. + */ + public String getName() + { + return fName; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.avm.AVMStore#getAcl() + */ + public DbAccessControlList getStoreAcl() + { + return fACL; + } + + public void setStoreAcl(DbAccessControlList acl) + { + fACL = acl; + } + + /** + * Set the next version id. + * @param nextVersionID + */ + public void setNextVersionID(int nextVersionID) + { + fNextVersionID = nextVersionID; + } + + /** + * Get the next version id. + * @return The next version id. + */ + public int getNextVersionID() + { + return fNextVersionID; + } + + /** + * This gets the last extant version id. + */ + public int getLastVersionID() + { + Integer lastVersionId = AVMDAOs.Instance().fVersionRootDAO.getMaxVersionID(this); + if (lastVersionId == null) + { + return 0; + } + else + { + return lastVersionId.intValue(); + } + } + + /** + * Set the root directory. + * @param root + */ + public void setRoot(DirectoryNode root) + { + fRoot = root; + } + + /** + * Get the root directory. + * @return The root directory. + */ + public DirectoryNode getRoot() + { + return fRoot; + } + + /** + * Set the version (for concurrency control). + * @param vers The version for optimistic locks. + */ + public void setVers(long vers) + { + fVers = vers; + } + + /** + * Get the version (for concurrency control). + * @return The version for optimistic locks. + */ + public long getVers() + { + return fVers; + } + + /** + * Equals override. + * @param obj + * @return Equality. + */ + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (!(obj instanceof AVMStore)) + { + return false; + } + return getId() == ((AVMStore)obj).getId(); + } + + /** + * Get a hash code. + * @return The hash code. + */ + @Override + public int hashCode() + { + return (int)getId(); + } + + /** + * Purge all nodes reachable only via this version and repository. + * @param version + */ + public void purgeVersion(int version) + { + if (version == 0) + { + throw new AVMBadArgumentException("Cannot purge initial version"); + } + VersionRoot vRoot = AVMDAOs.Instance().fVersionRootDAO.getByVersionID(this, version); + if (vRoot == null) + { + throw new AVMNotFoundException("Version not found."); + } + AVMDAOs.Instance().fVersionLayeredNodeEntryDAO.delete(vRoot); + AVMNode root = vRoot.getRoot(); + if (!fAVMRepository.can(null, root, PermissionService.DELETE_CHILDREN, true)) + { + throw new AccessDeniedException("Not allowed to purge: " + getName() + "@" + version); + } + root.setIsRoot(false); + AVMDAOs.Instance().fAVMNodeDAO.update(root); + AVMDAOs.Instance().fVersionRootDAO.delete(vRoot); + if (root.equals(getRoot())) + { + // We have to set a new current root. + vRoot = AVMDAOs.Instance().fVersionRootDAO.getMaxVersion(this); + setRoot(vRoot.getRoot()); + AVMDAOs.Instance().fAVMStoreDAO.update(this); + } + } + + // TODO permissions? + /** + * Get the descriptor for this. + * @return An AVMStoreDescriptor + */ + public AVMStoreDescriptor getDescriptor() + { + // Get the creator ensuring that nulls are not hit + PropertyValue creatorValue = getProperty(ContentModel.PROP_CREATOR); + String creator = (creatorValue == null ? AuthenticationUtil.SYSTEM_USER_NAME : (String) creatorValue.getValue(DataTypeDefinition.TEXT)); + creator = (creator == null ? AuthenticationUtil.SYSTEM_USER_NAME : creator); + // Get the created date ensuring that nulls are not hit + PropertyValue createdValue = getProperty(ContentModel.PROP_CREATED); + Date created = createdValue == null ? (new Date()) : (Date) createdValue.getValue(DataTypeDefinition.DATE); + created = (created == null) ? (new Date()) : created; return new AVMStoreDescriptor(getId(), getName(), creator, created.getTime()); - } - - /** - * Set the opacity of a layered directory. An opaque directory hides - * what is pointed at by its indirection. - * @param path The path to the layered directory. - * @param opacity True is opaque; false is not. - */ - public void setOpacity(String path, boolean opacity) - { - Lookup lPath = lookup(-1, path, true, false); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!(node instanceof LayeredDirectoryNode)) - { - throw new AVMWrongTypeException("Not a LayeredDirectoryNode."); - } - if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write: " + path); - } - ((LayeredDirectoryNode)node).setOpacity(opacity); - node.updateModTime(); - - AVMDAOs.Instance().fAVMNodeDAO.update(node); - } - - // TODO Does it make sense to set properties on DeletedNodes? - /** - * Set a property on a node. - * @param path The path to the node. - * @param name The name of the property. - * @param value The value to set. - */ - public void setNodeProperty(String path, QName name, PropertyValue value) - { - Lookup lPath = lookup(-1, path, true, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write: " + path); - } - - node.setProperty(name, value); - - node.setGuid(GUID.generate()); - - AVMDAOs.Instance().fAVMNodeDAO.update(node); // guid and property - } - - /** - * Set a collection of properties on a node. - * @param path The path to the node. - * @param properties The Map of QNames to PropertyValues. - */ - public void setNodeProperties(String path, Map properties) - { - Lookup lPath = lookup(-1, path, true, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write: " + path); - } - if (properties != null) - { - Map props = new HashMap(properties.size()); - props.putAll(properties); - node.addProperties(props); - } - node.setGuid(GUID.generate()); - - AVMDAOs.Instance().fAVMNodeDAO.update(node); - } - - /** - * Get a property by name. - * @param version The version to lookup. - * @param path The path to the node. - * @param name The name of the property. - * @return A PropertyValue or null if not found. - */ - public PropertyValue getNodeProperty(int version, String path, QName name) - { - Lookup lPath = lookup(version, path, false, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to read: " + path); - } - - return node.getProperty(name); - } - - /** - * Get all the properties associated with a node. - * @param version The version to lookup. - * @param path The path to the node. - * @return A Map of QNames to PropertyValues. - */ - public Map getNodeProperties(int version, String path) - { - Lookup lPath = lookup(version, path, false, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to read: " + path); - } - - return node.getProperties(); - } - - /** - * Delete a single property from a node. - * @param path The path to the node. - * @param name The name of the property. - */ - public void deleteNodeProperty(String path, QName name) - { - Lookup lPath = lookup(-1, path, true, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write: " + path); - } - node.setGuid(GUID.generate()); - - node.deleteProperty(name); - - AVMDAOs.Instance().fAVMNodeDAO.update(node); - } - - /** - * Delete all properties from a node. - * @param path The path to the node. - */ - public void deleteNodeProperties(String path) - { - Lookup lPath = lookup(-1, path, true, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write: " + path); - } - node.setGuid(GUID.generate()); - node.deleteProperties(); - - AVMDAOs.Instance().fAVMNodeDAO.update(node); - } - - /** - * Set a property on this store. Replaces if property already exists. - * @param name The QName of the property. - * @param value The actual PropertyValue. - */ - public void setProperty(QName name, PropertyValue value) - { - AVMStoreProperty prop = new AVMStorePropertyImpl(); - prop.setStore(this); - prop.setQname(name); - prop.setValue(value); - AVMDAOs.Instance().fAVMStorePropertyDAO.save(prop); - } - - /** - * Set a group of properties on this store. Replaces any property that exists. - * @param properties A Map of QNames to PropertyValues to set. - */ - public void setProperties(Map properties) - { - for (QName name : properties.keySet()) - { - setProperty(name, properties.get(name)); - } - } - - /** - * Get a property by name. - * @param name The QName of the property to fetch. - * @return The PropertyValue or null if non-existent. - */ - public PropertyValue getProperty(QName name) - { - return AVMDAOs.Instance().fAVMStorePropertyDAO.get(this, name); - } - - /** - * Get all the properties associated with this store. - * @return A Map of the properties. - */ - public Map getProperties() - { - return AVMDAOs.Instance().fAVMStorePropertyDAO.get(this); - } - - /** - * Delete a property. - * @param name The name of the property to delete. - */ - public void deleteProperty(QName name) - { - AVMDAOs.Instance().fAVMStorePropertyDAO.delete(this, name); - } - - /** - * Get the ContentData on a file. - * @param version The version to look under. - * @param path The path to the file. - * @return The ContentData corresponding to the file. - */ - public ContentData getContentDataForRead(int version, String path) - { - Lookup lPath = lookup(version, path, false, false); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!(node instanceof FileNode)) - { - throw new AVMWrongTypeException("File Expected."); - } - if (!fAVMRepository.can(this, node, PermissionService.READ_CONTENT, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to read: " + path); - } - ContentData content = ((FileNode)node).getContentData(lPath); - // AVMDAOs.Instance().fAVMNodeDAO.evict(node); - return content; - } - - /** - * Get the ContentData on a file for writing. - * @param path The path to the file. - * @return The ContentData corresponding to the file. - */ - public ContentData getContentDataForWrite(String path) - { - Lookup lPath = lookup(-1, path, true, false); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!(node instanceof FileNode)) - { - throw new AVMWrongTypeException("File Expected."); - } - if (!fAVMRepository.can(this, node, PermissionService.WRITE_CONTENT, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write content: " + path); - } - // TODO Set modifier. - node.updateModTime(); - node.setGuid(GUID.generate()); - - //AVMDAOs.Instance().fAVMNodeDAO.update(node); - // TODO review 'optimisation' - AVMDAOs.Instance().fAVMNodeDAO.updateModTimeAndGuid(node); - - ContentData content = ((FileNode)node).getContentData(lPath); - // AVMDAOs.Instance().fAVMNodeDAO.evict(node); - return content; - } - - // Not doing permission checking because it will already have been done - // at the getContentDataForWrite point. - /** - * Set the ContentData for a file. - * @param path The path to the file. - * @param data The ContentData to set. - */ - public void setContentData(String path, ContentData data) - { - Lookup lPath = lookup(-1, path, true, false); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!(node instanceof FileNode)) - { - throw new AVMWrongTypeException("File Expected."); - } - ((FileNode)node).setContentData(data); - node.updateModTime(); - - AVMDAOs.Instance().fAVMNodeDAO.update(node); - } - - /** - * Set meta data, aspects, properties, acls, from another node. - * @param path The path to the node to set metadata on. - * @param from The node to get the metadata from. - */ - public void setMetaDataFrom(String path, AVMNode from) - { - Lookup lPath = lookup(-1, path, true, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path not found: " + path); - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write properties: " + path); - } - node.copyMetaDataFrom(from, node.getAcl() == null ? null : node.getAcl().getInheritsFrom()); - node.setGuid(GUID.generate()); - - AVMDAOs.Instance().fAVMNodeDAO.update(node); - } - - /** - * Add an aspect to a node. - * @param path The path to the node. - * @param aspectName The name of the aspect. - */ - public void addAspect(String path, QName aspectName) - { - Lookup lPath = lookup(-1, path, true, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write: " + path); - } - - node.addAspect(aspectName); - node.setGuid(GUID.generate()); - - AVMDAOs.Instance().fAVMNodeDAO.update(node); - } - - /** - * Get all aspects on a given node. - * @param version The version to look under. - * @param path The path to the node. - * @return A List of the QNames of the aspects. - */ - public Set getAspects(int version, String path) - { - Lookup lPath = lookup(version, path, false, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to read properties: " + path); - } - - return node.getAspects(); - } - - /** - * Remove an aspect and all its properties from a node. - * @param path The path to the node. - * @param aspectName The name of the aspect. - */ - public void removeAspect(String path, QName aspectName) - { - Lookup lPath = lookup(-1, path, true, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write properties: " + path); - } - - node.removeAspect(aspectName); - - AspectDefinition def = RawServices.Instance().getDictionaryService().getAspect(aspectName); - Map properties = def.getProperties(); - - for (QName propertyQName : properties.keySet()) - { - node.deleteProperty(propertyQName); - } - - node.setGuid(GUID.generate()); - - AVMDAOs.Instance().fAVMNodeDAO.update(node); - } - - /** - * Does a given node have a given aspect. - * @param version The version to look under. - * @param path The path to the node. - * @param aspectName The name of the aspect. - * @return Whether the node has the aspect. - */ - public boolean hasAspect(int version, String path, QName aspectName) - { - Lookup lPath = lookup(version, path, false, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to read properties: " + path); - } - - return node.getAspects().contains(aspectName); - } - - /** - * Set the ACL on a node. - * @param path The path to the node. - * @param acl The ACL to set. - */ - public void setACL(String path, DbAccessControlList acl) - { - Lookup lPath = lookup(-1, path, true, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.CHANGE_PERMISSIONS, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to change permissions: " + path); - } - node.setAcl(acl); - node.setGuid(GUID.generate()); - - AVMDAOs.Instance().fAVMNodeDAO.update(node); - } - - /** - * Get the ACL on a node. - * @param version The version to look under. - * @param path The path to the node. - * @return The ACL. - */ - public DbAccessControlList getACL(int version, String path) - { - Lookup lPath = lookup(version, path, false, false); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - if (!fAVMRepository.can(this, lPath.getCurrentNode(), PermissionService.READ_PERMISSIONS, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to read permissions: " + path + " in "+getName()); - } - return lPath.getCurrentNode().getAcl(); - } - - /** - * Link a node into a directory, directly. - * @param parentPath The path to the directory. - * @param name The name to give the parent. - * @param toLink The node to link. - */ - public void link(String parentPath, String name, AVMNodeDescriptor toLink) - { - Lookup lPath = lookupDirectory(-1, parentPath, true); - if (lPath == null) - { - String pathParts[] = AVMUtil.splitBase(parentPath); - Lookup lPath2 = lookup(-1, pathParts[0], true, false); - if (lPath2 != null) - { - DirectoryNode parent = (DirectoryNode)lPath2.getCurrentNode(); - Pair temp = parent.lookupChild(lPath2, pathParts[1], false); - if ((temp != null) && (temp.getFirst() != null)) - { - DirectoryNode dir = (DirectoryNode)temp.getFirst(); - - if (logger.isDebugEnabled()) - { - logger.debug("Found: "+dir); - } - - boolean directlyContained = false; - - if (!fAVMRepository.can(null, dir, PermissionService.ADD_CHILDREN, directlyContained)) - { - throw new AccessDeniedException("Not allowed to add children: " + parentPath); - } - - AVMNodeDescriptor desc = fAVMRepository.forceCopy(AVMUtil.buildAVMPath(this.getName(), parentPath)); - fAVMRepository.link(desc, name, toLink); - return; - } - } - - throw new AVMNotFoundException("Path " + parentPath + " not found."); - } - DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - if (!fAVMRepository.can(null, dir, PermissionService.ADD_CHILDREN, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to add children: " + parentPath); - } - dir.link(lPath, name, toLink); - } - - /** - * Update a link to a node in a directory, directly. - * @param parentPath The path to the directory. - * @param name The name to give the parent. - * @param toLink The node to link. - */ - public void updateLink(String parentPath, String name, AVMNodeDescriptor toLink) - { - Lookup lPath = lookupDirectory(-1, parentPath, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + parentPath + " not found."); - } - DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - - Lookup cPath = new Lookup(lPath, AVMDAOs.Instance().fAVMNodeDAO, AVMDAOs.Instance().fAVMStoreDAO); - Pair result = dir.lookupChild(cPath, name, true); - if (result != null) - { - AVMNode child = result.getFirst(); - if (!fAVMRepository.can(null, child, PermissionService.WRITE, cPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to update node: " + parentPath + "/" +name ); - } - dir.removeChild(lPath, name); - } - dir.link(lPath, name, toLink); - } - - /** - * Revert a head path to a given version. This works by cloning - * the version to revert to, and then linking that new version into head. - * The reverted version will have the previous head version as ancestor. - * @param path The path to the parent directory. - * @param name The name of the node to revert. - * @param toRevertTo The descriptor of the version to revert to. - */ - public void revert(String path, String name, AVMNodeDescriptor toRevertTo) - { - Lookup lPath = lookupDirectory(-1, path, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path " + path + " not found."); - } - DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - - Pair temp = dir.lookupChild(lPath, name, true); - AVMNode child = (temp == null) ? null : temp.getFirst(); - if (child == null) - { - throw new AVMNotFoundException("Node not found: " + name); - } - if (!fAVMRepository.can(null, child, PermissionService.WRITE, false)) - { - throw new AccessDeniedException("Not allowed to revert: " + path); - } - AVMNode revertNode = AVMDAOs.Instance().fAVMNodeDAO.getByID(toRevertTo.getId()); - if (revertNode == null) - { - throw new AVMNotFoundException(toRevertTo.toString()); - } - AVMNode toLink = revertNode.copy(lPath); - dir.putChild(name, toLink); - toLink.changeAncestor(child); - toLink.setVersionID(child.getVersionID() + 1); - - toLink.addAspect(WCMModel.ASPECT_REVERTED); - - PropertyValue value = new PropertyValue(null, toRevertTo.getId()); - toLink.setProperty(WCMModel.PROP_REVERTED_ID, value); - - AVMDAOs.Instance().fAVMNodeDAO.update(toLink); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.AVMStore#setGuid(java.lang.String, java.lang.String) - */ - public void setGuid(String path, String guid) - { - Lookup lPath = lookup(-1, path, true, true); - if (lPath == null) - { - throw new AVMNotFoundException("Path not found: " + path); - } - AVMNode node = lPath.getCurrentNode(); - if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write properties: " + path); - } - node.setGuid(guid); - - AVMDAOs.Instance().fAVMNodeDAO.update(node); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.AVMStore#setEncoding(java.lang.String, java.lang.String) - */ - public void setEncoding(String path, String encoding) - { - Lookup lPath = lookup(-1, path, true, false); - if (lPath == null) - { - throw new AVMNotFoundException("Path not found: " + path); - } - AVMNode node = lPath.getCurrentNode(); - if (node.getType() != AVMNodeType.PLAIN_FILE) - { - throw new AVMWrongTypeException("Not a File: " + path); - } - if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write properties: " + path); - } - PlainFileNode file = (PlainFileNode)node; + } + + /** + * Set the opacity of a layered directory. An opaque directory hides + * what is pointed at by its indirection. + * @param path The path to the layered directory. + * @param opacity True is opaque; false is not. + */ + public void setOpacity(String path, boolean opacity) + { + Lookup lPath = lookup(-1, path, true, false); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!(node instanceof LayeredDirectoryNode)) + { + throw new AVMWrongTypeException("Not a LayeredDirectoryNode."); + } + if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write: " + path); + } + ((LayeredDirectoryNode)node).setOpacity(opacity); + node.updateModTime(); + + AVMDAOs.Instance().fAVMNodeDAO.update(node); + } + + // TODO Does it make sense to set properties on DeletedNodes? + /** + * Set a property on a node. + * @param path The path to the node. + * @param name The name of the property. + * @param value The value to set. + */ + public void setNodeProperty(String path, QName name, PropertyValue value) + { + Lookup lPath = lookup(-1, path, true, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write: " + path); + } + + node.setProperty(name, value); + + node.setGuid(GUID.generate()); + + AVMDAOs.Instance().fAVMNodeDAO.update(node); // guid and property + } + + /** + * Set a collection of properties on a node. + * @param path The path to the node. + * @param properties The Map of QNames to PropertyValues. + */ + public void setNodeProperties(String path, Map properties) + { + Lookup lPath = lookup(-1, path, true, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write: " + path); + } + if (properties != null) + { + Map props = new HashMap(properties.size()); + props.putAll(properties); + node.addProperties(props); + } + node.setGuid(GUID.generate()); + + AVMDAOs.Instance().fAVMNodeDAO.update(node); + } + + /** + * Get a property by name. + * @param version The version to lookup. + * @param path The path to the node. + * @param name The name of the property. + * @return A PropertyValue or null if not found. + */ + public PropertyValue getNodeProperty(int version, String path, QName name) + { + Lookup lPath = lookup(version, path, false, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to read: " + path); + } + + return node.getProperty(name); + } + + /** + * Get all the properties associated with a node. + * @param version The version to lookup. + * @param path The path to the node. + * @return A Map of QNames to PropertyValues. + */ + public Map getNodeProperties(int version, String path) + { + Lookup lPath = lookup(version, path, false, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to read: " + path); + } + + return node.getProperties(); + } + + /** + * Delete a single property from a node. + * @param path The path to the node. + * @param name The name of the property. + */ + public void deleteNodeProperty(String path, QName name) + { + Lookup lPath = lookup(-1, path, true, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write: " + path); + } + node.setGuid(GUID.generate()); + + node.deleteProperty(name); + + AVMDAOs.Instance().fAVMNodeDAO.update(node); + } + + /** + * Delete all properties from a node. + * @param path The path to the node. + */ + public void deleteNodeProperties(String path) + { + Lookup lPath = lookup(-1, path, true, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write: " + path); + } + node.setGuid(GUID.generate()); + node.deleteProperties(); + + AVMDAOs.Instance().fAVMNodeDAO.update(node); + } + + /** + * Set a property on this store. Replaces if property already exists. + * @param name The QName of the property. + * @param value The actual PropertyValue. + */ + public void setProperty(QName name, PropertyValue value) + { + AVMStoreProperty prop = new AVMStorePropertyImpl(); + prop.setStore(this); + prop.setQname(name); + prop.setValue(value); + AVMDAOs.Instance().fAVMStorePropertyDAO.save(prop); + } + + /** + * Set a group of properties on this store. Replaces any property that exists. + * @param properties A Map of QNames to PropertyValues to set. + */ + public void setProperties(Map properties) + { + for (QName name : properties.keySet()) + { + setProperty(name, properties.get(name)); + } + } + + /** + * Get a property by name. + * @param name The QName of the property to fetch. + * @return The PropertyValue or null if non-existent. + */ + public PropertyValue getProperty(QName name) + { + return AVMDAOs.Instance().fAVMStorePropertyDAO.get(this, name); + } + + /** + * Get all the properties associated with this store. + * @return A Map of the properties. + */ + public Map getProperties() + { + return AVMDAOs.Instance().fAVMStorePropertyDAO.get(this); + } + + /** + * Delete a property. + * @param name The name of the property to delete. + */ + public void deleteProperty(QName name) + { + AVMDAOs.Instance().fAVMStorePropertyDAO.delete(this, name); + } + + /** + * Get the ContentData on a file. + * @param version The version to look under. + * @param path The path to the file. + * @return The ContentData corresponding to the file. + */ + public ContentData getContentDataForRead(int version, String path) + { + Lookup lPath = lookup(version, path, false, false); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!(node instanceof FileNode)) + { + throw new AVMWrongTypeException("File Expected."); + } + if (!fAVMRepository.can(this, node, PermissionService.READ_CONTENT, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to read: " + path); + } + ContentData content = ((FileNode)node).getContentData(lPath); + // AVMDAOs.Instance().fAVMNodeDAO.evict(node); + return content; + } + + /** + * Get the ContentData on a file for writing. + * @param path The path to the file. + * @return The ContentData corresponding to the file. + */ + public ContentData getContentDataForWrite(String path) + { + Lookup lPath = lookup(-1, path, true, false); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!(node instanceof FileNode)) + { + throw new AVMWrongTypeException("File Expected."); + } + if (!fAVMRepository.can(this, node, PermissionService.WRITE_CONTENT, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write content: " + path); + } + // TODO Set modifier. + node.updateModTime(); + node.setGuid(GUID.generate()); + + //AVMDAOs.Instance().fAVMNodeDAO.update(node); + // TODO review 'optimisation' + AVMDAOs.Instance().fAVMNodeDAO.updateModTimeAndGuid(node); + + ContentData content = ((FileNode)node).getContentData(lPath); + // AVMDAOs.Instance().fAVMNodeDAO.evict(node); + return content; + } + + // Not doing permission checking because it will already have been done + // at the getContentDataForWrite point. + /** + * Set the ContentData for a file. + * @param path The path to the file. + * @param data The ContentData to set. + */ + public void setContentData(String path, ContentData data) + { + Lookup lPath = lookup(-1, path, true, false); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!(node instanceof FileNode)) + { + throw new AVMWrongTypeException("File Expected."); + } + ((FileNode)node).setContentData(data); + node.updateModTime(); + + AVMDAOs.Instance().fAVMNodeDAO.update(node); + } + + /** + * Set meta data, aspects, properties, acls, from another node. + * @param path The path to the node to set metadata on. + * @param from The node to get the metadata from. + */ + public void setMetaDataFrom(String path, AVMNode from) + { + Lookup lPath = lookup(-1, path, true, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path not found: " + path); + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write properties: " + path); + } + node.copyMetaDataFrom(from, node.getAcl() == null ? null : node.getAcl().getInheritsFrom()); + node.setGuid(GUID.generate()); + + AVMDAOs.Instance().fAVMNodeDAO.update(node); + } + + /** + * Add an aspect to a node. + * @param path The path to the node. + * @param aspectName The name of the aspect. + */ + public void addAspect(String path, QName aspectName) + { + Lookup lPath = lookup(-1, path, true, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write: " + path); + } + + node.addAspect(aspectName); + node.setGuid(GUID.generate()); + + AVMDAOs.Instance().fAVMNodeDAO.update(node); + } + + /** + * Get all aspects on a given node. + * @param version The version to look under. + * @param path The path to the node. + * @return A List of the QNames of the aspects. + */ + public Set getAspects(int version, String path) + { + Lookup lPath = lookup(version, path, false, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to read properties: " + path); + } + + return node.getAspects(); + } + + /** + * Remove an aspect and all its properties from a node. + * @param path The path to the node. + * @param aspectName The name of the aspect. + */ + public void removeAspect(String path, QName aspectName) + { + Lookup lPath = lookup(-1, path, true, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write properties: " + path); + } + + node.removeAspect(aspectName); + + AspectDefinition def = RawServices.Instance().getDictionaryService().getAspect(aspectName); + Map properties = def.getProperties(); + + for (QName propertyQName : properties.keySet()) + { + node.deleteProperty(propertyQName); + } + + node.setGuid(GUID.generate()); + + AVMDAOs.Instance().fAVMNodeDAO.update(node); + } + + /** + * Does a given node have a given aspect. + * @param version The version to look under. + * @param path The path to the node. + * @param aspectName The name of the aspect. + * @return Whether the node has the aspect. + */ + public boolean hasAspect(int version, String path, QName aspectName) + { + Lookup lPath = lookup(version, path, false, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to read properties: " + path); + } + + return node.getAspects().contains(aspectName); + } + + /** + * Set the ACL on a node. + * @param path The path to the node. + * @param acl The ACL to set. + */ + public void setACL(String path, DbAccessControlList acl) + { + Lookup lPath = lookup(-1, path, true, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.CHANGE_PERMISSIONS, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to change permissions: " + path); + } + node.setAcl(acl); + node.setGuid(GUID.generate()); + + AVMDAOs.Instance().fAVMNodeDAO.update(node); + } + + /** + * Get the ACL on a node. + * @param version The version to look under. + * @param path The path to the node. + * @return The ACL. + */ + public DbAccessControlList getACL(int version, String path) + { + Lookup lPath = lookup(version, path, false, false); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + if (!fAVMRepository.can(this, lPath.getCurrentNode(), PermissionService.READ_PERMISSIONS, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to read permissions: " + path + " in "+getName()); + } + return lPath.getCurrentNode().getAcl(); + } + + /** + * Link a node into a directory, directly. + * @param parentPath The path to the directory. + * @param name The name to give the parent. + * @param toLink The node to link. + */ + public void link(String parentPath, String name, AVMNodeDescriptor toLink) + { + Lookup lPath = lookupDirectory(-1, parentPath, true); + if (lPath == null) + { + String pathParts[] = AVMUtil.splitBase(parentPath); + Lookup lPath2 = lookup(-1, pathParts[0], true, false); + if (lPath2 != null) + { + DirectoryNode parent = (DirectoryNode)lPath2.getCurrentNode(); + Pair temp = parent.lookupChild(lPath2, pathParts[1], false); + if ((temp != null) && (temp.getFirst() != null)) + { + DirectoryNode dir = (DirectoryNode)temp.getFirst(); + + if (logger.isDebugEnabled()) + { + logger.debug("Found: "+dir); + } + + boolean directlyContained = false; + + if (!fAVMRepository.can(null, dir, PermissionService.ADD_CHILDREN, directlyContained)) + { + throw new AccessDeniedException("Not allowed to add children: " + parentPath); + } + + AVMNodeDescriptor desc = fAVMRepository.forceCopy(AVMUtil.buildAVMPath(this.getName(), parentPath)); + fAVMRepository.link(desc, name, toLink); + return; + } + } + + throw new AVMNotFoundException("Path " + parentPath + " not found."); + } + DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); + if (!fAVMRepository.can(null, dir, PermissionService.ADD_CHILDREN, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to add children: " + parentPath); + } + dir.link(lPath, name, toLink); + } + + /** + * Update a link to a node in a directory, directly. + * @param parentPath The path to the directory. + * @param name The name to give the parent. + * @param toLink The node to link. + */ + public void updateLink(String parentPath, String name, AVMNodeDescriptor toLink) + { + Lookup lPath = lookupDirectory(-1, parentPath, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + parentPath + " not found."); + } + DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); + + Lookup cPath = new Lookup(lPath, AVMDAOs.Instance().fAVMNodeDAO, AVMDAOs.Instance().fAVMStoreDAO); + Pair result = dir.lookupChild(cPath, name, true); + if (result != null) + { + AVMNode child = result.getFirst(); + if (!fAVMRepository.can(null, child, PermissionService.WRITE, cPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to update node: " + parentPath + "/" +name ); + } + dir.removeChild(lPath, name); + } + dir.link(lPath, name, toLink); + } + + /** + * Revert a head path to a given version. This works by cloning + * the version to revert to, and then linking that new version into head. + * The reverted version will have the previous head version as ancestor. + * @param path The path to the parent directory. + * @param name The name of the node to revert. + * @param toRevertTo The descriptor of the version to revert to. + */ + public void revert(String path, String name, AVMNodeDescriptor toRevertTo) + { + Lookup lPath = lookupDirectory(-1, path, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path " + path + " not found."); + } + DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); + + Pair temp = dir.lookupChild(lPath, name, true); + AVMNode child = (temp == null) ? null : temp.getFirst(); + if (child == null) + { + throw new AVMNotFoundException("Node not found: " + name); + } + if (!fAVMRepository.can(null, child, PermissionService.WRITE, false)) + { + throw new AccessDeniedException("Not allowed to revert: " + path); + } + AVMNode revertNode = AVMDAOs.Instance().fAVMNodeDAO.getByID(toRevertTo.getId()); + if (revertNode == null) + { + throw new AVMNotFoundException(toRevertTo.toString()); + } + AVMNode toLink = revertNode.copy(lPath); + dir.putChild(name, toLink); + toLink.changeAncestor(child); + toLink.setVersionID(child.getVersionID() + 1); + + toLink.addAspect(WCMModel.ASPECT_REVERTED); + + PropertyValue value = new PropertyValue(null, toRevertTo.getId()); + toLink.setProperty(WCMModel.PROP_REVERTED_ID, value); + + AVMDAOs.Instance().fAVMNodeDAO.update(toLink); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.avm.AVMStore#setGuid(java.lang.String, java.lang.String) + */ + public void setGuid(String path, String guid) + { + Lookup lPath = lookup(-1, path, true, true); + if (lPath == null) + { + throw new AVMNotFoundException("Path not found: " + path); + } + AVMNode node = lPath.getCurrentNode(); + if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write properties: " + path); + } + node.setGuid(guid); + + AVMDAOs.Instance().fAVMNodeDAO.update(node); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.avm.AVMStore#setEncoding(java.lang.String, java.lang.String) + */ + public void setEncoding(String path, String encoding) + { + Lookup lPath = lookup(-1, path, true, false); + if (lPath == null) + { + throw new AVMNotFoundException("Path not found: " + path); + } + AVMNode node = lPath.getCurrentNode(); + if (node.getType() != AVMNodeType.PLAIN_FILE) + { + throw new AVMWrongTypeException("Not a File: " + path); + } + if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write properties: " + path); + } + PlainFileNode file = (PlainFileNode)node; ContentData contentData = file.getContentData(); contentData = ContentData.setEncoding(contentData, encoding); file.setContentData(contentData); - - AVMDAOs.Instance().fAVMNodeDAO.update(file); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.AVMStore#setMimeType(java.lang.String, java.lang.String) - */ - public void setMimeType(String path, String mimeType) - { - Lookup lPath = lookup(-1, path, true, false); - if (lPath == null) - { - throw new AVMNotFoundException("Path not found: " + path); - } - AVMNode node = lPath.getCurrentNode(); - if (node.getType() != AVMNodeType.PLAIN_FILE) - { - throw new AVMWrongTypeException("Not a File: " + path); - } - if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) - { - throw new AccessDeniedException("Not allowed to write properties: " + path); - } - PlainFileNode file = (PlainFileNode)node; + + AVMDAOs.Instance().fAVMNodeDAO.update(file); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.avm.AVMStore#setMimeType(java.lang.String, java.lang.String) + */ + public void setMimeType(String path, String mimeType) + { + Lookup lPath = lookup(-1, path, true, false); + if (lPath == null) + { + throw new AVMNotFoundException("Path not found: " + path); + } + AVMNode node = lPath.getCurrentNode(); + if (node.getType() != AVMNodeType.PLAIN_FILE) + { + throw new AVMWrongTypeException("Not a File: " + path); + } + if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained())) + { + throw new AccessDeniedException("Not allowed to write properties: " + path); + } + PlainFileNode file = (PlainFileNode)node; ContentData contentData = file.getContentData(); contentData = ContentData.setMimetype(contentData, mimeType); file.setContentData(contentData); - - AVMDAOs.Instance().fAVMNodeDAO.update(file); - } - - // for debug - @Override - public String toString() - { - return getName(); - } -} + + AVMDAOs.Instance().fAVMNodeDAO.update(file); + } + + // for debug + @Override + public String toString() + { + return getName(); + } +} diff --git a/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java b/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java index a9883b2e24..c0d8ce6967 100644 --- a/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java @@ -24,9 +24,9 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TreeMap; +import java.util.TreeMap; -import org.alfresco.repo.avm.util.AVMUtil; +import org.alfresco.repo.avm.util.AVMUtil; import org.alfresco.repo.domain.DbAccessControlList; import org.alfresco.repo.domain.PropertyValue; import org.alfresco.repo.security.permissions.ACLCopyMode; @@ -55,7 +55,7 @@ import org.apache.commons.logging.LogFactory; */ public class AVMSyncServiceImpl implements AVMSyncService { - private static Log logger = LogFactory.getLog(AVMSyncServiceImpl.class); + private static Log logger = LogFactory.getLog(AVMSyncServiceImpl.class); /** * The AVMService. @@ -112,11 +112,11 @@ public class AVMSyncServiceImpl implements AVMSyncService int dstVersion, String dstPath, NameMatcher excluder) { - long start = System.currentTimeMillis(); - - if (logger.isDebugEnabled()) + long start = System.currentTimeMillis(); + + if (logger.isDebugEnabled()) { - logger.debug(srcPath + " : " + dstPath); + logger.debug(srcPath + " : " + dstPath); } if (srcPath == null || dstPath == null) { @@ -141,12 +141,12 @@ public class AVMSyncServiceImpl implements AVMSyncService // Invoke the recursive implementation. compare(srcVersion, srcDesc, dstVersion, dstDesc, result, excluder, true); } - - if (logger.isDebugEnabled()) - { - logger.debug("Raw compare: ["+srcVersion+","+srcPath+"]["+dstVersion+","+dstPath+"]["+result.size()+"] in "+(System.currentTimeMillis()-start)+" msecs"); - } - + + if (logger.isDebugEnabled()) + { + logger.debug("Raw compare: ["+srcVersion+","+srcPath+"]["+dstVersion+","+dstPath+"]["+result.size()+"] in "+(System.currentTimeMillis()-start)+" msecs"); + } + return result; } @@ -161,29 +161,29 @@ public class AVMSyncServiceImpl implements AVMSyncService int dstVersion, AVMNodeDescriptor dstDesc, List result, NameMatcher excluder, boolean firstLevel) { - String srcPath = srcDesc.getPath(); - String dstPath = dstDesc.getPath(); - - String srcParts[] = AVMUtil.splitBase(srcPath); - String srcChildName = srcParts[1]; - - String dstParts[] = AVMUtil.splitBase(dstPath); - String dstChildName = dstParts[1]; - - if ((dstChildName.equalsIgnoreCase(srcChildName)) && (! dstChildName.equals(srcChildName))) - { - // specific rename 'case' - String dstParentPath = dstParts[0]; - if (dstParentPath == null) - { - dstParentPath = AVMUtil.buildAVMPath(AVMUtil.getStoreName(dstPath), ""); - } - dstPath = AVMUtil.extendAVMPath(dstParentPath, srcChildName); - } - + String srcPath = srcDesc.getPath(); + String dstPath = dstDesc.getPath(); + + String srcParts[] = AVMUtil.splitBase(srcPath); + String srcChildName = srcParts[1]; + + String dstParts[] = AVMUtil.splitBase(dstPath); + String dstChildName = dstParts[1]; + + if ((dstChildName.equalsIgnoreCase(srcChildName)) && (! dstChildName.equals(srcChildName))) + { + // specific rename 'case' + String dstParentPath = dstParts[0]; + if (dstParentPath == null) + { + dstParentPath = AVMUtil.buildAVMPath(AVMUtil.getStoreName(dstPath), ""); + } + dstPath = AVMUtil.extendAVMPath(dstParentPath, srcChildName); + } + // Determine how the source and destination nodes differ. - if (excluder != null && (excluder.matches(srcPath) || - excluder.matches(dstPath))) + if (excluder != null && (excluder.matches(srcPath) || + excluder.matches(dstPath))) { return; } @@ -200,8 +200,8 @@ public class AVMSyncServiceImpl implements AVMSyncService case AVMDifference.OLDER : case AVMDifference.CONFLICT : { - result.add(new AVMDifference(srcVersion, srcPath, - dstVersion, dstPath, + result.add(new AVMDifference(srcVersion, srcPath, + dstVersion, dstPath, diffCode)); return; } @@ -210,7 +210,7 @@ public class AVMSyncServiceImpl implements AVMSyncService // First special case: source is a layered directory which points to // the destinations path, and we are comparing 'head' versions. if (srcDesc.isLayeredDirectory() && - srcDesc.getIndirection().equalsIgnoreCase(dstPath) && srcVersion < 0 && dstVersion < 0) + srcDesc.getIndirection().equalsIgnoreCase(dstPath) && srcVersion < 0 && dstVersion < 0) { // skip firstLevel (root) if (! firstLevel) @@ -223,8 +223,8 @@ public class AVMSyncServiceImpl implements AVMSyncService case AVMDifference.NEWER : case AVMDifference.CONFLICT : { - result.add(new AVMDifference(srcVersion, srcPath, - dstVersion, dstPath, + result.add(new AVMDifference(srcVersion, srcPath, + dstVersion, dstPath, dirDiffCode)); return; // short circuit } @@ -255,21 +255,21 @@ public class AVMSyncServiceImpl implements AVMSyncService { AVMNodeDescriptor srcChild = srcList.get(name); AVMNodeDescriptor dstChild = dstList.get(name); - - String srcChildPath = srcChild.getPath(); - String dstChildPath = AVMNodeConverter.ExtendAVMPath(dstPath, name); - - if (excluder != null && (excluder.matches(srcChildPath) || - excluder.matches(dstChildPath))) + + String srcChildPath = srcChild.getPath(); + String dstChildPath = AVMNodeConverter.ExtendAVMPath(dstPath, name); + + if (excluder != null && (excluder.matches(srcChildPath) || + excluder.matches(dstChildPath))) { continue; } if (dstChild == null) { // A missing destination child means the source is NEWER. - result.add(new AVMDifference(srcVersion, srcChildPath, - dstVersion, dstChildPath, - AVMDifference.NEWER)); + result.add(new AVMDifference(srcVersion, srcChildPath, + dstVersion, dstChildPath, + AVMDifference.NEWER)); continue; } // Otherwise recursively invoke. @@ -281,7 +281,7 @@ public class AVMSyncServiceImpl implements AVMSyncService } // Second special case. Just as above but reversed. if (dstDesc.isLayeredDirectory() && - dstDesc.getIndirection().equalsIgnoreCase(srcPath) && srcVersion < 0 && dstVersion < 0) + dstDesc.getIndirection().equalsIgnoreCase(srcPath) && srcVersion < 0 && dstVersion < 0) { // skip firstLevel (root) if (! firstLevel) @@ -294,8 +294,8 @@ public class AVMSyncServiceImpl implements AVMSyncService case AVMDifference.NEWER : case AVMDifference.CONFLICT : { - result.add(new AVMDifference(srcVersion, srcPath, - dstVersion, dstPath, + result.add(new AVMDifference(srcVersion, srcPath, + dstVersion, dstPath, dirDiffCode)); return; // short circuit } @@ -325,20 +325,20 @@ public class AVMSyncServiceImpl implements AVMSyncService { AVMNodeDescriptor dstChild = dstList.get(name); AVMNodeDescriptor srcChild = srcList.get(name); - - String srcChildPath = AVMNodeConverter.ExtendAVMPath(srcPath, name); - String dstChildPath = dstChild.getPath(); - - if (excluder != null && (excluder.matches(srcChildPath) || - excluder.matches(dstChildPath))) + + String srcChildPath = AVMNodeConverter.ExtendAVMPath(srcPath, name); + String dstChildPath = dstChild.getPath(); + + if (excluder != null && (excluder.matches(srcChildPath) || + excluder.matches(dstChildPath))) { continue; } if (srcChild == null) { // Missing means the source is older. - result.add(new AVMDifference(srcVersion, srcChildPath, - dstVersion, dstChildPath, + result.add(new AVMDifference(srcVersion, srcChildPath, + dstVersion, dstChildPath, AVMDifference.OLDER)); continue; } @@ -359,20 +359,20 @@ public class AVMSyncServiceImpl implements AVMSyncService { AVMNodeDescriptor srcChild = srcList.get(name); AVMNodeDescriptor dstChild = dstList.get(name); - - String srcChildPath = srcChild.getPath(); - String dstChildPath = AVMNodeConverter.ExtendAVMPath(dstPath, name); - - if (excluder != null && (excluder.matches(srcChildPath) || - excluder.matches(dstChildPath))) + + String srcChildPath = srcChild.getPath(); + String dstChildPath = AVMNodeConverter.ExtendAVMPath(dstPath, name); + + if (excluder != null && (excluder.matches(srcChildPath) || + excluder.matches(dstChildPath))) { continue; } if (dstChild == null) { // Not found in the destination means NEWER. - result.add(new AVMDifference(srcVersion, srcChildPath, - dstVersion, dstChildPath, + result.add(new AVMDifference(srcVersion, srcChildPath, + dstVersion, dstChildPath, AVMDifference.NEWER)); continue; } @@ -388,20 +388,20 @@ public class AVMSyncServiceImpl implements AVMSyncService { continue; } - + AVMNodeDescriptor dstChild = dstList.get(name); - - String srcChildPath = AVMNodeConverter.ExtendAVMPath(srcPath, name); - String dstChildPath = dstChild.getPath(); - - if (excluder != null && (excluder.matches(srcChildPath) || - excluder.matches(dstChildPath))) + + String srcChildPath = AVMNodeConverter.ExtendAVMPath(srcPath, name); + String dstChildPath = dstChild.getPath(); + + if (excluder != null && (excluder.matches(srcChildPath) || + excluder.matches(dstChildPath))) { continue; } // An entry not found in the source is OLDER. - result.add(new AVMDifference(srcVersion, srcChildPath, - dstVersion, dstChildPath, + result.add(new AVMDifference(srcVersion, srcChildPath, + dstVersion, dstChildPath, AVMDifference.OLDER)); } break; @@ -437,12 +437,12 @@ public class AVMSyncServiceImpl implements AVMSyncService boolean overrideConflicts, boolean overrideOlder, String tag, String description) { long start = System.currentTimeMillis(); - + Map storeVersions = new HashMap(); Set destStores = new HashSet(); - - Map diffsToUpdate = new TreeMap(); - + + Map diffsToUpdate = new TreeMap(); + for (AVMDifference diff : diffList) { if (excluder != null && (excluder.matches(diff.getSourcePath()) || @@ -450,26 +450,26 @@ public class AVMSyncServiceImpl implements AVMSyncService { continue; } - + if (!diff.isValid()) { throw new AVMSyncException("Malformed AVMDifference."); } - - diffsToUpdate.put(diff.getSourcePath(), diff); - } - - for (AVMDifference diff : diffsToUpdate.values()) - { - if (logger.isDebugEnabled()) + + diffsToUpdate.put(diff.getSourcePath(), diff); + } + + for (AVMDifference diff : diffsToUpdate.values()) + { + if (logger.isDebugEnabled()) { - logger.debug("update: " + diff); + logger.debug("update: " + diff); } // Snapshot the source if needed. int version = diff.getSourceVersion(); if (version < 0) { - String storeName = AVMUtil.getStoreName(diff.getSourcePath()); + String storeName = AVMUtil.getStoreName(diff.getSourcePath()); if (storeVersions.containsKey(storeName)) { // We've already snapshotted this store. @@ -500,20 +500,20 @@ public class AVMSyncServiceImpl implements AVMSyncService // Keep track of stores updated so that they can all be snapshotted // at end of update. String dstPath = diff.getDestinationPath(); - destStores.add(AVMUtil.getStoreName(dstPath)); + destStores.add(AVMUtil.getStoreName(dstPath)); dispatchUpdate(diffCode, dstParts[0], dstParts[1], excluder, srcDesc, dstDesc, ignoreConflicts, ignoreOlder, overrideConflicts, overrideOlder); } - + for (String storeName : destStores) { fAVMService.createSnapshot(storeName, tag, description); } - - if (logger.isDebugEnabled()) + + if (logger.isDebugEnabled()) { - logger.debug("Raw update: [" + diffList.size() + "] in " + (System.currentTimeMillis() - start) + " msecs"); + logger.debug("Raw update: [" + diffList.size() + "] in " + (System.currentTimeMillis() - start) + " msecs"); } } @@ -531,7 +531,7 @@ public class AVMSyncServiceImpl implements AVMSyncService case AVMDifference.NEWER : { // You can't delete what isn't there. - linkIn(parentPath, name, srcDesc, excluder, dstDesc != null && !dstDesc.isDeleted(), dstDesc); + linkIn(parentPath, name, srcDesc, excluder, dstDesc != null && !dstDesc.isDeleted(), dstDesc); return; } case AVMDifference.OLDER : @@ -539,7 +539,7 @@ public class AVMSyncServiceImpl implements AVMSyncService // You can force it. if (overrideOlder) { - linkIn(parentPath, name, srcDesc, excluder, !dstDesc.isDeleted(), dstDesc); + linkIn(parentPath, name, srcDesc, excluder, !dstDesc.isDeleted(), dstDesc); return; } // You can ignore it. @@ -555,7 +555,7 @@ public class AVMSyncServiceImpl implements AVMSyncService // You can force it. if (overrideConflicts) { - linkIn(parentPath, name, srcDesc, excluder, true, dstDesc); + linkIn(parentPath, name, srcDesc, excluder, true, dstDesc); return; } // You can ignore it. @@ -593,7 +593,7 @@ public class AVMSyncServiceImpl implements AVMSyncService * @param toLink The node descriptor. * @param removeFirst Whether to do a removeNode before linking in. */ - private void linkIn(String parentPath, String name, AVMNodeDescriptor toLink, NameMatcher excluder, boolean removeFirst, AVMNodeDescriptor dstDesc) + private void linkIn(String parentPath, String name, AVMNodeDescriptor toLink, NameMatcher excluder, boolean removeFirst, AVMNodeDescriptor dstDesc) { // This is a delete. if (toLink == null) @@ -605,9 +605,9 @@ public class AVMSyncServiceImpl implements AVMSyncService catch (AVMNotFoundException nfe) { // ignore - if (logger.isDebugEnabled()) + if (logger.isDebugEnabled()) { - logger.debug("linkIn: Does not exist: "+parentPath+"/"+name); + logger.debug("linkIn: Does not exist: "+parentPath+"/"+name); } } return; @@ -624,18 +624,18 @@ public class AVMSyncServiceImpl implements AVMSyncService recursiveCopy(parentPath, name, toLink, excluder); return; } - - String newPath = AVMNodeConverter.ExtendAVMPath(parentPath, name); - - if (toLink.isLayeredDirectory() && - toLink.isPrimary() && - dstDesc == null && - toLink.getIndirection().equals(newPath)) - { - recursiveCopy(parentPath, name, toLink, excluder); - return; - } - + + String newPath = AVMNodeConverter.ExtendAVMPath(parentPath, name); + + if (toLink.isLayeredDirectory() && + toLink.isPrimary() && + dstDesc == null && + toLink.getIndirection().equals(newPath)) + { + recursiveCopy(parentPath, name, toLink, excluder); + return; + } + if (removeFirst) { if (toLink.isDirectory()) @@ -655,11 +655,9 @@ public class AVMSyncServiceImpl implements AVMSyncService fAVMService.link(parentPath, name, toLink); } - DbAccessControlList parentAcl= getACL(parentPath); - DbAccessControlList acl = getACL(toLink.getPath()); - setACL(newPath, acl == null ? null : acl.getCopy(parentAcl == null ? null : parentAcl.getId(), ACLCopyMode.COPY)); + setACL(parentPath, toLink.getPath(), newPath); } - + /* * Get acl */ @@ -680,18 +678,18 @@ public class AVMSyncServiceImpl implements AVMSyncService /* * Set ACL without COW */ - private void setACL(String path, DbAccessControlList acl) + private void setACL(String parentPath, String toCopyPath, String newPath) { - Lookup lookup = AVMRepository.GetInstance().lookup(-1, path, false); + DbAccessControlList parentAcl= getACL(parentPath); + DbAccessControlList acl = getACL(toCopyPath); + + Lookup lookup = AVMRepository.GetInstance().lookup(-1, newPath, false); if (lookup != null) { - AVMNode node = lookup.getCurrentNode(); - // May be support an unwrapped getById to avoid this monkey madness - AVMDAOs.Instance().fAVMNodeDAO.evict(node); - node = AVMDAOs.Instance().fAVMNodeDAO.getByID(node.getId()); - node.setAcl(acl); + AVMNode newNode = lookup.getCurrentNode(); + newNode.copyACLs(acl, parentAcl, ACLCopyMode.COPY); - AVMDAOs.Instance().fAVMNodeDAO.update(node); + AVMDAOs.Instance().fAVMNodeDAO.update(newNode); } else { @@ -737,10 +735,9 @@ public class AVMSyncServiceImpl implements AVMSyncService if (toCopy.isFile() || toCopy.isDeleted() || toCopy.isPlainDirectory()) { fAVMRepository.link(parent, name, toCopy); + // needs to get the acl from the new location - DbAccessControlList parentAcl = getACL(parent.getPath()); - DbAccessControlList acl = getACL(toCopy.getPath()); - setACL(newPath, acl == null ? null : acl.getCopy(parentAcl == null ? null : parentAcl.getId(), ACLCopyMode.COPY)); + setACL(parent.getPath(), toCopy.getPath(), newPath); return; } // Otherwise make a directory in the target parent, and recursiveCopy all the source @@ -801,30 +798,30 @@ public class AVMSyncServiceImpl implements AVMSyncService if (common.isLayeredFile()) { - Integer diff = compareLayeredCommonAncestor(common, srcDesc, dstDesc); - if (diff != null) + Integer diff = compareLayeredCommonAncestor(common, srcDesc, dstDesc); + if (diff != null) { - return diff; + return diff; } } if (srcDesc.isDeleted() && (srcDesc.getDeletedType() == AVMNodeType.LAYERED_DIRECTORY)) { - Integer diff = compareLayeredCommonAncestor(common, srcDesc, dstDesc); - if (diff != null) + Integer diff = compareLayeredCommonAncestor(common, srcDesc, dstDesc); + if (diff != null) { - return diff; + return diff; } } else if (dstDesc.isDeleted() && (dstDesc.getDeletedType() == AVMNodeType.LAYERED_DIRECTORY)) { - Integer diff = compareLayeredCommonAncestor(common, dstDesc, srcDesc); - if (diff != null) + Integer diff = compareLayeredCommonAncestor(common, dstDesc, srcDesc); + if (diff != null) { - return diff; + return diff; } } - + // Must be a conflict. return AVMDifference.CONFLICT; } @@ -936,15 +933,15 @@ public class AVMSyncServiceImpl implements AVMSyncService return AVMDifference.NEWER; } - if (common.isLayeredFile()) - { - Integer diff = compareLayeredCommonAncestor(common, srcDesc, dstDesc); - if (diff != null) - { - return diff; - } - } - + if (common.isLayeredFile()) + { + Integer diff = compareLayeredCommonAncestor(common, srcDesc, dstDesc); + if (diff != null) + { + return diff; + } + } + return AVMDifference.CONFLICT; } // Destination is a plain file. @@ -966,10 +963,10 @@ public class AVMSyncServiceImpl implements AVMSyncService if (common.isLayeredFile()) { - Integer diff = compareLayeredCommonAncestor(common, srcDesc, dstDesc); - if (diff != null) + Integer diff = compareLayeredCommonAncestor(common, srcDesc, dstDesc); + if (diff != null) { - return diff; + return diff; } } @@ -977,42 +974,42 @@ public class AVMSyncServiceImpl implements AVMSyncService return AVMDifference.CONFLICT; } - private Integer compareLayeredCommonAncestor(AVMNodeDescriptor common, AVMNodeDescriptor srcDesc, AVMNodeDescriptor dstDesc) - { - Integer diff = null; - - // check dst ancestry - diff = compareLayeredCommonAncestor(common, dstDesc.getId(), AVMDifference.NEWER); - if (diff == null) - { - // check src ancestry - diff = compareLayeredCommonAncestor(common, srcDesc.getId(), AVMDifference.OLDER); - } - - return diff; - } - - private Integer compareLayeredCommonAncestor(AVMNodeDescriptor common, long compareNodeId, int diffType) - { - Integer diff = null; - - AVMNode compareAncNode = AVMDAOs.Instance().fAVMNodeDAO.getByID(compareNodeId).getAncestor(); - if (compareAncNode != null) - { - if (common.getId() == compareAncNode.getId()) - { - diff = diffType; - } - else if (common.isLayeredFile()) - { - // TODO review (alongside createSnapshot+COW) - diff = compareLayeredCommonAncestor(common, compareAncNode.getId(), diffType); - } - } - - return diff; - } - + private Integer compareLayeredCommonAncestor(AVMNodeDescriptor common, AVMNodeDescriptor srcDesc, AVMNodeDescriptor dstDesc) + { + Integer diff = null; + + // check dst ancestry + diff = compareLayeredCommonAncestor(common, dstDesc.getId(), AVMDifference.NEWER); + if (diff == null) + { + // check src ancestry + diff = compareLayeredCommonAncestor(common, srcDesc.getId(), AVMDifference.OLDER); + } + + return diff; + } + + private Integer compareLayeredCommonAncestor(AVMNodeDescriptor common, long compareNodeId, int diffType) + { + Integer diff = null; + + AVMNode compareAncNode = AVMDAOs.Instance().fAVMNodeDAO.getByID(compareNodeId).getAncestor(); + if (compareAncNode != null) + { + if (common.getId() == compareAncNode.getId()) + { + diff = diffType; + } + else if (common.isLayeredFile()) + { + // TODO review (alongside createSnapshot+COW) + diff = compareLayeredCommonAncestor(common, compareAncNode.getId(), diffType); + } + } + + return diff; + } + // compare node properties private int compareNodeProps(AVMNodeDescriptor srcDesc, AVMNodeDescriptor dstDesc) { @@ -1219,8 +1216,8 @@ public class AVMSyncServiceImpl implements AVMSyncService */ public void flatten(String layerPath, String underlyingPath) { - long start = System.currentTimeMillis(); - + long start = System.currentTimeMillis(); + if (layerPath == null || underlyingPath == null) { throw new AVMBadArgumentException("Illegal null path."); @@ -1235,12 +1232,12 @@ public class AVMSyncServiceImpl implements AVMSyncService { throw new AVMNotFoundException("Not found: " + underlyingPath); } - - flatten(layerNode, underlyingNode); - - if (logger.isDebugEnabled()) + + flatten(layerNode, underlyingNode); + + if (logger.isDebugEnabled()) { - logger.debug("Raw flatten: " + layerNode + " " + underlyingNode + " in " + (System.currentTimeMillis() - start) + " msecs"); + logger.debug("Raw flatten: " + layerNode + " " + underlyingNode + " in " + (System.currentTimeMillis() - start) + " msecs"); } } @@ -1251,9 +1248,9 @@ public class AVMSyncServiceImpl implements AVMSyncService */ private boolean flatten(AVMNodeDescriptor layer, AVMNodeDescriptor underlying) { - if (logger.isDebugEnabled()) + if (logger.isDebugEnabled()) { - logger.debug("flatten: " + layer + " " + underlying); + logger.debug("flatten: " + layer + " " + underlying); } if (!layer.isLayeredDirectory()) { @@ -1269,7 +1266,7 @@ public class AVMSyncServiceImpl implements AVMSyncService { return false; } - + Map layerListing = fAVMService.getDirectoryListingDirect(-1, layer.getPath(), true); // If the layer is empty (directly, that is) we're done. @@ -1277,29 +1274,29 @@ public class AVMSyncServiceImpl implements AVMSyncService { return true; } - + // Grab the listing Map underListing = fAVMService.getDirectoryListing(underlying, true); - + boolean flattened = true; for (String name : layerListing.keySet()) { AVMNodeDescriptor topNode = layerListing.get(name); AVMNodeDescriptor bottomNode = underListing.get(name); - - if (logger.isTraceEnabled()) - { - logger.trace("Trying to flatten out: " + name); - } - + + if (logger.isTraceEnabled()) + { + logger.trace("Trying to flatten out: " + name); + } + if (bottomNode == null) { - if (logger.isTraceEnabled()) - { - logger.trace("Can't flatten (no bottomNode): " + name); - } - + if (logger.isTraceEnabled()) + { + logger.trace("Can't flatten (no bottomNode): " + name); + } + flattened = false; continue; } @@ -1307,38 +1304,38 @@ public class AVMSyncServiceImpl implements AVMSyncService if (topNode.getId() == bottomNode.getId()) { fAVMRepository.flatten(layer.getPath(), name); - - if (logger.isTraceEnabled()) - { - logger.trace("Identity flattened: " + name); - } + + if (logger.isTraceEnabled()) + { + logger.trace("Identity flattened: " + name); + } } else { - if (bottomNode.isLayeredDirectory()) - { - AVMNodeDescriptor lookup = fAVMService.lookup(bottomNode.getIndirectionVersion(), bottomNode.getIndirection()); - if (lookup == null) - { - if (logger.isDebugEnabled()) - { - logger.debug("Can't flatten (no bottomNode indirection): " + name); - } - - flattened = false; - continue; - } - } - + if (bottomNode.isLayeredDirectory()) + { + AVMNodeDescriptor lookup = fAVMService.lookup(bottomNode.getIndirectionVersion(), bottomNode.getIndirection()); + if (lookup == null) + { + if (logger.isDebugEnabled()) + { + logger.debug("Can't flatten (no bottomNode indirection): " + name); + } + + flattened = false; + continue; + } + } + // Otherwise recursively flatten the children. if (flatten(topNode, bottomNode)) { fAVMRepository.flatten(layer.getPath(), name); - - if (logger.isTraceEnabled()) - { - logger.trace("Recursively flattened: " + name); - } + + if (logger.isTraceEnabled()) + { + logger.trace("Recursively flattened: " + name); + } } else { @@ -1348,7 +1345,7 @@ public class AVMSyncServiceImpl implements AVMSyncService } return flattened; } - + /** * Takes a layer, deletes it and recreates it pointing at the same underlying * node. Any changes in the layer are lost (except to history if the layer has been @@ -1360,8 +1357,8 @@ public class AVMSyncServiceImpl implements AVMSyncService */ public void resetLayer(String layerPath) { - long start = System.currentTimeMillis(); - + long start = System.currentTimeMillis(); + AVMNodeDescriptor desc = fAVMService.lookup(-1, layerPath); if (desc == null) { @@ -1373,11 +1370,11 @@ public class AVMSyncServiceImpl implements AVMSyncService { fAVMRepository.flatten(layerPath, name); } - - if (logger.isDebugEnabled()) - { - logger.debug("Raw resetLayer: " + layerPath + " in " + (System.currentTimeMillis() - start) + " msecs"); - } + + if (logger.isDebugEnabled()) + { + logger.debug("Raw resetLayer: " + layerPath + " in " + (System.currentTimeMillis() - start) + " msecs"); + } } /** diff --git a/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java index 416aa04d9b..0ae6127a1f 100644 --- a/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java @@ -35,7 +35,7 @@ public abstract class DirectoryNodeImpl extends AVMNodeImpl implements Directory protected DirectoryNodeImpl() { } - + /** * A pass through constructor. Called when a new concrete subclass * instance is created. @@ -67,22 +67,19 @@ public abstract class DirectoryNodeImpl extends AVMNodeImpl implements Directory ChildKey key = new ChildKey(this, name); ChildEntry newChild = new ChildEntryImpl(key, node); AVMDAOs.Instance().fChildEntryDAO.save(newChild); - - AVMDAOs.Instance().fChildEntryDAO.evict(newChild); - AVMDAOs.Instance().fAVMNodeDAO.evict(node); } - - /** - * Does this node directly contain the indicated node. - * - * @param node - * The node we are checking. - * @return Whether node is directly contained. - */ - public boolean directlyContains(AVMNode node) - { - return AVMDAOs.Instance().fChildEntryDAO.existsParentChild(this, node); - } + + /** + * Does this node directly contain the indicated node. + * + * @param node + * The node we are checking. + * @return Whether node is directly contained. + */ + public boolean directlyContains(AVMNode node) + { + return AVMDAOs.Instance().fChildEntryDAO.existsParentChild(this, node); + } /** * Lookup a child node by name. @@ -99,5 +96,5 @@ public abstract class DirectoryNodeImpl extends AVMNodeImpl implements Directory return null; } return new Pair(result.getFirst().getChild(), result.getSecond()); - } + } } diff --git a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java index b846086a54..e1e8a1a257 100644 --- a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java @@ -26,7 +26,6 @@ import java.util.SortedMap; import java.util.TreeMap; import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.hibernate.DbAccessControlListImpl; import org.alfresco.repo.security.permissions.ACLCopyMode; import org.alfresco.repo.security.permissions.ACLType; import org.alfresco.service.cmr.avm.AVMBadArgumentException; @@ -117,23 +116,23 @@ public class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements Layer DirectoryNode dir = (DirectoryNode) lookup.getCurrentNode(); if (dir.getAcl() != null) { - setAcl(DbAccessControlListImpl.createLayeredAcl(dir.getAcl().getId())); + setAcl(AVMDAOs.Instance().fAclDAO.createLayeredAcl(dir.getAcl().getId())); } else { // TODO: Will not pick up changes if we start with no permission on the target node - may need // to add - setAcl(DbAccessControlListImpl.createLayeredAcl(null)); + setAcl(AVMDAOs.Instance().fAclDAO.createLayeredAcl(null)); } } else { - setAcl(DbAccessControlListImpl.createLayeredAcl(null)); + setAcl(AVMDAOs.Instance().fAclDAO.createLayeredAcl(null)); } } else { - setAcl(DbAccessControlListImpl.createLayeredAcl(null)); + setAcl(AVMDAOs.Instance().fAclDAO.createLayeredAcl(null)); } } @@ -749,12 +748,12 @@ public class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements Layer AVMNodeDescriptor desc = entry.getChild().getDescriptor(mine.getPath(), name, mine.getIndirection(), mine.getIndirectionVersion()); return desc; } - // Don't check our underlying directory if we are opaque. + // Don't check our underlying directory if we are opaque. if (getOpacity()) { return null; } - // Not here so check our indirection. + // Not here so check our indirection. Lookup lookup = AVMRepository.GetInstance().lookupDirectory(mine.getIndirectionVersion(), mine.getIndirection()); if (lookup != null) { @@ -849,9 +848,9 @@ public class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements Layer */ public String toString(Lookup lPath) { - return "[LD:" + getId() + (lPath != null ? ":" + getUnderlying(lPath) : "") + "]"; + return "[LD:" + getId() + (lPath != null ? ":" + getUnderlying(lPath) : "") + "]"; } - + /** * Set the primary indirection. No COW. Cascade resetting of acls also does not COW * @@ -864,7 +863,7 @@ public class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements Layer { checkReadOnly(); } - + setIndirection(path); setPrimaryIndirection(true); @@ -882,22 +881,23 @@ public class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements Layer { if (getAcl() == null) { - acl = DbAccessControlListImpl.createLayeredAcl(dir.getAcl().getId()); + acl = AVMDAOs.Instance().fAclDAO.createLayeredAcl(dir.getAcl().getId()); } else { - acl = getAcl().getCopy(dir.getAcl().getId(), ACLCopyMode.REDIRECT); + + acl = AVMDAOs.Instance().fAclDAO.getDbAccessControlListCopy(getAcl().getId(), dir.getAcl().getId(), ACLCopyMode.REDIRECT); } } else { if (getAcl() == null) { - acl = DbAccessControlListImpl.createLayeredAcl(null); + acl = AVMDAOs.Instance().fAclDAO.createLayeredAcl(null); } else { - acl = getAcl().getCopy(null, ACLCopyMode.REDIRECT); + acl = AVMDAOs.Instance().fAclDAO.getDbAccessControlListCopy(getAcl().getId(), null, ACLCopyMode.REDIRECT); } } } @@ -906,17 +906,16 @@ public class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements Layer } else { - if (getAcl().getAclType() == ACLType.LAYERED) { DbAccessControlList acl = null; if (getAcl() == null) { - acl = DbAccessControlListImpl.createLayeredAcl(null); + acl = AVMDAOs.Instance().fAclDAO.createLayeredAcl(null); } else { - acl = getAcl().getCopy(null, ACLCopyMode.REDIRECT); + acl = AVMDAOs.Instance().fAclDAO.getDbAccessControlListCopy(getAcl().getId(), null, ACLCopyMode.REDIRECT); } setAclAndInherit(this, acl, null); } @@ -947,7 +946,7 @@ public class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements Layer } else { - childNode.setAclAndInherit(childNode, acl.getCopy(acl.getId(), ACLCopyMode.REDIRECT), key); + childNode.setAclAndInherit(childNode, AVMDAOs.Instance().fAclDAO.getDbAccessControlListCopy(acl.getId(), acl.getId(), ACLCopyMode.REDIRECT), key); } } else @@ -958,7 +957,7 @@ public class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements Layer } else { - childNode.setAclAndInherit(childNode, currentAcl.getCopy(acl.getId(), ACLCopyMode.REDIRECT), key); + childNode.setAclAndInherit(childNode, AVMDAOs.Instance().fAclDAO.getDbAccessControlListCopy(currentAcl.getId(), acl.getId(), ACLCopyMode.REDIRECT), key); } } } @@ -974,7 +973,7 @@ public class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements Layer } else { - childNode.setAcl(acl.getCopy(acl.getId(), ACLCopyMode.REDIRECT)); + childNode.setAcl(AVMDAOs.Instance().fAclDAO.getDbAccessControlListCopy(acl.getId(), acl.getId(), ACLCopyMode.REDIRECT)); } } else @@ -985,7 +984,7 @@ public class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements Layer } else { - childNode.setAcl(currentAcl.getCopy(acl.getId(), ACLCopyMode.REDIRECT)); + childNode.setAcl(AVMDAOs.Instance().fAclDAO.getDbAccessControlListCopy(currentAcl.getId(), acl.getId(), ACLCopyMode.REDIRECT)); } } diff --git a/source/java/org/alfresco/repo/avm/LayeredFileNodeImpl.java b/source/java/org/alfresco/repo/avm/LayeredFileNodeImpl.java index c8f8cadd68..d4500265e0 100644 --- a/source/java/org/alfresco/repo/avm/LayeredFileNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/LayeredFileNodeImpl.java @@ -19,7 +19,6 @@ package org.alfresco.repo.avm; import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.hibernate.DbAccessControlListImpl; import org.alfresco.repo.security.permissions.ACLCopyMode; import org.alfresco.service.cmr.avm.AVMException; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; @@ -38,19 +37,19 @@ public class LayeredFileNodeImpl extends FileNodeImpl implements LayeredFileNode * The indirection. */ private String fIndirection; - + /** * The indirection version. */ private int fIndirectionVersion; - + /** - * Default constructor. + * Default constructor. */ public LayeredFileNodeImpl() { } - + /** * Basically a copy constructor. Used when a branch is created from a layered file. * @@ -62,17 +61,17 @@ public class LayeredFileNodeImpl extends FileNodeImpl implements LayeredFileNode public LayeredFileNodeImpl(LayeredFileNode other, AVMStore store, Long parentAcl, ACLCopyMode mode) { super(store); - setIndirection(other.getIndirection()); - setIndirectionVersion(-1); + setIndirection(other.getIndirection()); + setIndirectionVersion(-1); setVersionID(other.getVersionID() + 1); copyACLs(other, parentAcl, mode); copyCreationAndOwnerBasicAttributes(other); - AVMDAOs.Instance().fAVMNodeDAO.save(this); - - copyProperties(other); - copyAspects(other); + AVMDAOs.Instance().fAVMNodeDAO.save(this); + + copyProperties(other); + copyAspects(other); } /** @@ -86,8 +85,8 @@ public class LayeredFileNodeImpl extends FileNodeImpl implements LayeredFileNode public LayeredFileNodeImpl(String indirection, AVMStore store, DbAccessControlList acl) { super(store); - setIndirection(indirection); - setIndirectionVersion(-1); + setIndirection(indirection); + setIndirectionVersion(-1); setVersionID(1); if (acl != null) @@ -104,21 +103,21 @@ public class LayeredFileNodeImpl extends FileNodeImpl implements LayeredFileNode AVMNode node = lookup.getCurrentNode(); if (node.getAcl() != null) { - setAcl(DbAccessControlListImpl.createLayeredAcl(node.getAcl().getId())); + setAcl(AVMDAOs.Instance().fAclDAO.createLayeredAcl(node.getAcl().getId())); } else { - setAcl(DbAccessControlListImpl.createLayeredAcl(null)); + setAcl(AVMDAOs.Instance().fAclDAO.createLayeredAcl(null)); } } else { - setAcl(DbAccessControlListImpl.createLayeredAcl(null)); + setAcl(AVMDAOs.Instance().fAclDAO.createLayeredAcl(null)); } } else { - setAcl(DbAccessControlListImpl.createLayeredAcl(null)); + setAcl(AVMDAOs.Instance().fAclDAO.createLayeredAcl(null)); } } } @@ -132,7 +131,7 @@ public class LayeredFileNodeImpl extends FileNodeImpl implements LayeredFileNode public AVMNode copy(Lookup lPath) { // LayeredFileNodes are always copied. - Lookup lookup = AVMRepository.GetInstance().lookup(-1, getIndirection(), false); + Lookup lookup = AVMRepository.GetInstance().lookup(-1, getIndirection(), false); if (lookup == null) { throw new AVMException("Unbacked layered file node."); @@ -143,14 +142,14 @@ public class LayeredFileNodeImpl extends FileNodeImpl implements LayeredFileNode throw new AVMException("Unbacked layered file node."); } DirectoryNode dir = lPath.getCurrentNodeDirectory(); - Long parentAclId = null; + DbAccessControlList parentAcl = null; if ((dir != null) && (dir.getAcl() != null)) { - parentAclId = dir.getAcl().getId(); + parentAcl = dir.getAcl(); } // TODO This doesn't look quite right. PlainFileNodeImpl newMe = new PlainFileNodeImpl(lPath.getAVMStore(), getBasicAttributes(), getContentData(lPath), indirect.getProperties(), indirect.getAspects(), indirect - .getAcl(), getVersionID(), parentAclId, ACLCopyMode.COPY); + .getAcl(), getVersionID(), parentAcl, ACLCopyMode.COPY); newMe.setAncestor(this); return newMe; } @@ -174,7 +173,7 @@ public class LayeredFileNodeImpl extends FileNodeImpl implements LayeredFileNode */ public String getUnderlying(Lookup lookup) { - return getIndirection(); + return getIndirection(); } /** @@ -186,7 +185,7 @@ public class LayeredFileNodeImpl extends FileNodeImpl implements LayeredFileNode */ public String toString(Lookup lPath) { - return "[LF:" + getId() + ":" + getIndirection() + "]"; + return "[LF:" + getId() + ":" + getIndirection() + "]"; } /** @@ -244,7 +243,7 @@ public class LayeredFileNodeImpl extends FileNodeImpl implements LayeredFileNode BasicAttributes attrs = getBasicAttributes(); String path = parentPath.endsWith("/") ? parentPath + name : parentPath + "/" + name; return new AVMNodeDescriptor(path, name, AVMNodeType.LAYERED_FILE, attrs.getCreator(), attrs.getOwner(), attrs.getLastModifier(), attrs.getCreateDate(), - attrs.getModDate(), attrs.getAccessDate(), getId(), getGuid(), getVersionID(), getIndirection(), getIndirectionVersion(), false, -1, false, 0, -1); + attrs.getModDate(), attrs.getAccessDate(), getId(), getGuid(), getVersionID(), getIndirection(), getIndirectionVersion(), false, -1, false, 0, -1); } /** @@ -286,16 +285,16 @@ public class LayeredFileNodeImpl extends FileNodeImpl implements LayeredFileNode */ public ContentData getContentData(Lookup lPath) { - Lookup lookup = null; - if (lPath != null) - { - lookup = lPath.getAVMStore().getAVMRepository().lookup(getUnderlyingVersion(lPath), getIndirection(), false); - } - else - { - lookup = AVMRepository.GetInstance().lookup(getUnderlyingVersion(null), getIndirection(), false); - } - + Lookup lookup = null; + if (lPath != null) + { + lookup = lPath.getAVMStore().getAVMRepository().lookup(getUnderlyingVersion(lPath), getIndirection(), false); + } + else + { + lookup = AVMRepository.GetInstance().lookup(getUnderlyingVersion(null), getIndirection(), false); + } + if (lookup == null) { throw new AVMException("Invalid target."); @@ -316,11 +315,11 @@ public class LayeredFileNodeImpl extends FileNodeImpl implements LayeredFileNode */ public int getUnderlyingVersion(Lookup lookup) { - if ((lookup != null) && (lookup.getVersion() == -1)) + if ((lookup != null) && (lookup.getVersion() == -1)) { return -1; } - return getIndirectionVersion(); + return getIndirectionVersion(); } /* diff --git a/source/java/org/alfresco/repo/avm/OrphanReaper.java b/source/java/org/alfresco/repo/avm/OrphanReaper.java index 682a54cc5a..ca38bcbdc0 100644 --- a/source/java/org/alfresco/repo/avm/OrphanReaper.java +++ b/source/java/org/alfresco/repo/avm/OrphanReaper.java @@ -83,11 +83,6 @@ public class OrphanReaper */ private TransactionService fTransactionService; - /** - * The Session Factory - */ - private SessionFactory fSessionFactory; - /** * Active base sleep interval. */ @@ -163,16 +158,6 @@ public class OrphanReaper fTransactionService = transactionService; } - /** - * Set the hibernate session factory. (For Spring.) - * - * @param sessionFactory - */ - public void setSessionFactory(SessionFactory sessionFactory) - { - fSessionFactory = sessionFactory; - } - /** * Set the maximum size of the queue of purgeable nodes. * diff --git a/source/java/org/alfresco/repo/avm/PlainFileNodeImpl.java b/source/java/org/alfresco/repo/avm/PlainFileNodeImpl.java index e450c61541..85c2524846 100644 --- a/source/java/org/alfresco/repo/avm/PlainFileNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/PlainFileNodeImpl.java @@ -117,17 +117,16 @@ public class PlainFileNodeImpl extends FileNodeImpl implements PlainFileNode Map props, Set aspects, DbAccessControlList acl, - int versionID, Long parentAcl, ACLCopyMode mode) + int versionID, + DbAccessControlList parentAcl, + ACLCopyMode mode) { super(store); setContentData(content); setBasicAttributes(attrs); setVersionID(versionID + 1); - if (acl != null) - { - setAcl(acl.getCopy(parentAcl, mode)); - } + copyACLs(acl, parentAcl, mode); AVMDAOs.Instance().fAVMNodeDAO.save(this); diff --git a/source/java/org/alfresco/repo/avm/actions/AVMUndoSandboxListAction.java b/source/java/org/alfresco/repo/avm/actions/AVMUndoSandboxListAction.java index 47535b906c..ec8b2c3016 100644 --- a/source/java/org/alfresco/repo/avm/actions/AVMUndoSandboxListAction.java +++ b/source/java/org/alfresco/repo/avm/actions/AVMUndoSandboxListAction.java @@ -1,144 +1,144 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.avm.actions; - -import java.util.List; - -import org.alfresco.repo.action.ParameterDefinitionImpl; -import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; -import org.alfresco.repo.avm.AVMNodeConverter; -import org.alfresco.repo.avm.util.AVMUtil; -import org.alfresco.service.cmr.action.Action; -import org.alfresco.service.cmr.action.ParameterDefinition; -import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.cmr.avm.AVMService; -import org.alfresco.service.cmr.avm.locking.AVMLockingService; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.util.Pair; -import org.alfresco.wcm.util.WCMUtil; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Undos a list of changed nodes in a user sandbox. The set of nodes to undo is - * passed in as a packed string (Obtained by VersionPathStuffer). - * The actionedUponNodeRef is a dummy and can be null. - * @author britt - * - * @deprecated see org.alfresco.wcm.actions.WCMSandboxRevertListAction or org.alfresco.wcm.SandboxService.revert - */ -public class AVMUndoSandboxListAction extends ActionExecuterAbstractBase -{ - private static Log fgLogger = LogFactory.getLog(AVMUndoSandboxListAction.class); - - public static final String NAME = "avm-undo-list"; - // The encoded list of nodes. - public static final String PARAM_NODE_LIST = "node-list"; - - /** - * The AVM Service reference. - */ - private AVMService fAVMService; - - /** - * The AVM Locking Service reference. - */ - private AVMLockingService fAVMLockingService; - - public void setAvmService(AVMService service) - { - fAVMService = service; - } - - public void setAvmLockingService(AVMLockingService service) - { - fAVMLockingService = service; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef) - */ - @SuppressWarnings("unchecked") - @Override - protected void executeImpl(Action action, NodeRef actionedUponNodeRef) - { - List> versionPaths = - (List>)action.getParameterValue(PARAM_NODE_LIST); - for (Pair item : versionPaths) - { - String avmPath = item.getSecond(); - AVMNodeDescriptor desc = fAVMService.lookup(-1, avmPath, true); - if (desc == null) - { - continue; - } - String [] parentChild = AVMNodeConverter.SplitBase(avmPath); - if (parentChild.length != 2) - { - continue; - } - AVMNodeDescriptor parent = fAVMService.lookup(-1, parentChild[0], true); - if (parent.isLayeredDirectory()) - { - if (fgLogger.isDebugEnabled()) - fgLogger.debug("reverting " + parentChild[1] + " in " + parentChild[0]); - fAVMService.makeTransparent(parentChild[0], parentChild[1]); - } - - if (desc.isFile() || desc.isDeletedFile()) - { - String parts[] = AVMUtil.splitPath(avmPath); - String avmStore = parts[0]; - String path = parts[1]; // store relative path - - String webProject = WCMUtil.getWebProject(fAVMService, avmStore); - if (webProject != null) - { - if (fgLogger.isDebugEnabled()) - { - fgLogger.debug("unlocking file " + path + " in web project " + webProject); - } - - if (fAVMLockingService.getLock(webProject, path) != null) - { - fAVMLockingService.removeLock(webProject, path); - } - else - { - fgLogger.warn("expected file " + path + " in " + webProject + " to be locked"); - } - } - } - } - } - - /* (non-Javadoc) - * @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List) - */ - @Override - protected void addParameterDefinitions(List paramList) - { - paramList.add( - new ParameterDefinitionImpl(PARAM_NODE_LIST, - DataTypeDefinition.ANY, - true, - getParamDisplayLabel(PARAM_NODE_LIST))); - } -} +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.avm.actions; + +import java.util.List; + +import org.alfresco.repo.action.ParameterDefinitionImpl; +import org.alfresco.repo.action.executer.ActionExecuterAbstractBase; +import org.alfresco.repo.avm.AVMNodeConverter; +import org.alfresco.repo.avm.util.AVMUtil; +import org.alfresco.service.cmr.action.Action; +import org.alfresco.service.cmr.action.ParameterDefinition; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.avm.locking.AVMLockingService; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.Pair; +import org.alfresco.wcm.util.WCMUtil; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Undos a list of changed nodes in a user sandbox. The set of nodes to undo is + * passed in as a packed string (Obtained by VersionPathStuffer). + * The actionedUponNodeRef is a dummy and can be null. + * @author britt + * + * @deprecated see org.alfresco.wcm.actions.WCMSandboxRevertListAction or org.alfresco.wcm.SandboxService.revert + */ +public class AVMUndoSandboxListAction extends ActionExecuterAbstractBase +{ + private static Log fgLogger = LogFactory.getLog(AVMUndoSandboxListAction.class); + + public static final String NAME = "avm-undo-list"; + // The encoded list of nodes. + public static final String PARAM_NODE_LIST = "node-list"; + + /** + * The AVM Service reference. + */ + private AVMService fAVMService; + + /** + * The AVM Locking Service reference. + */ + private AVMLockingService fAVMLockingService; + + public void setAvmService(AVMService service) + { + fAVMService = service; + } + + public void setAvmLockingService(AVMLockingService service) + { + fAVMLockingService = service; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action, org.alfresco.service.cmr.repository.NodeRef) + */ + @SuppressWarnings("unchecked") + @Override + protected void executeImpl(Action action, NodeRef actionedUponNodeRef) + { + List> versionPaths = + (List>)action.getParameterValue(PARAM_NODE_LIST); + for (Pair item : versionPaths) + { + String avmPath = item.getSecond(); + AVMNodeDescriptor desc = fAVMService.lookup(-1, avmPath, true); + if (desc == null) + { + continue; + } + String [] parentChild = AVMNodeConverter.SplitBase(avmPath); + if (parentChild.length != 2) + { + continue; + } + AVMNodeDescriptor parent = fAVMService.lookup(-1, parentChild[0], true); + if (parent.isLayeredDirectory()) + { + if (fgLogger.isDebugEnabled()) + fgLogger.debug("reverting " + parentChild[1] + " in " + parentChild[0]); + fAVMService.makeTransparent(parentChild[0], parentChild[1]); + } + + if (desc.isFile() || desc.isDeletedFile()) + { + String parts[] = AVMUtil.splitPath(avmPath); + String avmStore = parts[0]; + String path = parts[1]; // store relative path + + String webProject = WCMUtil.getWebProject(fAVMService, avmStore); + if (webProject != null) + { + if (fgLogger.isDebugEnabled()) + { + fgLogger.debug("unlocking file " + path + " in web project " + webProject); + } + + if (fAVMLockingService.getLockOwner(webProject, path) != null) + { + fAVMLockingService.removeLock(webProject, path); + } + else + { + fgLogger.warn("expected file " + path + " in " + webProject + " to be locked"); + } + } + } + } + } + + /* (non-Javadoc) + * @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List) + */ + @Override + protected void addParameterDefinitions(List paramList) + { + paramList.add( + new ParameterDefinitionImpl(PARAM_NODE_LIST, + DataTypeDefinition.ANY, + true, + getParamDisplayLabel(PARAM_NODE_LIST))); + } +} diff --git a/source/java/org/alfresco/repo/avm/ibatis/AVMNodeDAOIbatis.java b/source/java/org/alfresco/repo/avm/ibatis/AVMNodeDAOIbatis.java index b050023fb3..4d4ffe57c6 100644 --- a/source/java/org/alfresco/repo/avm/ibatis/AVMNodeDAOIbatis.java +++ b/source/java/org/alfresco/repo/avm/ibatis/AVMNodeDAOIbatis.java @@ -49,9 +49,7 @@ import org.alfresco.repo.domain.DbAccessControlList; import org.alfresco.repo.domain.PropertyValue; import org.alfresco.repo.domain.avm.AVMNodeEntity; import org.alfresco.repo.domain.avm.AVMVersionRootEntity; -import org.alfresco.repo.domain.hibernate.DbAccessControlListImpl; -import org.alfresco.service.namespace.QName; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; +import org.alfresco.service.namespace.QName; /** * iBATIS DAO wrapper for AVMNode @@ -59,7 +57,7 @@ import org.springframework.orm.hibernate3.support.HibernateDaoSupport; * @author janv * */ -class AVMNodeDAOIbatis extends HibernateDaoSupport implements AVMNodeDAO +class AVMNodeDAOIbatis implements AVMNodeDAO { /* (non-Javadoc) * @see org.alfresco.repo.avm.AVMNodeDAO#save(org.alfresco.repo.avm.AVMNode) @@ -81,17 +79,17 @@ class AVMNodeDAOIbatis extends HibernateDaoSupport implements AVMNodeDAO /* (non-Javadoc) * @see org.alfresco.repo.avm.AVMNodeDAO#createAspect(long, long) */ - public void createAspect(long nodeId, QName aspectQName) + public void createAspect(long nodeId, QName aspectQName) { - AVMDAOs.Instance().newAVMNodeDAO.createAspect(nodeId, aspectQName); + AVMDAOs.Instance().newAVMNodeDAO.createAspect(nodeId, aspectQName); } /* (non-Javadoc) * @see org.alfresco.repo.avm.AVMNodeDAO#deleteAspect(long, long) */ - public void deleteAspect(long nodeId, QName aspectQName) + public void deleteAspect(long nodeId, QName aspectQName) { - AVMDAOs.Instance().newAVMNodeDAO.deleteAspect(nodeId, aspectQName); + AVMDAOs.Instance().newAVMNodeDAO.deleteAspect(nodeId, aspectQName); } /* (non-Javadoc) @@ -105,25 +103,25 @@ class AVMNodeDAOIbatis extends HibernateDaoSupport implements AVMNodeDAO /* (non-Javadoc) * @see org.alfresco.repo.avm.AVMNodeDAO#getAspects(long) */ - public Set getAspects(long nodeId) + public Set getAspects(long nodeId) { - return AVMDAOs.Instance().newAVMNodeDAO.getAspects(nodeId); + return AVMDAOs.Instance().newAVMNodeDAO.getAspects(nodeId); } /* (non-Javadoc) - * @see org.alfresco.repo.avm.AVMNodeDAO#createOrUpdateProperty(long, QName, org.alfresco.repo.domain.PropertyValue) + * @see org.alfresco.repo.avm.AVMNodeDAO#createOrUpdateProperty(long, QName, org.alfresco.repo.domain.PropertyValue) */ - public void createOrUpdateProperty(long nodeId, QName qname, PropertyValue value) + public void createOrUpdateProperty(long nodeId, QName qname, PropertyValue value) { - AVMDAOs.Instance().newAVMNodeDAO.createOrUpdateNodeProperty(nodeId, qname, value); + AVMDAOs.Instance().newAVMNodeDAO.createOrUpdateNodeProperty(nodeId, qname, value); } /* (non-Javadoc) - * @see org.alfresco.repo.avm.AVMNodeDAO#deleteProperty(long, QName) + * @see org.alfresco.repo.avm.AVMNodeDAO#deleteProperty(long, QName) */ - public void deleteProperty(long nodeId, QName propQName) + public void deleteProperty(long nodeId, QName propQName) { - AVMDAOs.Instance().newAVMNodeDAO.deleteNodeProperty(nodeId, propQName); + AVMDAOs.Instance().newAVMNodeDAO.deleteNodeProperty(nodeId, propQName); } /* (non-Javadoc) @@ -137,9 +135,9 @@ class AVMNodeDAOIbatis extends HibernateDaoSupport implements AVMNodeDAO /* (non-Javadoc) * @see org.alfresco.repo.avm.AVMNodeDAO#getProperties(long) */ - public Map getProperties(long nodeId) + public Map getProperties(long nodeId) { - return AVMDAOs.Instance().newAVMNodeDAO.getNodeProperties(nodeId); + return AVMDAOs.Instance().newAVMNodeDAO.getNodeProperties(nodeId); } /* (non-Javadoc) @@ -173,21 +171,21 @@ class AVMNodeDAOIbatis extends HibernateDaoSupport implements AVMNodeDAO */ public void update(AVMNode node) { - AVMNodeEntity nodeEntity = convertNodeToNodeEntity(node); - AVMDAOs.Instance().newAVMNodeDAO.updateNode(nodeEntity); - ((AVMNodeImpl)node).setVers(nodeEntity.getVers()); + AVMNodeEntity nodeEntity = convertNodeToNodeEntity(node); + AVMDAOs.Instance().newAVMNodeDAO.updateNode(nodeEntity); + ((AVMNodeImpl)node).setVers(nodeEntity.getVers()); } - /** - * TODO review - * - * @deprecated - */ - public void updateModTimeAndGuid(AVMNode node) + /** + * TODO review + * + * @deprecated + */ + public void updateModTimeAndGuid(AVMNode node) { - AVMNodeEntity nodeEntity = convertNodeToNodeEntity(node); - AVMDAOs.Instance().newAVMNodeDAO.updateNodeModTimeAndGuid(nodeEntity); - ((AVMNodeImpl)node).setVers(nodeEntity.getVers()); + AVMNodeEntity nodeEntity = convertNodeToNodeEntity(node); + AVMDAOs.Instance().newAVMNodeDAO.updateNodeModTimeAndGuid(nodeEntity); + ((AVMNodeImpl)node).setVers(nodeEntity.getVers()); } /* (non-Javadoc) @@ -362,7 +360,7 @@ class AVMNodeDAOIbatis extends HibernateDaoSupport implements AVMNodeDAO nodeEntity.setType(node.getType()); nodeEntity.setVersion(new Long(node.getVersionID())); - nodeEntity.setVers(((AVMNodeImpl)node).getVers()); + nodeEntity.setVers(((AVMNodeImpl)node).getVers()); nodeEntity.setAclId((node.getAcl() == null ? null : node.getAcl().getId())); nodeEntity.setGuid(node.getGuid()); @@ -465,7 +463,7 @@ class AVMNodeDAOIbatis extends HibernateDaoSupport implements AVMNodeDAO node.setIsRoot(nodeEntity.isRoot()); node.setGuid(nodeEntity.getGuid()); node.setVersionID(nodeEntity.getVersion().intValue()); - node.setVers(nodeEntity.getVers()); + node.setVers(nodeEntity.getVers()); BasicAttributes ba = new BasicAttributesImpl(); ba.setAccessDate(nodeEntity.getAccessDate()); @@ -491,7 +489,7 @@ class AVMNodeDAOIbatis extends HibernateDaoSupport implements AVMNodeDAO DbAccessControlList acl = null; if (nodeEntity.getAclId() != null) { - acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, nodeEntity.getAclId()); + acl = AVMDAOs.Instance().fAclDAO.getDbAccessControlList(nodeEntity.getAclId()); } node.setAcl(acl); diff --git a/source/java/org/alfresco/repo/avm/ibatis/AVMStoreDAOIbatis.java b/source/java/org/alfresco/repo/avm/ibatis/AVMStoreDAOIbatis.java index 01f1b8fb81..f4228b6433 100644 --- a/source/java/org/alfresco/repo/avm/ibatis/AVMStoreDAOIbatis.java +++ b/source/java/org/alfresco/repo/avm/ibatis/AVMStoreDAOIbatis.java @@ -29,15 +29,13 @@ import org.alfresco.repo.avm.AVMStoreImpl; import org.alfresco.repo.avm.DirectoryNode; import org.alfresco.repo.domain.DbAccessControlList; import org.alfresco.repo.domain.avm.AVMStoreEntity; -import org.alfresco.repo.domain.hibernate.DbAccessControlListImpl; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; /** * iBATIS DAO wrapper for AVMStore * * @author janv */ -class AVMStoreDAOIbatis extends HibernateDaoSupport implements AVMStoreDAO +class AVMStoreDAOIbatis implements AVMStoreDAO { /* (non-Javadoc) * @see org.alfresco.repo.avm.AVMStoreDAO#save(org.alfresco.repo.avm.AVMStore) @@ -76,7 +74,7 @@ class AVMStoreDAOIbatis extends HibernateDaoSupport implements AVMStoreDAO public AVMStore getByName(String name) { AVMStoreEntity storeEntity = AVMDAOs.Instance().newAVMStoreDAO.getStore(name); - return convertStoreEntityToStore(storeEntity); + return convertStoreEntityToStore(storeEntity); } /* (non-Javadoc) @@ -85,7 +83,7 @@ class AVMStoreDAOIbatis extends HibernateDaoSupport implements AVMStoreDAO public AVMStore getByRoot(AVMNode root) { AVMStoreEntity storeEntity = AVMDAOs.Instance().newAVMStoreDAO.getStoreByRoot(root.getId()); - return convertStoreEntityToStore(storeEntity); + return convertStoreEntityToStore(storeEntity); } /* (non-Javadoc) @@ -93,9 +91,9 @@ class AVMStoreDAOIbatis extends HibernateDaoSupport implements AVMStoreDAO */ public void update(AVMStore store) { - AVMStoreEntity storeEntity = convertStoreToStoreEntity(store); - AVMDAOs.Instance().newAVMStoreDAO.updateStore(storeEntity); - ((AVMStoreImpl)store).setVers(storeEntity.getVers()); + AVMStoreEntity storeEntity = convertStoreToStoreEntity(store); + AVMDAOs.Instance().newAVMStoreDAO.updateStore(storeEntity); + ((AVMStoreImpl)store).setVers(storeEntity.getVers()); } /* (non-Javadoc) @@ -106,33 +104,33 @@ class AVMStoreDAOIbatis extends HibernateDaoSupport implements AVMStoreDAO AVMStoreEntity storeEntity = AVMDAOs.Instance().newAVMStoreDAO.getStore(id); return convertStoreEntityToStore(storeEntity); } - + /* (non-Javadoc) * @see org.alfresco.repo.avm.AVMStoreDAO#invalidateCache() */ public void invalidateCache() { - AVMDAOs.Instance().newAVMStoreDAO.clearStoreEntityCache(); + AVMDAOs.Instance().newAVMStoreDAO.clearStoreEntityCache(); } private AVMStore convertStoreEntityToStore(AVMStoreEntity storeEntity) { - if (storeEntity == null) - { - return null; - } - + if (storeEntity == null) + { + return null; + } + AVMStoreImpl store = new AVMStoreImpl(); store.setId(storeEntity.getId()); store.setName(storeEntity.getName()); store.setNextVersionID(storeEntity.getVersion().intValue()); - store.setVers(storeEntity.getVers()); + store.setVers(storeEntity.getVers()); DbAccessControlList acl = null; if (storeEntity.getAclId() != null) { - acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, storeEntity.getAclId()); + acl = AVMDAOs.Instance().fAclDAO.getDbAccessControlList(storeEntity.getAclId()); } store.setStoreAcl(acl); @@ -150,7 +148,7 @@ class AVMStoreDAOIbatis extends HibernateDaoSupport implements AVMStoreDAO storeEntity.setName(store.getName()); storeEntity.setRootNodeId(store.getRoot().getId()); storeEntity.setVersion(new Long(store.getNextVersionID())); - storeEntity.setVers(((AVMStoreImpl)store).getVers()); + storeEntity.setVers(((AVMStoreImpl)store).getVers()); storeEntity.setAclId((store.getStoreAcl() == null ? null : store.getStoreAcl().getId())); return storeEntity; diff --git a/source/java/org/alfresco/repo/avm/ibatis/AVMStorePropertyDAOIbatis.java b/source/java/org/alfresco/repo/avm/ibatis/AVMStorePropertyDAOIbatis.java index 44a441fdcc..d81a183214 100644 --- a/source/java/org/alfresco/repo/avm/ibatis/AVMStorePropertyDAOIbatis.java +++ b/source/java/org/alfresco/repo/avm/ibatis/AVMStorePropertyDAOIbatis.java @@ -18,28 +18,21 @@ package org.alfresco.repo.avm.ibatis; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.Map; import org.alfresco.repo.avm.AVMDAOs; import org.alfresco.repo.avm.AVMStore; import org.alfresco.repo.avm.AVMStoreProperty; import org.alfresco.repo.avm.AVMStorePropertyDAO; -import org.alfresco.repo.avm.AVMStorePropertyImpl; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.qname.QNameDAO; -import org.alfresco.repo.domain.avm.AVMStorePropertyEntity; +import org.alfresco.repo.domain.PropertyValue; import org.alfresco.service.namespace.QName; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; /** * iBATIS DAO wrapper for AVMStoreProperty * * @author janv */ -class AVMStorePropertyDAOIbatis extends HibernateDaoSupport implements AVMStorePropertyDAO +class AVMStorePropertyDAOIbatis implements AVMStorePropertyDAO { /* (non-Javadoc) @@ -47,23 +40,23 @@ class AVMStorePropertyDAOIbatis extends HibernateDaoSupport implements AVMStoreP */ public void save(AVMStoreProperty prop) { - AVMDAOs.Instance().newAVMStoreDAO.createOrUpdateStoreProperty(prop.getStore().getId(), prop.getQname(), prop.getValue()); + AVMDAOs.Instance().newAVMStoreDAO.createOrUpdateStoreProperty(prop.getStore().getId(), prop.getQname(), prop.getValue()); } /* (non-Javadoc) * @see org.alfresco.repo.avm.AVMStorePropertyDAO#get(org.alfresco.repo.avm.AVMStore, org.alfresco.service.namespace.QName) */ - public PropertyValue get(AVMStore store, QName name) + public PropertyValue get(AVMStore store, QName name) { - return AVMDAOs.Instance().newAVMStoreDAO.getStoreProperty(store.getId(), name); + return AVMDAOs.Instance().newAVMStoreDAO.getStoreProperty(store.getId(), name); } /* (non-Javadoc) * @see org.alfresco.repo.avm.AVMStorePropertyDAO#get(org.alfresco.repo.avm.AVMStore) */ - public Map get(AVMStore store) + public Map get(AVMStore store) { - return AVMDAOs.Instance().newAVMStoreDAO.getStoreProperties(store.getId()); + return AVMDAOs.Instance().newAVMStoreDAO.getStoreProperties(store.getId()); } /** @@ -72,7 +65,7 @@ class AVMStorePropertyDAOIbatis extends HibernateDaoSupport implements AVMStoreP * @param keyPattern An sql 'like' pattern wrapped up in a QName * @return A List of matching AVMStoreProperties. */ - public Map queryByKeyPattern(AVMStore store, QName keyPattern) + public Map queryByKeyPattern(AVMStore store, QName keyPattern) { // Get the URI and LocalName parts String uri = keyPattern.getNamespaceURI(); @@ -86,7 +79,7 @@ class AVMStorePropertyDAOIbatis extends HibernateDaoSupport implements AVMStoreP localName = "%"; } - return AVMDAOs.Instance().newAVMStoreDAO.getStorePropertiesByStoreAndKeyPattern(store.getId(), uri, localName); + return AVMDAOs.Instance().newAVMStoreDAO.getStorePropertiesByStoreAndKeyPattern(store.getId(), uri, localName); } /** @@ -94,7 +87,7 @@ class AVMStorePropertyDAOIbatis extends HibernateDaoSupport implements AVMStoreP * @param keyPattern The sql 'like' pattern wrapped up in a QName * @return A List of match AVMStoreProperties. */ - public Map> queryByKeyPattern(QName keyPattern) + public Map> queryByKeyPattern(QName keyPattern) { // Get the URI and LocalName parts String uri = keyPattern.getNamespaceURI(); @@ -108,7 +101,7 @@ class AVMStorePropertyDAOIbatis extends HibernateDaoSupport implements AVMStoreP localName = "%"; } - return AVMDAOs.Instance().newAVMStoreDAO.getStorePropertiesByKeyPattern(uri, localName); + return AVMDAOs.Instance().newAVMStoreDAO.getStorePropertiesByKeyPattern(uri, localName); } /* (non-Javadoc) @@ -124,7 +117,7 @@ class AVMStorePropertyDAOIbatis extends HibernateDaoSupport implements AVMStoreP */ public void delete(AVMStore store, QName name) { - AVMDAOs.Instance().newAVMStoreDAO.deleteStoreProperty(store.getId(), name); + AVMDAOs.Instance().newAVMStoreDAO.deleteStoreProperty(store.getId(), name); } /* (non-Javadoc) diff --git a/source/java/org/alfresco/repo/avm/locking/AVMLockingBootstrap.java b/source/java/org/alfresco/repo/avm/locking/AVMLockingBootstrap.java deleted file mode 100644 index 21256fcf6d..0000000000 --- a/source/java/org/alfresco/repo/avm/locking/AVMLockingBootstrap.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.avm.locking; - -import org.alfresco.service.cmr.avm.locking.AVMLockingService; -import org.alfresco.service.transaction.TransactionService; -import org.springframework.extensions.surf.util.AbstractLifecycleBean; -import org.springframework.context.ApplicationEvent; - -/** - * Bootstrap for AVM Locking Service. - * - * @author britt - */ -public class AVMLockingBootstrap extends AbstractLifecycleBean -{ - private AVMLockingService fLockingService; - private TransactionService transactionService; - - public void setAvmLockingService(AVMLockingService service) - { - fLockingService = service; - } - - public void setTransactionService(TransactionService transactionService) - { - this.transactionService = transactionService; - } - - @Override - protected void onBootstrap(ApplicationEvent event) - { - // Do nothing if the repo is read-only - if (transactionService.isReadOnly()) - { - return; - } - - if (fLockingService instanceof AVMLockingServiceImpl) - { - ((AVMLockingServiceImpl) fLockingService).init(); - } - } - - @Override - protected void onShutdown(ApplicationEvent event) - { - // Do nothing. - } -} diff --git a/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java index e18e12897c..aedbe52c93 100644 --- a/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java +++ b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceImpl.java @@ -19,21 +19,21 @@ package org.alfresco.repo.avm.locking; +import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.alfresco.model.WCMAppModel; -import org.alfresco.repo.attributes.Attribute; -import org.alfresco.repo.attributes.MapAttributeValue; -import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.service.cmr.attributes.AttrQueryEquals; +import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.cmr.attributes.AttributeService; +import org.alfresco.service.cmr.attributes.DuplicateAttributeException; +import org.alfresco.service.cmr.attributes.AttributeService.AttributeQueryCallback; import org.alfresco.service.cmr.avm.AVMBadArgumentException; -import org.alfresco.service.cmr.avm.AVMExistsException; -import org.alfresco.service.cmr.avm.AVMNotFoundException; -import org.alfresco.service.cmr.avm.locking.AVMLock; +import org.alfresco.service.cmr.avm.locking.AVMLockingException; import org.alfresco.service.cmr.avm.locking.AVMLockingService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; @@ -44,61 +44,32 @@ import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.util.MD5; -import org.alfresco.util.Pair; +import org.alfresco.util.EqualsHelper; +import org.alfresco.util.ParameterCheck; +import org.alfresco.wcm.util.WCMUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Implementation of the lock service. - * @author britt + * + * @author Derek Hulley, janv */ public class AVMLockingServiceImpl implements AVMLockingService { - public static final String LOCK_TABLE = ".avm_lock_table"; - public static final String WEB_PROJECTS = "web_projects"; - public static final String USERS = "users"; - public static final String STORES = "stores"; + public static final String KEY_AVM_LOCKS = ".avm_locks"; + public static final String KEY_LOCK_OWNER = "lock-owner"; private static final String ROLE_CONTENT_MANAGER = "ContentManager"; private static final Log logger = LogFactory.getLog(AVMLockingServiceImpl.class); - /** - * Store name containing the web project nodes. - */ private String webProjectStore; - - /** - * SearchService for access to web project properties. - */ - private SearchService fSearchService; - - /** - * AttributeService reference. - */ - private AttributeService fAttributeService; - - /** - * AuthorityService reference. - */ - private AuthorityService fAuthorityService; - - /** - * PersonService reference. - */ - private PersonService fPersonService; - - /** - * The NodeService. - */ - private NodeService fNodeService; - - /** - * Transaction Helper reference. - */ - private RetryingTransactionHelper fRetryingTransactionHelper; - + private SearchService searchService; + private AttributeService attributeService; + private AuthorityService authorityService; + private PersonService personService; + private NodeService nodeService; /** * @param webProjectStore The webProjectStore to set @@ -109,97 +80,479 @@ public class AVMLockingServiceImpl implements AVMLockingService } /** - * Setter for AttributeService reference. - * @param service + * @param attributeService the service to persist attributes */ - public void setAttributeService(AttributeService service) + public void setAttributeService(AttributeService attributeService) { - fAttributeService = service; + this.attributeService = attributeService; } /** - * Set the authority service reference. - * @param service + * @param authorityService the service to check validity of usernames */ - public void setAuthorityService(AuthorityService service) + public void setAuthorityService(AuthorityService authorityService) { - fAuthorityService = service; + this.authorityService = authorityService; } /** - * Set the person service reference. - * @param service + * @param personService checks validity of person names */ - public void setPersonService(PersonService service) + public void setPersonService(PersonService personService) { - fPersonService = service; + this.personService = personService; + } + + public void setSearchService(SearchService searchService) + { + this.searchService = searchService; + } + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + /** + * Appends the lock owner to the lock data. + */ + private HashMap createLockAttributes(String lockOwner, Map lockData) + { + HashMap lockAttributes = new HashMap(lockData); + lockAttributes.put(KEY_LOCK_OWNER, lockOwner); + return lockAttributes; } /** - * Setter for RetryingTransactionHelper reference. - * @param helper + * {@inheritDoc} */ - public void setRetryingTransactionHelper(RetryingTransactionHelper helper) + public void lock(String avmStore, String path, String lockOwner, Map lockData) { - fRetryingTransactionHelper = helper; - } - - public void setSearchService(SearchService service) - { - fSearchService = service; - } - - public void setNodeService(NodeService service) - { - fNodeService = service; - } - - public void init() - { - RetryingTransactionHelper.RetryingTransactionCallback callback = - new RetryingTransactionHelper.RetryingTransactionCallback() + ParameterCheck.mandatoryString("avmStore", avmStore); + ParameterCheck.mandatoryString("path", path); + ParameterCheck.mandatoryString("lockOwner", lockOwner); + path = AVMLockingServiceImpl.normalizePath(path); + + if (!authorityService.authorityExists(lockOwner) && + !personService.personExists(lockOwner)) { - public Object execute() + throw new AVMBadArgumentException("Not an Authority: " + lockOwner); + } + + LockState lockState = getLockState(avmStore, path, lockOwner); + switch (lockState) + { + case LOCK_NOT_OWNER: + throw new AVMLockingException("avmlockservice.locked", path, lockOwner); + case NO_LOCK: + // Lock it, assuming that the lock doesn't exist (concurrency-safe). + try { - if (!fAttributeService.exists(LOCK_TABLE)) - { - fAttributeService.setAttribute("", LOCK_TABLE, new MapAttributeValue()); - } - if (!fAttributeService.exists(LOCK_TABLE + '/' + WEB_PROJECTS)) - { - fAttributeService.setAttribute(LOCK_TABLE, WEB_PROJECTS, new MapAttributeValue()); - } - return null; + HashMap lockAttributes = createLockAttributes(lockOwner, lockData); + attributeService.createAttribute( + lockAttributes, + KEY_AVM_LOCKS, avmStore, path); } - }; - fRetryingTransactionHelper.doInTransaction(callback, false); + catch (DuplicateAttributeException e) + { + String currentLockOwner = getLockOwner(avmStore, path); + // Should trigger a retry, hence we pass the exception out + throw new AVMLockingException(e, "avmlockservice.locked", path, currentLockOwner); + } + break; + case LOCK_OWNER: + // Nothing to do + break; + } } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#getLock(java.lang.String, java.lang.String) + /** + * {@inheritDoc} */ - public AVMLock getLock(String webProject, String path) + public boolean modifyLock( + String avmStore, String path, String lockOwner, + String newAvmStore, String newPath, + Map lockData) { - path = normalizePath(path); - List keys = new ArrayList(3); - keys.add(LOCK_TABLE); - keys.add(WEB_PROJECTS); - keys.add(webProject); - List> attrs = - fAttributeService.query(keys, new AttrQueryEquals(MD5.Digest(path.getBytes()))); - if (attrs.size() == 0) + ParameterCheck.mandatoryString("avmStore", avmStore); + ParameterCheck.mandatoryString("path", path); + ParameterCheck.mandatoryString("lockOwner", lockOwner); + ParameterCheck.mandatoryString("newAvmStore", newAvmStore); + ParameterCheck.mandatoryString("newPath", newPath); + path = AVMLockingServiceImpl.normalizePath(path); + newPath = AVMLockingServiceImpl.normalizePath(newPath); + + LockState currentLockState = getLockState(avmStore, path, lockOwner); + switch (currentLockState) + { + case LOCK_NOT_OWNER: + case LOCK_OWNER: + if (currentLockState.equals(LockState.LOCK_NOT_OWNER)) + { + // The lock is held by another user + if (! AuthenticationUtil.isRunAsUserTheSystemUser()) + { + String currentLockOwner = getLockOwner(avmStore, path); + throw new AVMLockingException("avmlockservice.locked", path, currentLockOwner); + } + } + // Remove the lock first + attributeService.removeAttribute(KEY_AVM_LOCKS, avmStore, path); + HashMap lockAttributes = createLockAttributes(lockOwner, lockData); + attributeService.setAttribute( + lockAttributes, + KEY_AVM_LOCKS, newAvmStore, newPath); + return true; + case NO_LOCK: + // Do nothing + return false; + default: + throw new IllegalStateException("Unexpected enum constant"); + } + } + + /** + * {@inheritDoc} + */ + public String getLockOwner(String avmStore, String path) + { + ParameterCheck.mandatoryString("path", path); + path = AVMLockingServiceImpl.normalizePath(path); + + Map lockAttributes = getLockData(avmStore, path); + if (lockAttributes == null) { return null; } - return new AVMLock(attrs.get(0).getSecond()); + else if (!lockAttributes.containsKey(KEY_LOCK_OWNER)) + { + logger.warn("AVM lock does not have a lock owner: " + avmStore + "-" + path); + return null; + } + return lockAttributes.get(KEY_LOCK_OWNER); + } + + /** + * {@inheritDoc} + */ + @SuppressWarnings("unchecked") + public Map getLockData(String avmStore, String path) + { + ParameterCheck.mandatoryString("avmStore", avmStore); + ParameterCheck.mandatoryString("path", path); + path = AVMLockingServiceImpl.normalizePath(path); + + Map lockAttributes = (Map) attributeService.getAttribute( + KEY_AVM_LOCKS, avmStore, path); + return lockAttributes; + } + + /** + * {@inheritDoc} + */ + public LockState getLockState(String avmStore, String path, String lockOwner) + { + ParameterCheck.mandatoryString("avmStore", avmStore); + ParameterCheck.mandatoryString("lockOwner", lockOwner); + path = AVMLockingServiceImpl.normalizePath(path); + + String currentLockOwner = getLockOwner(avmStore, path); + if (currentLockOwner == null) + { + return LockState.NO_LOCK; + } + else if (currentLockOwner.equals(lockOwner)) + { + return LockState.LOCK_OWNER; + } + else + { + return LockState.LOCK_NOT_OWNER; + } + } + + /** + * {@inheritDoc} + */ + public void removeLock(String avmStore, String path) + { + ParameterCheck.mandatoryString("avmStore", avmStore); + ParameterCheck.mandatoryString("path", path); + path = AVMLockingServiceImpl.normalizePath(path); + + attributeService.removeAttribute(KEY_AVM_LOCKS, avmStore, path); + } + + /** + * {@inheritDoc} + */ + public void removeLocks(String avmStore) + { + ParameterCheck.mandatoryString("avmStore", avmStore); + + attributeService.removeAttributes(KEY_AVM_LOCKS, avmStore); + } + + /** + * {@inheritDoc} + */ + public void removeLocks(String avmStore, String dirPath, final Map lockDataToMatch) + { + ParameterCheck.mandatoryString("avmStore", avmStore); + ParameterCheck.mandatory("lockDataToMatch", lockDataToMatch); + + final String dirPathStart; + if (dirPath == null) + { + dirPathStart = null; + } + else + { + dirPath = normalizePath(dirPath); + if (! dirPath.endsWith("/")) + { + dirPath = dirPath + '/'; + } + + dirPathStart = dirPath; + } + + final List pathKeys = new ArrayList(10); + + AttributeQueryCallback callback = new AttributeQueryCallback() + { + @SuppressWarnings("unchecked") + public boolean handleAttribute(Long id, Serializable value, Serializable[] keys) + { + if (keys.length != 3 || !EqualsHelper.nullSafeEquals(keys[0], KEY_AVM_LOCKS) || keys[1] == null || keys[2] == null || value == null) + { + logger.warn("Unexpected AVM lock attribute: \n" + + " id: " + id + "\n" + + " keys: " + Arrays.toString(keys) + "\n" + + " value: " + value); + return true; + } + + Map lockData = (Map) value; + + for (Map.Entry entry : lockDataToMatch.entrySet()) + { + String lockDataValue = lockData.get(entry.getKey()); + if (lockDataValue != null) + { + if (! lockDataValue.equals(entry.getValue())) + { + return true; + } + } + } + + String pathKey = (String)keys[2]; + + if (dirPathStart == null || pathKey.startsWith(dirPathStart)) + { + pathKeys.add(pathKey); + } + + // Continue + return true; + } + }; + + attributeService.getAttributes(callback, KEY_AVM_LOCKS, avmStore); + + for (String pathKey : pathKeys) + { + attributeService.removeAttribute(KEY_AVM_LOCKS, avmStore, pathKey); + } + } + + /** + * {@inheritDoc} + */ + public void removeLocks(String avmStore, final Map lockDataToMatch) + { + removeLocks(avmStore, null, lockDataToMatch); + } + + /** + * {@inheritDoc} + */ + public boolean hasAccess(String webProject, String avmPath, String lockOwner) + { + if (personService.getPerson(lockOwner) == null && !authorityService.authorityExists(lockOwner)) + { + return false; + } + if (authorityService.isAdminAuthority(lockOwner)) + { + return true; + } + StoreRef storeRef = new StoreRef(this.webProjectStore); + ResultSet results = searchService.query( + storeRef, + SearchService.LANGUAGE_LUCENE, + "@wca\\:avmstore:\"" + webProject + '"'); + try + { + if (results.getNodeRefs().size() == 1) + { + return hasAccess(webProject, results.getNodeRefs().get(0), avmPath, lockOwner); + } + return false; + } + finally + { + results.close(); + } + } + + /** + * {@inheritDoc} + */ + public boolean hasAccess(NodeRef webProjectRef, String avmPath, String lockOwner) + { + if (personService.getPerson(lockOwner) == null && + !authorityService.authorityExists(lockOwner)) + { + return false; + } + if (authorityService.isAdminAuthority(lockOwner)) + { + return true; + } + String webProject = (String)nodeService.getProperty(webProjectRef, WCMAppModel.PROP_AVMSTORE); + return hasAccess(webProject, webProjectRef, avmPath, lockOwner); + } + + private boolean hasAccess(String webProject, NodeRef webProjectRef, String avmPath, String lockOwner) + { + String[] storePath = avmPath.split(":"); + if (storePath.length != 2) + { + throw new AVMBadArgumentException("Malformed AVM Path : " + avmPath); + } + + if (logger.isDebugEnabled()) + logger.debug( + "Testing lock access on path: " + avmPath + + " for user: " + lockOwner + " in webproject: " + webProject); + + // check if a lock exists at all for this path in the specified webproject id + String path = normalizePath(storePath[1]); + + Map lockData = getLockData(webProject, path); + + if (lockData == null) + { + if (logger.isDebugEnabled()) + logger.debug(" GRANTED: No lock found."); + return true; + } + + String currentLockOwner = lockData.get(KEY_LOCK_OWNER); + String currentLockStore = lockData.get(WCMUtil.LOCK_KEY_STORE_NAME); + + + // locks are ignored in a workflow store + if (storePath[0].contains("--workflow")) + { + if (logger.isDebugEnabled()) + logger.debug(" GRANTED: Workflow store path."); + return true; + } + + // locks are specific to a store - no access if the stores are different + if (! ((currentLockStore != null) && (currentLockStore.equals(storePath[0])))) + { + if (logger.isDebugEnabled()) + logger.debug(" DENIED: Store on path and lock (" + currentLockStore + ") do not match."); + return false; + } + + // check for content manager role - we allow access to all managers within the same store + // TODO as part of WCM refactor, consolidate with WebProject.getWebProjectUserRole + StringBuilder query = new StringBuilder(128); + query.append("+PARENT:\"").append(webProjectRef).append("\" "); + query.append("+TYPE:\"").append(WCMAppModel.TYPE_WEBUSER).append("\" "); + query.append("+@").append(NamespaceService.WCMAPP_MODEL_PREFIX).append("\\:username:\""); + query.append(lockOwner); + query.append("\""); + ResultSet resultSet = searchService.query( + new StoreRef(this.webProjectStore), + SearchService.LANGUAGE_LUCENE, + query.toString()); + List nodes = resultSet.getNodeRefs(); + resultSet.close(); + + if (nodes.size() == 1) + { + String userrole = (String)nodeService.getProperty(nodes.get(0), WCMAppModel.PROP_WEBUSERROLE); + if (ROLE_CONTENT_MANAGER.equals(userrole)) + { + if (logger.isDebugEnabled()) + { + logger.debug("GRANTED: Store match and user is ContentManager role in webproject."); + } + return true; + } + } + else if (nodes.size() == 0) + { + logger.warn("hasAccess: user role not found for " + lockOwner); + } + else + { + logger.warn("hasAccess: more than one user role found for " + lockOwner); + } + + // finally check the owner of the lock against the specified authority + if (AuthorityType.getAuthorityType(currentLockOwner) == AuthorityType.EVERYONE) + { + if (logger.isDebugEnabled()) + logger.debug(" GRANTED: Authority EVERYONE matched lock owner."); + return true; + } + + if (checkAgainstAuthority(lockOwner, currentLockOwner)) + { + if (logger.isDebugEnabled()) + logger.debug(" GRANTED: User matched as lock owner."); + return true; + } + + if (logger.isDebugEnabled()) + logger.debug(" DENIED: User did not match as lock owner."); + return false; + } + + /** + * Helper function that checks the transitive closure of authorities for user. + */ + private boolean checkAgainstAuthority(String user, String authority) + { + if (user.equalsIgnoreCase(authority)) + { + return true; + } + Set containing = authorityService.getContainingAuthorities(null, user, false); + for (String parent : containing) + { + if (parent.equalsIgnoreCase(authority)) + { + return true; + } + } + return false; } /** * Utility to get relative paths into canonical form. + * * @param path The incoming path. * @return The normalized path. */ - private String normalizePath(String path) + public static String normalizePath(String path) { while (path.startsWith("/")) { @@ -211,526 +564,4 @@ public class AVMLockingServiceImpl implements AVMLockingService } return path.replaceAll("/+", "/"); } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#getUsersLocks(java.lang.String) - */ - public List getUsersLocks(String user) - { -// List keys = new ArrayList(3); -// keys.add(LOCK_TABLE); -// keys.add(USERS); -// keys.add(user); -// Attribute userLocks = fAttributeService.getAttribute(keys); -// List locks = new ArrayList(); -// if (userLocks == null) -// { -// return locks; -// } -// for (Attribute entry : userLocks) -// { -// String webProject = entry.get("web_project").getStringValue(); -// String path = entry.get("path").getStringValue(); -// locks.add(getLock(webProject, path)); -// } -// return locks; - return null; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#lockPath(org.alfresco.service.cmr.avm.locking.AVMLock) - */ - public void lockPath(AVMLock lock) - { - for (String authority : lock.getOwners()) - { - if (!fAuthorityService.authorityExists(authority) && - !fPersonService.personExists(authority)) - { - throw new AVMBadArgumentException("Not an Authority: " + authority); - } - } - List keys = new ArrayList(); - Attribute lockData = lock.getAttribute(); - keys.add(LOCK_TABLE); - keys.add(WEB_PROJECTS); - keys.add(lock.getWebProject()); - String digest = MD5.Digest(lock.getPath().getBytes()); - keys.add(digest); - if (fAttributeService.exists(keys)) - { - throw new AVMExistsException("Lock Exists: " + keys); - } - keys.remove(3); - fAttributeService.setAttribute(keys, digest, lockData); -// Attribute reverseEntry = new MapAttributeValue(); -// reverseEntry.put("web_project", new StringAttributeValue(lock.getWebProject())); -// reverseEntry.put("path", new StringAttributeValue(lock.getPath())); -// keys.clear(); -// keys.add(LOCK_TABLE); -// keys.add(USERS); -// for (String user : lock.getOwners()) -// { -// keys.add(user); -// Attribute userEntry = fAttributeService.getAttribute(keys); -// keys.remove(2); -// if (userEntry == null) -// { -// fAttributeService.setAttribute(keys, user, new ListAttributeValue()); -// } -// keys.add(user); -// fAttributeService.addAttribute(keys, reverseEntry); -// keys.remove(2); -// } -// String store = lock.getStore(); -// keys.clear(); -// keys.add(LOCK_TABLE); -// keys.add(STORES); -// keys.add(store); -// Attribute storeEntry = fAttributeService.getAttribute(keys); -// keys.remove(2); -// if (storeEntry == null) -// { -// fAttributeService.setAttribute(keys, store, new ListAttributeValue()); -// } -// keys.add(store); -// fAttributeService.addAttribute(keys, reverseEntry); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#removeLock(java.lang.String, java.lang.String) - */ - public void removeLock(String webProject, String path) - { - path = normalizePath(path); - String pathKey = MD5.Digest(path.getBytes()); - List keys = new ArrayList(4); - keys.add(LOCK_TABLE); - keys.add(WEB_PROJECTS); - keys.add(webProject); - keys.add(pathKey); - if (!fAttributeService.exists(keys)) - { - return; - } - keys.remove(3); - fAttributeService.removeAttribute(keys, pathKey); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#removeLocksInDirectory(java.lang.String, java.lang.String, java.lang.String) - */ - public void removeLocksInDirectory(String webProject, String store, - String path) - { - path = normalizePath(path); - if (logger.isDebugEnabled()) - { - logger.debug("removing locks in directory: " + path + "(" + webProject + ", " + store + ")"); - } - List keys = new ArrayList(); - keys.add(LOCK_TABLE); - keys.add(WEB_PROJECTS); - keys.add(webProject); - Attribute map = fAttributeService.getAttribute(keys); - if (map == null) - { - return; - } - for (Map.Entry entry : map.entrySet()) - { - if (logger.isDebugEnabled()) - { - logger.debug(entry); - } - Attribute child = entry.getValue(); - if (child.get("store").getStringValue().equals(store) && - child.get("path").getStringValue().startsWith(path + '/')) - { - fAttributeService.removeAttribute(keys, entry.getKey()); - } - } - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#addWebProject(java.lang.String) - */ - public void addWebProject(String webProject) - { - List keys = new ArrayList(3); - keys.add(LOCK_TABLE); - keys.add(WEB_PROJECTS); - keys.add(webProject); - if (fAttributeService.exists(keys)) - { - return; - } - keys.remove(2); - fAttributeService.setAttribute(keys, webProject, new MapAttributeValue()); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#getWebProjectLocks(java.lang.String) - */ - public List getWebProjectLocks(String webProject) - { - List keys = new ArrayList(3); - keys.add(LOCK_TABLE); - keys.add(WEB_PROJECTS); - keys.add(webProject); - Attribute locksMap = fAttributeService.getAttribute(keys); - List result = new ArrayList(); - if (locksMap != null) - { - for (Attribute lockData : locksMap.values()) - { - result.add(new AVMLock(lockData)); - } - } - return result; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#removeWebProject(java.lang.String) - */ - public void removeWebProject(String webProject) - { -// List userKeys = new ArrayList(2); -// userKeys.add(LOCK_TABLE); -// userKeys.add(USERS); -// List users = fAttributeService.getKeys(userKeys); -// // TODO This works incredibly slowly. AttributeService has to support -// // extended querying on values. -// for (String user : users) -// { -// userKeys.add(user); -// Attribute userLocks = fAttributeService.getAttribute(userKeys); -// Iterator iter = userLocks.iterator(); -// while (iter.hasNext()) -// { -// Attribute lockInfo = iter.next(); -// if (lockInfo.get("web_project").getStringValue().equals(webProject)) -// { -// iter.remove(); -// } -// } -// userKeys.remove(2); -// fAttributeService.setAttribute(userKeys, user, userLocks); -// } -// List storeKeys = new ArrayList(); -// storeKeys.add(LOCK_TABLE); -// storeKeys.add(STORES); -// List stores = fAttributeService.getKeys(storeKeys); -// // TODO Ditto. -// for (String store : stores) -// { -// storeKeys.add(store); -// Attribute storeLocks = fAttributeService.getAttribute(storeKeys); -// Iterator iter = storeLocks.iterator(); -// while (iter.hasNext()) -// { -// Attribute lockInfo = iter.next(); -// if (lockInfo.get("web_project").getStringValue().equals(webProject)) -// { -// iter.remove(); -// } -// } -// storeKeys.remove(2); -// fAttributeService.setAttribute(storeKeys, store, storeLocks); -// } - List keys = new ArrayList(2); - keys.add(LOCK_TABLE); - keys.add(WEB_PROJECTS); - fAttributeService.removeAttribute(keys, webProject); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#getStoreLocks(java.lang.String) - */ - public List getStoreLocks(String store) - { - return null; -// List locks = new ArrayList(3); -// List keys = new ArrayList(); -// keys.add(LOCK_TABLE); -// keys.add(STORES); -// keys.add(store); -// List lockKeys = new ArrayList(); -// lockKeys.add(LOCK_TABLE); -// lockKeys.add(WEB_PROJECTS); -// Attribute storeLocks = fAttributeService.getAttribute(keys); -// for (Attribute lockInfo : storeLocks) -// { -// String webProject = lockInfo.get("web_project").getStringValue(); -// String path = lockInfo.get("path").getStringValue(); -// lockKeys.add(webProject); -// lockKeys.add(MD5.Digest(path.getBytes())); -// Attribute lockData = fAttributeService.getAttribute(lockKeys); -// locks.add(new AVMLock(lockData)); -// lockKeys.remove(3); -// lockKeys.remove(2); -// } -// return locks; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#modifyLock(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.util.List, java.util.List) - */ - public void modifyLock(String webProject, String path, String newPath, String newStore, List usersToRemove, List usersToAdd) - { - AVMLock lock = getLock(webProject, path); - if (lock == null) - { - throw new AVMNotFoundException("Lock not found for " + webProject + ":" + path); - } - removeLock(webProject, path); - if (newPath != null) - { - lock.setPath(newPath); - } - if (newStore != null) - { - lock.setStore(newStore); - } - if (usersToRemove != null) - { - for (String user : usersToRemove) - { - lock.getOwners().remove(user); - } - } - if (usersToAdd != null) - { - for (String user : usersToAdd) - { - if (!fAuthorityService.authorityExists(user) && - !fPersonService.personExists(user)) - { - throw new AVMBadArgumentException("Not an authority: " + user); - } - if (lock.getOwners().contains(user)) - { - continue; - } - lock.getOwners().add(user); - } - } - lockPath(lock); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#removeStoreLocks(java.lang.String) - */ - public void removeStoreLocks(String store) - { - String webProject = store; - int index = store.indexOf("--"); - if (index >= 0) - { - webProject = store.substring(0, index); - } - List keys = new ArrayList(3); - keys.add(LOCK_TABLE); - keys.add(WEB_PROJECTS); - keys.add(webProject); - Attribute project = fAttributeService.getAttribute(keys); - if (project == null) - { - return; - } - List toDelete = new ArrayList(); - for (Map.Entry entry: project.entrySet()) - { - AVMLock lock = new AVMLock(entry.getValue()); - if (lock.getStore().equals(store)) - { - toDelete.add(entry.getKey()); - } - } - for (String name : toDelete) - { - fAttributeService.removeAttribute(keys, name); - } - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#hasAccess(java.lang.String, java.lang.String) - */ - public boolean hasAccess(String webProject, String avmPath, String user) - { - if (fPersonService.getPerson(user) == null && - !fAuthorityService.authorityExists(user)) - { - return false; - } - if (fAuthorityService.isAdminAuthority(user)) - { - return true; - } - StoreRef storeRef = new StoreRef(this.webProjectStore); - ResultSet results = fSearchService.query( - storeRef, - SearchService.LANGUAGE_LUCENE, - "@wca\\:avmstore:\"" + webProject + '"'); - try - { - if (results.getNodeRefs().size() == 1) - { - return hasAccess(webProject, results.getNodeRefs().get(0), avmPath, user); - } - return false; - } - finally - { - results.close(); - } - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#hasAccess(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.lang.String) - */ - public boolean hasAccess(NodeRef webProjectRef, String avmPath, String user) - { - if (fPersonService.getPerson(user) == null && - !fAuthorityService.authorityExists(user)) - { - return false; - } - if (fAuthorityService.isAdminAuthority(user)) - { - return true; - } - String webProject = (String)fNodeService.getProperty(webProjectRef, WCMAppModel.PROP_AVMSTORE); - return hasAccess(webProject, webProjectRef, avmPath, user); - } - - private boolean hasAccess(String webProject, NodeRef webProjectRef, String avmPath, String user) - { - String[] storePath = avmPath.split(":"); - if (storePath.length != 2) - { - throw new AVMBadArgumentException("Malformed AVM Path : " + avmPath); - } - - if (logger.isDebugEnabled()) - logger.debug("Testing lock access on path: " + avmPath + " for user: " + user + " in webproject: " + webProject); - - // check if a lock exists at all for this path in the specified webproject id - String path = normalizePath(storePath[1]); - AVMLock lock = getLock(webProject, path); - if (lock == null) - { - if (logger.isDebugEnabled()) - logger.debug(" GRANTED: No lock found."); - return true; - } - - // locks are ignored in a workflow store - if (storePath[0].contains("--workflow")) - { - if (logger.isDebugEnabled()) - logger.debug(" GRANTED: Workflow store path."); - return true; - } - - // locks are specific to a store - no access if the stores are different - if (!lock.getStore().equals(storePath[0])) - { - if (logger.isDebugEnabled()) - logger.debug(" DENIED: Store on path and lock (" + lock.getStore().toString() + ") do not match."); - return false; - } - - // check for content manager role - we allow access to all managers within the same store - // TODO as part of WCM refactor, consolidate with WebProject.getWebProjectUserRole - StringBuilder query = new StringBuilder(128); - query.append("+PARENT:\"").append(webProjectRef).append("\" "); - query.append("+TYPE:\"").append(WCMAppModel.TYPE_WEBUSER).append("\" "); - query.append("+@").append(NamespaceService.WCMAPP_MODEL_PREFIX).append("\\:username:\""); - query.append(user); - query.append("\""); - ResultSet resultSet = fSearchService.query( - new StoreRef(this.webProjectStore), - SearchService.LANGUAGE_LUCENE, - query.toString()); - List nodes = resultSet.getNodeRefs(); - resultSet.close(); - - if (nodes.size() == 1) - { - String userrole = (String)fNodeService.getProperty(nodes.get(0), WCMAppModel.PROP_WEBUSERROLE); - if (ROLE_CONTENT_MANAGER.equals(userrole)) - { - if (logger.isDebugEnabled()) - { - logger.debug("GRANTED: Store match and user is ContentManager role in webproject."); - } - return true; - } - } - else if (nodes.size() == 0) - { - logger.warn("hasAccess: user role not found for " + user); - } - else - { - logger.warn("hasAccess: more than one user role found for " + user); - } - - // finally check the owners of the lock against the specified authority - List owners = lock.getOwners(); - for (String owner : owners) - { - if (AuthorityType.getAuthorityType(owner) == AuthorityType.EVERYONE) - { - if (logger.isDebugEnabled()) - logger.debug(" GRANTED: Authority EVERYONE matched lock owner."); - return true; - } - if (checkAgainstAuthority(user, owner)) - { - if (logger.isDebugEnabled()) - logger.debug(" GRANTED: User matched as lock owner."); - return true; - } - } - - if (logger.isDebugEnabled()) - logger.debug(" DENIED: User did not match as lock owner."); - return false; - } - - /** - * Helper function that checks the transitive closure of authorities for user. - * @param user - * @param authority - * @return - */ - private boolean checkAgainstAuthority(String user, String authority) - { - if (user.equalsIgnoreCase(authority)) - { - return true; - } - Set containing = fAuthorityService.getContainingAuthorities(null, user, false); - for (String parent : containing) - { - if (parent.equalsIgnoreCase(authority)) - { - return true; - } - } - return false; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.locking.AVMLockingService#getWebProjects() - */ - public List getWebProjects() - { - List keys = new ArrayList(2); - keys.add(LOCK_TABLE); - keys.add(WEB_PROJECTS); - return fAttributeService.getKeys(keys); - } } diff --git a/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceTest.java b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceTest.java index 1862909109..1a5d6382dd 100644 --- a/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceTest.java +++ b/source/java/org/alfresco/repo/avm/locking/AVMLockingServiceTest.java @@ -16,12 +16,11 @@ * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ - package org.alfresco.repo.avm.locking; import java.io.IOException; import java.io.Serializable; -import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,15 +29,13 @@ import junit.framework.TestCase; import org.alfresco.model.ContentModel; import org.alfresco.model.WCMAppModel; -import org.alfresco.repo.avm.AVMTestSuite; import org.alfresco.repo.avm.util.BulkLoader; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.domain.PropertyValue; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.service.cmr.attributes.AttributeService; import org.alfresco.service.cmr.avm.AVMService; -import org.alfresco.service.cmr.avm.locking.AVMLock; +import org.alfresco.service.cmr.avm.locking.AVMLockingException; import org.alfresco.service.cmr.avm.locking.AVMLockingService; import org.alfresco.service.cmr.avmsync.AVMDifference; import org.alfresco.service.cmr.avmsync.AVMSyncService; @@ -55,71 +52,53 @@ import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.util.ApplicationContextHelper; import org.alfresco.wcm.sandbox.SandboxConstants; +import org.alfresco.wcm.util.WCMUtil; import org.springframework.context.ApplicationContext; /** * Tests for WCM (web project) locking - AVMLockingService & AVMLockingAwareService * - * @author britt + * @author Derek Hulley, janv */ public class AVMLockingServiceTest extends TestCase { - private static ApplicationContext fContext = null; + private static String[] TESTUSERS = {"Buffy", "Willow", "Xander", "Tara", "Spike"}; + private static String[] TESTAUTHORITIES = {"GROUP_Scoobies", "ROLE_SUPER_POWERED", "GROUP_vampires"}; - private static AVMLockingService fLockingService; + private ApplicationContext ctx = null; - private static AVMService fService; - - private static AVMSyncService fSyncService; - - private static AttributeService fAttributeService; - - private static PersonService fPersonService; - - private static AuthorityService fAuthorityService; - - private static MutableAuthenticationService fAuthenticationService; - - private static NodeService fNodeService; - - private static RepoRemote fRepoRemote; - - private static NodeRef fWebProject; - - private static String[] testUsers = {"Buffy", "Willow", "Xander", "Tara", "Spike"}; - - private static String[] testAuthorities = {"GROUP_Scoobies", "ROLE_SUPER_POWERED", "GROUP_vampires"}; + private static AVMLockingService lockingService; + private static AVMService avmService; + private static AVMSyncService syncService; + private static PersonService personService; + private static AuthorityService authorityService; + private static MutableAuthenticationService authenticationService; + private static NodeService nodeService; + private static RepoRemote repoRemoteService; private static final String testWP1 = "alfresco-"+System.currentTimeMillis(); + private NodeRef testWP1NodeRef; - /* (non-Javadoc) - * @see junit.framework.TestCase#setUp() - */ @Override protected void setUp() throws Exception { - if (fContext == null) - { - fContext = AVMTestSuite.getContext(); - - fLockingService = (AVMLockingService)fContext.getBean("AVMLockingService"); - fService = (AVMService) fContext.getBean("AVMLockingAwareService"); - fSyncService = (AVMSyncService)fContext.getBean("AVMSyncService"); - fAttributeService = (AttributeService)fContext.getBean("AttributeService"); - fPersonService = (PersonService)fContext.getBean("PersonService"); - fAuthorityService = (AuthorityService)fContext.getBean("AuthorityService"); - fAuthenticationService = (MutableAuthenticationService)fContext.getBean("AuthenticationService"); - fNodeService = (NodeService)fContext.getBean("NodeService"); - fRepoRemote = (RepoRemote)fContext.getBean("RepoRemoteService"); - } + ctx = ApplicationContextHelper.getApplicationContext(); + lockingService = (AVMLockingService)ctx.getBean("AVMLockingService"); + avmService = (AVMService) ctx.getBean("AVMLockingAwareService"); + syncService = (AVMSyncService)ctx.getBean("AVMSyncService"); + personService = (PersonService)ctx.getBean("PersonService"); + authorityService = (AuthorityService)ctx.getBean("AuthorityService"); + authenticationService = (MutableAuthenticationService)ctx.getBean("AuthenticationService"); + nodeService = (NodeService)ctx.getBean("NodeService"); + repoRemoteService = (RepoRemote)ctx.getBean("RepoRemoteService"); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName()); // Set up a fake web project. - NodeRef root = fRepoRemote.getRoot(); + NodeRef root = repoRemoteService.getRoot(); Map properties = new HashMap(); properties.put(WCMAppModel.PROP_AVMSTORE, testWP1); - fWebProject = fNodeService.createNode(root, ContentModel.ASSOC_CONTAINS, + testWP1NodeRef = nodeService.createNode(root, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, testWP1), WCMAppModel.TYPE_AVMWEBFOLDER, properties).getChildRef(); @@ -127,253 +106,199 @@ public class AVMLockingServiceTest extends TestCase cleanUsersAndGroups(); - fAuthenticationService.createAuthentication("Buffy", "Buffy".toCharArray()); - fPersonService.getPerson("Buffy"); - fAuthorityService.createAuthority(AuthorityType.GROUP, "Scoobies"); - fAuthorityService.addAuthority("GROUP_Scoobies", "Buffy"); - fAuthorityService.createAuthority(AuthorityType.ROLE, "SUPER_POWERED"); - fAuthorityService.addAuthority("ROLE_SUPER_POWERED", "Buffy"); + authenticationService.createAuthentication("Buffy", "Buffy".toCharArray()); + personService.getPerson("Buffy"); + authorityService.createAuthority(AuthorityType.GROUP, "Scoobies"); + authorityService.addAuthority("GROUP_Scoobies", "Buffy"); + authorityService.createAuthority(AuthorityType.ROLE, "SUPER_POWERED"); + authorityService.addAuthority("ROLE_SUPER_POWERED", "Buffy"); - fAuthenticationService.createAuthentication("Willow", "Willow".toCharArray()); - fPersonService.getPerson("Willow"); - fAuthorityService.addAuthority("GROUP_Scoobies", "Willow"); + authenticationService.createAuthentication("Willow", "Willow".toCharArray()); + personService.getPerson("Willow"); + authorityService.addAuthority("GROUP_Scoobies", "Willow"); - fAuthenticationService.createAuthentication("Xander", "Xander".toCharArray()); - fPersonService.getPerson("Xander"); - fAuthorityService.addAuthority("GROUP_Scoobies", "Xander"); + authenticationService.createAuthentication("Xander", "Xander".toCharArray()); + personService.getPerson("Xander"); + authorityService.addAuthority("GROUP_Scoobies", "Xander"); - fAuthenticationService.createAuthentication("Tara", "Tara".toCharArray()); - fPersonService.getPerson("Tara"); + authenticationService.createAuthentication("Tara", "Tara".toCharArray()); + personService.getPerson("Tara"); - fAuthenticationService.createAuthentication("Spike", "Spike".toCharArray()); - fPersonService.getPerson("Spike"); - fAuthorityService.addAuthority("ROLE_SUPER_POWERED", "Spike"); - fAuthorityService.createAuthority(AuthorityType.GROUP, "vampires"); - fAuthorityService.addAuthority("GROUP_vampires", "Spike"); + authenticationService.createAuthentication("Spike", "Spike".toCharArray()); + personService.getPerson("Spike"); + authorityService.addAuthority("ROLE_SUPER_POWERED", "Spike"); + authorityService.createAuthority(AuthorityType.GROUP, "vampires"); + authorityService.addAuthority("GROUP_vampires", "Spike"); } - /* (non-Javadoc) - * @see junit.framework.TestCase#tearDown() - */ @Override protected void tearDown() throws Exception { - List webProjects = fLockingService.getWebProjects(); - for (String webProject : webProjects) - { - if (webProject.equals(testWP1)) - { - fLockingService.removeStoreLocks(webProject); - fLockingService.removeWebProject(webProject); - } - } + lockingService.removeLocks(testWP1); cleanUsersAndGroups(); - fNodeService.deleteNode(fWebProject); + nodeService.deleteNode(testWP1NodeRef); } private void cleanUsersAndGroups() { - for (String testUser : testUsers) + for (String testUser : TESTUSERS) { - if (fAuthenticationService.authenticationExists(testUser)) + if (authenticationService.authenticationExists(testUser)) { - fAuthenticationService.deleteAuthentication(testUser); + authenticationService.deleteAuthentication(testUser); } - if (fPersonService.personExists(testUser)) + if (personService.personExists(testUser)) { - fPersonService.deletePerson(testUser); + personService.deletePerson(testUser); } } - for (String testAuthority : testAuthorities) + for (String testAuthority : TESTAUTHORITIES) { - if (fAuthorityService.authorityExists(testAuthority)) + if (authorityService.authorityExists(testAuthority)) { - fAuthorityService.deleteAuthority(testAuthority); + authorityService.deleteAuthority(testAuthority); } } } - public void testAll() + private static final Map EMPTY_MAP = Collections.emptyMap(); + + public void testAll() throws Exception { + lockingService.lock(testWP1, "Revello Drive/1630", TESTUSERS[0], EMPTY_MAP); + assertEquals(lockingService.getLockOwner(testWP1, "Revello Drive/1630"), TESTUSERS[0]); + lockingService.removeLock(testWP1, "Revello Drive/1630"); + assertNull(lockingService.getLockOwner(testWP1, "Revello Drive/1630")); + + lockingService.lock(testWP1, "UC Sunnydale/Stevenson Hall", TESTUSERS[0], EMPTY_MAP); + assertEquals(lockingService.getLockOwner(testWP1, "UC Sunnydale/Stevenson Hall"), TESTUSERS[0]); + try { - fLockingService.addWebProject(testWP1); - System.out.println(fAttributeService.getAttribute(".avm_lock_table")); - List owners = new ArrayList(); - owners.add("Buffy"); - owners.add("Spike"); - AVMLock lock = new AVMLock(testWP1, - "Sunnydale", - "Revello Drive/1630", - AVMLockingService.Type.DISCRETIONARY, - owners); - fLockingService.lockPath(lock); - System.out.println(fAttributeService.getAttribute(".avm_lock_table")); - assertNotNull(fLockingService.getLock(testWP1, "Revello Drive/1630")); - // assertEquals(1, fLockingService.getUsersLocks("Buffy").size()); - assertEquals(1, fLockingService.getWebProjectLocks(testWP1).size()); - List owners2 = new ArrayList(); - owners2.add("Buffy"); - owners2.add("Willow"); - AVMLock lock2 = new AVMLock(testWP1, - "Sunnydale", - "UC Sunnydale/Stevenson Hall", - AVMLockingService.Type.DISCRETIONARY, - owners2); - fLockingService.lockPath(lock2); - System.out.println(fAttributeService.getAttribute(".avm_lock_table")); - // assertEquals(2, fLockingService.getUsersLocks("Buffy").size()); - assertEquals(2, fLockingService.getWebProjectLocks(testWP1).size()); - System.out.println("Before----------------------------"); - fLockingService.removeLock(testWP1, "Revello Drive/1630"); - System.out.println("After----------------------------"); - System.out.println(fAttributeService.getAttribute(".avm_lock_table")); - // assertEquals(1, fLockingService.getUsersLocks("Buffy").size()); - assertEquals(1, fLockingService.getWebProjectLocks(testWP1).size()); - fLockingService.removeWebProject(testWP1); - System.out.println(fAttributeService.getAttribute(".avm_lock_table")); - // assertEquals(0, fLockingService.getUsersLocks("Spike").size()); - // assertEquals(0, fLockingService.getUsersLocks("Buffy").size()); - // assertEquals(0, fLockingService.getUsersLocks("Willow").size()); - // assertEquals(0, fLockingService.getUsersLocks("Tara").size()); + lockingService.lock(testWP1, "UC Sunnydale/Stevenson Hall", TESTUSERS[1], EMPTY_MAP); + fail("Failed to detect existing lock"); } - catch (Exception e) + catch (AVMLockingException e) { - e.printStackTrace(); - fail(); + // Expected } } + @SuppressWarnings("deprecation") public void testRoleBasedLocking() { - try - { - fLockingService.addWebProject(testWP1); - List owners = new ArrayList(); - owners.add("ROLE_SUPER_POWERED"); - owners.add("Tara"); - AVMLock lock = new AVMLock(testWP1, - "Sunnydale", - "TheInitiative/Adam/plans.txt", - AVMLockingService.Type.DISCRETIONARY, - owners); - fLockingService.lockPath(lock); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Buffy")); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Spike")); - assertFalse(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Willow")); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Tara")); - assertFalse(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Xander")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Buffy")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Spike")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Willow")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Tara")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Xander")); - } - catch (Exception e) - { - e.printStackTrace(); - fail(); - } + Map lockData = Collections.singletonMap(WCMUtil.LOCK_KEY_STORE_NAME, "Sunnydale"); + + // lock owner = "ROLE_SUPER_POWERED" + lockingService.lock(testWP1, "TheInitiative/Adam/plans.txt", TESTAUTHORITIES[1], lockData); + + assertTrue(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Buffy")); + assertTrue(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Spike")); + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Willow")); + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Tara")); // Tara does not belong to ROLE_SUPER_POWERED + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Xander")); + + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Buffy")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Spike")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Willow")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Tara")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Xander")); } + @SuppressWarnings("deprecation") public void testGroupBasedLocking() { - try - { - fLockingService.addWebProject(testWP1); - List owners = new ArrayList(); - owners.add("GROUP_Scoobies"); - owners.add("Tara"); - AVMLock lock = new AVMLock(testWP1, - "Sunnydale", - "TheInitiative/Adam/plans.txt", - AVMLockingService.Type.DISCRETIONARY, - owners); - fLockingService.lockPath(lock); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Buffy")); - assertFalse(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Spike")); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Willow")); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Tara")); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Xander")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Buffy")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Spike")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Willow")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Tara")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Xander")); - } - catch (Exception e) - { - e.printStackTrace(); - fail(); - } + Map lockData = Collections.singletonMap(WCMUtil.LOCK_KEY_STORE_NAME, "Sunnydale"); + + // lock owner = "GROUP_Scoobies" + lockingService.lock(testWP1, "TheInitiative/Adam/plans.txt", TESTAUTHORITIES[0], lockData); + + assertTrue(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Buffy")); + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Spike")); + assertTrue(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Willow")); + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Tara")); // Tara does not belong to GROUP_Scoobies + assertTrue(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Xander")); + + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Buffy")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Spike")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Willow")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Tara")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Xander")); } + @SuppressWarnings("deprecation") public void testLockModification() { - try + Map lockData = Collections.singletonMap(WCMUtil.LOCK_KEY_STORE_NAME, "Sunnydale"); + + // lock owner = "GROUP_Scoobies" + lockingService.lock(testWP1, "TheInitiative/Adam/plans.txt", TESTAUTHORITIES[0], lockData); + + assertTrue(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Buffy")); + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Spike")); + assertTrue(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Willow")); + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Tara")); // Tara does not belong to GROUP_Scoobies + assertTrue(lockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Xander")); + + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Buffy")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Spike")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Willow")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Tara")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Xander")); + + lockData = Collections.singletonMap(WCMUtil.LOCK_KEY_STORE_NAME, "Sunnydale"); + + // lock owner = "GROUP_Scoobies" + lockingService.modifyLock( + testWP1, "TheInitiative/Adam/plans.txt", TESTAUTHORITIES[0], + testWP1, "ScrapHeap/Adam/plans.txt", lockData); + + assertTrue(lockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Buffy")); + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Spike")); + assertTrue(lockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Willow")); + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Tara")); // Tara does not belong to GROUP_Scoobies + assertTrue(lockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Xander")); + + lockData = Collections.singletonMap(WCMUtil.LOCK_KEY_STORE_NAME, "LA"); + + lockingService.modifyLock( + testWP1, "ScrapHeap/Adam/plans.txt", TESTAUTHORITIES[0], + testWP1, "ScrapHeap/Adam/plans.txt", lockData); + + assertTrue(lockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Buffy")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Spike")); + assertTrue(lockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Willow")); + assertFalse(lockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Tara")); // Tara does not belong to GROUP_Scoobies + assertTrue(lockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Xander")); + + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Buffy")); + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Spike")); + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Willow")); + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Tara")); + assertFalse(lockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Xander")); + + + AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() { - fLockingService.addWebProject(testWP1); - List owners = new ArrayList(); - owners.add("GROUP_Scoobies"); - owners.add("Tara"); - AVMLock lock = new AVMLock(testWP1, - "Sunnydale", - "TheInitiative/Adam/plans.txt", - AVMLockingService.Type.DISCRETIONARY, - owners); - fLockingService.lockPath(lock); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Buffy")); - assertFalse(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Spike")); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Willow")); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Tara")); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/TheInitiative/Adam/plans.txt", "Xander")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Buffy")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Spike")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Willow")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Tara")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/TheInitiative/Adam/plans.txt", "Xander")); - fLockingService.modifyLock(testWP1, "TheInitiative/Adam/plans.txt", "ScrapHeap/Adam/plans.txt", null, null, null); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Buffy")); - assertFalse(fLockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Spike")); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Willow")); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Tara")); - assertTrue(fLockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Xander")); - fLockingService.modifyLock(testWP1, "ScrapHeap/Adam/plans.txt", null, "LA", null, null); - assertTrue(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Buffy")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Spike")); - assertTrue(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Willow")); - assertTrue(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Tara")); - assertTrue(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Xander")); - assertFalse(fLockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Buffy")); - assertFalse(fLockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Spike")); - assertFalse(fLockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Willow")); - assertFalse(fLockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Tara")); - assertFalse(fLockingService.hasAccess(testWP1, "Sunnydale:/ScrapHeap/Adam/plans.txt", "Xander")); - List usersToAdd = new ArrayList(); - usersToAdd.add("Spike"); - fLockingService.modifyLock(testWP1, "ScrapHeap/Adam/plans.txt", null, null, null, usersToAdd); - assertTrue(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Buffy")); - assertTrue(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Spike")); - assertTrue(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Willow")); - assertTrue(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Tara")); - assertTrue(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Xander")); - List usersToRemove = new ArrayList(); - usersToRemove.add("GROUP_Scoobies"); - fLockingService.modifyLock(testWP1, "ScrapHeap/Adam/plans.txt", null, null, usersToRemove, null); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Buffy")); - assertTrue(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Spike")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Willow")); - assertTrue(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Tara")); - assertFalse(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", "Xander")); - assertTrue(fLockingService.hasAccess(testWP1, "LA:/ScrapHeap/Adam/plans.txt", AuthenticationUtil.getAdminUserName())); - } - catch (Exception e) - { - e.printStackTrace(); - fail(); - } + public Object doWork() throws Exception + { + try + { + lockingService.modifyLock( + testWP1, "ScrapHeap/Adam/plans.txt", "Spike", + testWP1, "TheInitiative/Adam/plans.txt", EMPTY_MAP); + fail("Failed to prevent lock modification by non-owner."); + } + catch (AVMLockingException e) + { + // Expected + } + + return null; + } + }, "Buffy"); } /** @@ -385,114 +310,104 @@ public class AVMLockingServiceTest extends TestCase { AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); - fService.createStore("main"); - - fLockingService.addWebProject("main"); + if (avmService.getStore("main") == null) + { + avmService.createStore("main"); + } // note: locking applies to WCM web projects, hence relies on WCM sandbox conventions (naming and properties) - fService.setStoreProperty("main", SandboxConstants.PROP_WEB_PROJECT_NODE_REF, new PropertyValue(DataTypeDefinition.NODE_REF, new NodeRef("workspace://SpacesStore/dummy"))); + avmService.setStoreProperty("main", SandboxConstants.PROP_WEB_PROJECT_NODE_REF, new PropertyValue(DataTypeDefinition.NODE_REF, new NodeRef("workspace://SpacesStore/dummy"))); - fService.createStore("main--admin"); + if (avmService.getStore("main--admin") == null) + { + avmService.createStore("main--admin"); + } setupBasicTree0(); - List diffs = fSyncService.compare(-1, "main:/", -1, "main--admin:/", null); + List diffs = syncService.compare(-1, "main:/", -1, "main--admin:/", null); assertEquals(2, diffs.size()); assertEquals("[main:/a[-1] > main--admin:/a[-1], main:/d[-1] > main--admin:/d[-1]]", diffs.toString()); - fSyncService.update(diffs, null, false, false, false, false, null, null); + syncService.update(diffs, null, false, false, false, false, null, null); RetryingTransactionHelper.RetryingTransactionCallback cb = new RetryingTransactionHelper.RetryingTransactionCallback() { public Object execute() throws Exception { BulkLoader loader = new BulkLoader(); - loader.setAvmService(fService); + loader.setAvmService(avmService); loader.recursiveLoad("source/java/org/alfresco/repo/avm", "main--admin:/"); return null; } }; - RetryingTransactionHelper helper = (RetryingTransactionHelper) fContext.getBean("retryingTransactionHelper"); + RetryingTransactionHelper helper = (RetryingTransactionHelper) ctx.getBean("retryingTransactionHelper"); helper.doInTransaction(cb); } - catch (Exception e) - { - e.printStackTrace(); - throw e; - } finally { - fLockingService.removeStoreLocks("main"); - fLockingService.removeWebProject("main"); + lockingService.removeLocks("main"); - fService.purgeStore("main--admin"); - fService.purgeStore("main"); + avmService.purgeStore("main--admin"); + avmService.purgeStore("main"); AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName()); } } // Minimal test of locking with file 'rename' across web projects + @SuppressWarnings("deprecation") public void testLockingAwareServiceFileRename() throws Exception { + lockingService.removeLocks("wpA"); + lockingService.removeLocks("wpB"); try { AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); - fService.createStore("wpA"); - fLockingService.addWebProject("wpA"); + avmService.createStore("wpA"); + avmService.createStore("wpA--admin"); - fService.createStore("wpA--admin"); - - fService.createStore("wpB"); - fLockingService.addWebProject("wpB"); - - fService.createStore("wpB--admin"); + avmService.createStore("wpB"); + avmService.createStore("wpB--admin"); // note: locking applies to WCM web projects, hence relies on WCM sandbox conventions (naming and properties) - fService.setStoreProperty("wpA", SandboxConstants.PROP_WEB_PROJECT_NODE_REF, new PropertyValue(DataTypeDefinition.NODE_REF, new NodeRef("workspace://SpacesStore/dummyA"))); - fService.setStoreProperty("wpB", SandboxConstants.PROP_WEB_PROJECT_NODE_REF, new PropertyValue(DataTypeDefinition.NODE_REF, new NodeRef("workspace://SpacesStore/dummyB"))); + avmService.setStoreProperty("wpA", SandboxConstants.PROP_WEB_PROJECT_NODE_REF, new PropertyValue(DataTypeDefinition.NODE_REF, new NodeRef("workspace://SpacesStore/dummyA"))); + avmService.setStoreProperty("wpB", SandboxConstants.PROP_WEB_PROJECT_NODE_REF, new PropertyValue(DataTypeDefinition.NODE_REF, new NodeRef("workspace://SpacesStore/dummyB"))); - assertNull(fLockingService.getLock("wpA", "/file1.txt")); - assertTrue(fLockingService.hasAccess("wpA", "wpA--admin:/file1.txt", "admin")); + assertNull(lockingService.getLockOwner("wpA", "/file1.txt")); + assertTrue(lockingService.hasAccess("wpA", "wpA--admin:/file1.txt", "admin")); - fService.createFile("wpA--admin:/", "file1.txt").close(); + avmService.createFile("wpA--admin:/", "file1.txt").close(); - assertNotNull(fLockingService.getLock("wpA", "/file1.txt")); - assertEquals("admin", fLockingService.getLock("wpA", "/file1.txt").getOwners().get(0)); - assertTrue(fLockingService.hasAccess("wpA", "wpA--admin:/file1.txt", "admin")); + assertNotNull(lockingService.getLockOwner("wpA", "/file1.txt")); + assertEquals("admin", lockingService.getLockOwner("wpA", "/file1.txt")); + assertTrue(lockingService.hasAccess("wpA", "wpA--admin:/file1.txt", "admin")); - assertNull(fLockingService.getLock("wpB", "/file1.txt")); - assertTrue(fLockingService.hasAccess("wpB", "wpB--admin:/file1.txt", "admin")); + assertNull(lockingService.getLockOwner("wpB", "/file1.txt")); + assertTrue(lockingService.hasAccess("wpB", "wpB--admin:/file1.txt", "admin")); // ETHREEOH-1544 - fService.rename("wpA--admin:/", "file1.txt", "wpB--admin:/", "file1.txt"); + avmService.rename("wpA--admin:/", "file1.txt", "wpB--admin:/", "file1.txt"); - assertNull(fLockingService.getLock("wpA", "/file1.txt")); - assertTrue(fLockingService.hasAccess("wpA", "wpA--admin:/file1.txt", "admin")); + assertNull(lockingService.getLockOwner("wpA", "/file1.txt")); + assertTrue(lockingService.hasAccess("wpA", "wpA--admin:/file1.txt", "admin")); - assertNotNull(fLockingService.getLock("wpB", "/file1.txt")); - assertEquals("admin", fLockingService.getLock("wpB", "/file1.txt").getOwners().get(0)); - assertTrue(fLockingService.hasAccess("wpB", "wpB--admin:/file1.txt", "admin")); - } - catch (Exception e) - { - e.printStackTrace(); - throw e; + assertNotNull(lockingService.getLockOwner("wpB", "/file1.txt")); + assertEquals("admin", lockingService.getLockOwner("wpB", "/file1.txt")); + assertTrue(lockingService.hasAccess("wpB", "wpB--admin:/file1.txt", "admin")); } finally { - try { fLockingService.removeStoreLocks("wpA"); } catch (Exception e) {} - try { fLockingService.removeWebProject("wpA"); } catch (Exception e) {} + try { lockingService.removeLocks("wpA"); } catch (Exception e) {} - if (fService.getStore("wpA--admin") != null) { fService.purgeStore("wpA--admin"); } - if (fService.getStore("wpA") != null) { fService.purgeStore("wpA"); } + if (avmService.getStore("wpA--admin") != null) { avmService.purgeStore("wpA--admin"); } + if (avmService.getStore("wpA") != null) { avmService.purgeStore("wpA"); } - try { fLockingService.removeStoreLocks("wpB"); } catch (Exception e) {} - try { fLockingService.removeWebProject("wpB"); } catch (Exception e) {} + try { lockingService.removeLocks("wpB"); } catch (Exception e) {} - if (fService.getStore("wpB--admin") != null) { fService.purgeStore("wpB--admin"); } - if (fService.getStore("wpB") != null) { fService.purgeStore("wpB"); } + if (avmService.getStore("wpB--admin") != null) { avmService.purgeStore("wpB--admin"); } + if (avmService.getStore("wpB") != null) { avmService.purgeStore("wpB"); } AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName()); } @@ -504,26 +419,26 @@ public class AVMLockingServiceTest extends TestCase protected void setupBasicTree0() throws IOException { - fService.createDirectory("main:/", "a"); - fService.createDirectory("main:/a", "b"); - fService.createDirectory("main:/a/b", "c"); - fService.createDirectory("main:/", "d"); - fService.createDirectory("main:/d", "e"); - fService.createDirectory("main:/d/e", "f"); + avmService.createDirectory("main:/", "a"); + avmService.createDirectory("main:/a", "b"); + avmService.createDirectory("main:/a/b", "c"); + avmService.createDirectory("main:/", "d"); + avmService.createDirectory("main:/d", "e"); + avmService.createDirectory("main:/d/e", "f"); - fService.createFile("main:/a/b/c", "foo").close(); - ContentWriter writer = fService.getContentWriter("main:/a/b/c/foo", true); + avmService.createFile("main:/a/b/c", "foo").close(); + ContentWriter writer = avmService.getContentWriter("main:/a/b/c/foo", true); writer.setEncoding("UTF-8"); writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); writer.putContent("I am main:/a/b/c/foo"); - fService.createFile("main:/a/b/c", "bar").close(); - writer = fService.getContentWriter("main:/a/b/c/bar", true); + avmService.createFile("main:/a/b/c", "bar").close(); + writer = avmService.getContentWriter("main:/a/b/c/bar", true); // Force a conversion writer.setEncoding("UTF-16"); writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); writer.putContent("I am main:/a/b/c/bar"); - fService.createSnapshot("main", null, null); + avmService.createSnapshot("main", null, null); } } diff --git a/source/java/org/alfresco/repo/avm/wf/AVMSubmitLinkChecker.java b/source/java/org/alfresco/repo/avm/wf/AVMSubmitLinkChecker.java deleted file mode 100644 index 3117e56074..0000000000 --- a/source/java/org/alfresco/repo/avm/wf/AVMSubmitLinkChecker.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . */ - -package org.alfresco.repo.avm.wf; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -import org.alfresco.config.JNDIConstants; -import org.alfresco.linkvalidation.HrefValidationProgress; -import org.alfresco.linkvalidation.LinkValidationAction; -import org.alfresco.linkvalidation.LinkValidationReport; -import org.alfresco.repo.avm.AVMNodeConverter; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.workflow.jbpm.JBPMNode; -import org.alfresco.repo.workflow.jbpm.JBPMSpringActionHandler; -import org.alfresco.wcm.sandbox.SandboxConstants; -import org.alfresco.service.cmr.action.Action; -import org.alfresco.service.cmr.action.ActionService; -import org.alfresco.service.cmr.avm.AVMService; -import org.alfresco.service.cmr.repository.NodeRef; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.jbpm.graph.exe.ExecutionContext; -import org.springframework.beans.factory.BeanFactory; - -/** - * Performs a link validaton check for the workflow sandbox being used - * for a submisson process. - * - * @author gavinc - */ -public class AVMSubmitLinkChecker extends JBPMSpringActionHandler -{ - private static final long serialVersionUID = 1442635948148675461L; - - private static Log logger = LogFactory.getLog(AVMSubmitLinkChecker.class); - - /** - * The AVMService. - */ - private AVMService fAVMService; - - /** - * The ActionService. - */ - private ActionService fActionService; - - /** - * Set any bean references necessary. - * @param factory The BeanFactory from which to get beans. - */ - @Override - protected void initialiseHandler(BeanFactory factory) - { - this.fActionService = (ActionService)factory.getBean("ActionService"); - this.fAVMService = (AVMService)factory.getBean("AVMService"); - } - - /** - * Do the actual link validation check. - * - * @param executionContext The jBPM context. - */ - public void execute(ExecutionContext executionContext) throws Exception - { - // retrieve the workflow sandbox (the workflow package) - NodeRef pkg = ((JBPMNode)executionContext.getContextInstance().getVariable("bpm_package")).getNodeRef(); - - // get the store name - String storeName = pkg.getStoreRef().getIdentifier(); - - // retrieve the webapp name from the workflow execution context - String webappName = (String)executionContext.getContextInstance().getVariable("wcmwf_webapp"); - String webappPath = storeName + ":/" + JNDIConstants.DIR_DEFAULT_WWW + "/" + - JNDIConstants.DIR_DEFAULT_APPBASE + "/" + webappName; - NodeRef webappPathRef = AVMNodeConverter.ToNodeRef(-1, webappPath); - - if (logger.isDebugEnabled()) - logger.debug("Checking links in workflow webapp: " + webappPath); - - // create and execute the action - int brokenLinks = -1; - - try - { - HrefValidationProgress monitor = new HrefValidationProgress(); - Map args = new HashMap(1, 1.0f); - args.put(LinkValidationAction.PARAM_MONITOR, monitor); - args.put(LinkValidationAction.PARAM_COMPARE_TO_STAGING, Boolean.TRUE); - Action action = this.fActionService.createAction(LinkValidationAction.NAME, args); - this.fActionService.executeAction(action, webappPathRef, false, false); - - // retrieve the deployment report from the store property - PropertyValue val = this.fAVMService.getStoreProperty(storeName, - SandboxConstants.PROP_LINK_VALIDATION_REPORT); - if (val != null) - { - LinkValidationReport report = (LinkValidationReport)val.getSerializableValue(); - if (report != null && report.wasSuccessful()) - { - brokenLinks = report.getNumberBrokenLinks(); - } - } - - if (logger.isDebugEnabled()) - logger.debug("Link validation check found " + brokenLinks + " broken links"); - } - catch (Throwable err) - { - logger.error(err); - } - - // set the number of broken links in a variable, -1 indicates an error occured - executionContext.setVariable("wcmwf_brokenLinks", brokenLinks); - } -} diff --git a/source/java/org/alfresco/repo/cache/CacheTest.java b/source/java/org/alfresco/repo/cache/CacheTest.java index dd14125c38..0b705f5ecc 100644 --- a/source/java/org/alfresco/repo/cache/CacheTest.java +++ b/source/java/org/alfresco/repo/cache/CacheTest.java @@ -131,16 +131,28 @@ public class CacheTest extends TestCase assertNull("Non-transactional remove didn't go to backing cache", backingCache.get(key)); } + private static final String NEW_GLOBAL_ONE = "new_global_one"; + private static final String NEW_GLOBAL_TWO = "new_global_two"; + private static final String NEW_GLOBAL_THREE = "new_global_three"; + private static final String UPDATE_TXN_THREE = "updated_txn_three"; + private static final String UPDATE_TXN_FOUR = "updated_txn_four"; + public void testRollbackCleanup() throws Exception { TransactionService transactionService = serviceRegistry.getTransactionService(); RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper(); + + // Add items to the global cache + backingCache.put(NEW_GLOBAL_ONE, NEW_GLOBAL_ONE); RetryingTransactionCallback callback = new RetryingTransactionCallback() { private int throwCount = 0; public Object execute() throws Throwable { + transactionalCache.put(NEW_GLOBAL_TWO, NEW_GLOBAL_TWO); + transactionalCache.remove(NEW_GLOBAL_ONE); + String key = "B"; String value = "BBB"; // no transaction - do a put @@ -151,24 +163,32 @@ public class CacheTest extends TestCase throwCount++; throw new SQLException("Dummy"); } - return null; + else + { + throw new Exception("Fail"); + } } }; - txnHelper.doInTransaction(callback); + try + { + txnHelper.doInTransaction(callback); + } + catch (Exception e) + { + // Expected + } + + assertFalse("Remove not done after rollback", transactionalCache.contains(NEW_GLOBAL_ONE)); + assertFalse("Update happened after rollback", transactionalCache.contains(NEW_GLOBAL_TWO)); } public void testTransactionalCacheWithSingleTxn() throws Throwable { - String newGlobalOne = "new_global_one"; - String newGlobalTwo = "new_global_two"; - String newGlobalThree = "new_global_three"; - String updatedTxnThree = "updated_txn_three"; - String updatedTxnFour = "updated_txn_four"; // add item to global cache - backingCache.put(newGlobalOne, newGlobalOne); - backingCache.put(newGlobalTwo, newGlobalTwo); - backingCache.put(newGlobalThree, newGlobalThree); + backingCache.put(NEW_GLOBAL_ONE, NEW_GLOBAL_ONE); + backingCache.put(NEW_GLOBAL_TWO, NEW_GLOBAL_TWO); + backingCache.put(NEW_GLOBAL_THREE, NEW_GLOBAL_THREE); TransactionService transactionService = serviceRegistry.getTransactionService(); UserTransaction txn = transactionService.getUserTransaction(); @@ -178,29 +198,29 @@ public class CacheTest extends TestCase txn.begin(); // remove 1 from the cache - transactionalCache.remove(newGlobalOne); - assertFalse("Item was not removed from txn cache", transactionalCache.contains(newGlobalOne)); - assertNull("Get didn't return null", transactionalCache.get(newGlobalOne)); - assertTrue("Item was removed from backing cache", backingCache.contains(newGlobalOne)); + transactionalCache.remove(NEW_GLOBAL_ONE); + assertFalse("Item was not removed from txn cache", transactionalCache.contains(NEW_GLOBAL_ONE)); + assertNull("Get didn't return null", transactionalCache.get(NEW_GLOBAL_ONE)); + assertTrue("Item was removed from backing cache", backingCache.contains(NEW_GLOBAL_ONE)); // update 3 in the cache - transactionalCache.put(updatedTxnThree, "XXX"); - assertEquals("Item not updated in txn cache", "XXX", transactionalCache.get(updatedTxnThree)); + transactionalCache.put(UPDATE_TXN_THREE, "XXX"); + assertEquals("Item not updated in txn cache", "XXX", transactionalCache.get(UPDATE_TXN_THREE)); assertFalse("Item was put into backing cache (excl. NullValueMarker)", - backingCache.contains(updatedTxnThree) && - !(backingCache.get(updatedTxnThree) instanceof NullValueMarker)); + backingCache.contains(UPDATE_TXN_THREE) && + !(backingCache.get(UPDATE_TXN_THREE) instanceof NullValueMarker)); // check that the keys collection is correct Collection transactionalKeys = transactionalCache.getKeys(); - assertFalse("Transactionally removed item found in keys", transactionalKeys.contains(newGlobalOne)); - assertTrue("Transactionally added item not found in keys", transactionalKeys.contains(updatedTxnThree)); + assertFalse("Transactionally removed item found in keys", transactionalKeys.contains(NEW_GLOBAL_ONE)); + assertTrue("Transactionally added item not found in keys", transactionalKeys.contains(UPDATE_TXN_THREE)); // Register a post-commit cache reader to make sure that nothing blows up if the cache is hit in post-commit - PostCommitCacheReader listenerReader = new PostCommitCacheReader(transactionalCache, updatedTxnThree); + PostCommitCacheReader listenerReader = new PostCommitCacheReader(transactionalCache, UPDATE_TXN_THREE); AlfrescoTransactionSupport.bindListener(listenerReader); // Register a post-commit cache reader to make sure that nothing blows up if the cache is hit in post-commit - PostCommitCacheWriter listenerWriter = new PostCommitCacheWriter(transactionalCache, updatedTxnFour, "FOUR"); + PostCommitCacheWriter listenerWriter = new PostCommitCacheWriter(transactionalCache, UPDATE_TXN_FOUR, "FOUR"); AlfrescoTransactionSupport.bindListener(listenerWriter); // commit the transaction @@ -217,13 +237,13 @@ public class CacheTest extends TestCase } // check that backing cache was updated with the in-transaction changes - assertFalse("Item was not removed from backing cache", backingCache.contains(newGlobalOne)); - assertNull("Item could still be fetched from backing cache", backingCache.get(newGlobalOne)); - assertEquals("Item not updated in backing cache", "XXX", backingCache.get(updatedTxnThree)); + assertFalse("Item was not removed from backing cache", backingCache.contains(NEW_GLOBAL_ONE)); + assertNull("Item could still be fetched from backing cache", backingCache.get(NEW_GLOBAL_ONE)); + assertEquals("Item not updated in backing cache", "XXX", backingCache.get(UPDATE_TXN_THREE)); // Check that the transactional cache serves get requests assertEquals("Transactional cache must serve post-commit get requests", "XXX", - transactionalCache.get(updatedTxnThree)); + transactionalCache.get(UPDATE_TXN_THREE)); } catch (Throwable e) { diff --git a/source/java/org/alfresco/repo/cache/TransactionalCache.java b/source/java/org/alfresco/repo/cache/TransactionalCache.java index e58a1ba0a7..c7682c97fc 100644 --- a/source/java/org/alfresco/repo/cache/TransactionalCache.java +++ b/source/java/org/alfresco/repo/cache/TransactionalCache.java @@ -25,7 +25,6 @@ import java.util.Map; import java.util.Set; import net.sf.ehcache.CacheException; -import net.sf.ehcache.CacheManager; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; @@ -141,13 +140,6 @@ public class TransactionalCache this.sharedCache = sharedCache; } - /** - * No-op - */ - public void setCacheManager(CacheManager cacheManager) - { - } - /** * Set the maximum number of elements to store in the update and remove caches. * The maximum number of elements stored in the transaction will be twice the @@ -370,6 +362,7 @@ public class TransactionalCache * Where a transaction is present, a cache of updated items is lazily added to the * thread and the Object put onto that. */ + @SuppressWarnings("unchecked") public void put(K key, V value) { // are we in a transaction? @@ -417,14 +410,9 @@ public class TransactionalCache txnData.haveIssuedFullWarning = true; } } + Object existingValueObj = sharedCache.get(key); CacheBucket bucket = null; - if (sharedCache.contains(key)) - { - V existingValue = getSharedCacheValue(key); - // The value needs to be kept for later checks - bucket = new UpdateCacheBucket(existingValue, value); - } - else + if (existingValueObj == null) { // Insert a 'null' marker into the shared cache NullValueMarker nullMarker = new NullValueMarker(); @@ -432,6 +420,16 @@ public class TransactionalCache // The value didn't exist before bucket = new NewCacheBucket(nullMarker, value); } + else if (existingValueObj instanceof NullValueMarker) + { + // Record the null as is + bucket = new NewCacheBucket((NullValueMarker)existingValueObj, value); + } + else + { + // Record the existing value as is + bucket = new UpdateCacheBucket((V)existingValueObj, value); + } txnData.updatedItemsCache.put(key, bucket); // remove the item from the removed cache, if present txnData.removedItemsCache.remove(key); @@ -619,21 +617,19 @@ public class TransactionalCache sharedCache.clear(); if (isDebugEnabled) { - logger.debug("Clear notification recieved at end of transaction - clearing shared cache"); + logger.debug("Clear notification recieved in commit - clearing shared cache"); } } else { // transfer any removed items - // any removed items will have also been removed from the in-transaction updates - // propogate the deletes to the shared cache for (Serializable key : txnData.removedItemsCache) { sharedCache.remove(key); } if (isDebugEnabled) { - logger.debug("Removed " + txnData.removedItemsCache.size() + " values from shared cache"); + logger.debug("Removed " + txnData.removedItemsCache.size() + " values from shared cache in commit"); } } @@ -661,13 +657,45 @@ public class TransactionalCache } /** - * Just allow the transactional caches to be thrown away + * Transfers cache removals or clears. This allows explicit cache cleanup to be propagated + * to the shared cache even in the event of rollback - useful if the cause of a problem is + * the shared cache value. */ public void afterRollback() { TransactionData txnData = getTransactionData(); - // drop caches from cachemanager - removeCaches(txnData); + try + { + if (txnData.isClearOn) + { + // clear shared cache + sharedCache.clear(); + if (isDebugEnabled) + { + logger.debug("Clear notification recieved in rollback - clearing shared cache"); + } + } + else + { + // transfer any removed items + for (Serializable key : txnData.removedItemsCache) + { + sharedCache.remove(key); + } + if (isDebugEnabled) + { + logger.debug("Removed " + txnData.removedItemsCache.size() + " values from shared cache in rollback"); + } + } + } + catch (CacheException e) + { + throw new AlfrescoRuntimeException("Failed to transfer updates to shared cache", e); + } + finally + { + removeCaches(txnData); + } } /** diff --git a/source/java/org/alfresco/repo/cache/lookup/EntityLookupCache.java b/source/java/org/alfresco/repo/cache/lookup/EntityLookupCache.java index 0b6158f39d..2c03e99daf 100644 --- a/source/java/org/alfresco/repo/cache/lookup/EntityLookupCache.java +++ b/source/java/org/alfresco/repo/cache/lookup/EntityLookupCache.java @@ -488,7 +488,7 @@ public class EntityLookupCachenull not allowed) - * @param value The new entity value (may be null null) + * @param value The new entity value (may be null) * @return Returns the row update count. */ @SuppressWarnings("unchecked") @@ -528,6 +528,40 @@ public class EntityLookupCachenull not allowed) + * @param value The new entity value (may be null) + */ + @SuppressWarnings("unchecked") + public void setValue(K key, V value) + { + // Handle missing cache + if (cache == null) + { + return; + } + + // Remove entries for the key (bidirectional removal removes the old value as well) + removeByKey(key); + + // Get the value key. + VK valueKey = (value == null) ? (VK)VALUE_NULL : entityLookup.getValueKey(value); + // Check if the value has a good key + if (valueKey != null) + { + // There is a good value key, cache by value + CacheRegionValueKey valueCacheKey = new CacheRegionValueKey(cacheRegion, valueKey); + cache.put(valueCacheKey, key); + } + // Cache by key + cache.put( + new CacheRegionKey(cacheRegion, key), + (value == null ? VALUE_NULL : value)); + // Done + } + /** * Delete the entity associated with the given key. * The {@link EntityLookupCallbackDAO#deleteByKey(Serializable)} callback will be used if necessary. diff --git a/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java b/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java index 9b93414481..4462715769 100644 --- a/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java +++ b/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleaner.java @@ -28,7 +28,6 @@ import org.alfresco.repo.domain.avm.AVMNodeDAO; import org.alfresco.repo.domain.contentdata.ContentDataDAO; import org.alfresco.repo.domain.contentdata.ContentDataDAO.ContentUrlHandler; import org.alfresco.repo.lock.JobLockService; -import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.ContentService; @@ -89,7 +88,6 @@ public class ContentStoreCleaner private ContentDataDAO contentDataDAO; private DictionaryService dictionaryService; private ContentService contentService; - private NodeDaoService nodeDaoService; private AVMNodeDAO avmNodeDAO; private TransactionService transactionService; private int protectDays; @@ -139,14 +137,6 @@ public class ContentStoreCleaner this.contentService = contentService; } - /** - * @param nodeDaoService used to get the property values - */ - public void setNodeDaoService(NodeDaoService nodeDaoService) - { - this.nodeDaoService = nodeDaoService; - } - /** * @param avmNodeDAO The AVM Node DAO to get urls with. */ @@ -191,7 +181,6 @@ public class ContentStoreCleaner PropertyCheck.mandatory(this, "contentDataDAO", contentDataDAO); PropertyCheck.mandatory(this, "dictionaryService", dictionaryService); PropertyCheck.mandatory(this, "contentService", contentService); - PropertyCheck.mandatory(this, "nodeDaoService", nodeDaoService); PropertyCheck.mandatory(this, "avmNodeDAO", avmNodeDAO); PropertyCheck.mandatory(this, "transactionService", transactionService); PropertyCheck.mandatory(this, "eagerContentStoreCleaner", eagerContentStoreCleaner); diff --git a/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleanerScalabilityRunner.java b/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleanerScalabilityRunner.java index 2a4f9d1358..4562c220b3 100644 --- a/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleanerScalabilityRunner.java +++ b/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleanerScalabilityRunner.java @@ -19,8 +19,6 @@ package org.alfresco.repo.content.cleanup; import java.io.File; -import java.io.Serializable; -import java.lang.reflect.Method; import java.util.Collections; import java.util.Date; @@ -32,30 +30,23 @@ import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.filestore.FileContentReader; import org.alfresco.repo.content.filestore.FileContentStore; import org.alfresco.repo.content.filestore.FileContentWriter; -import org.alfresco.repo.node.db.NodeDaoService; -import org.alfresco.repo.node.db.NodeDaoService.NodePropertyHandler; -import org.alfresco.repo.transaction.SingleEntryTransactionResourceInterceptor; +import org.alfresco.repo.domain.node.ChildAssocEntity; +import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -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.ContentIOException; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; -import org.alfresco.service.cmr.repository.NodeRef; 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.tools.Repository; import org.alfresco.tools.ToolException; -import org.alfresco.util.GUID; import org.alfresco.util.TempFileProvider; import org.alfresco.util.VmShutdownListener; import org.apache.commons.lang.mutable.MutableInt; -import org.hibernate.SessionFactory; import org.springframework.context.ApplicationContext; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; /** * Loads the repository up with orphaned content and then runs the cleaner. @@ -71,11 +62,9 @@ public class ContentStoreCleanerScalabilityRunner extends Repository private VmShutdownListener vmShutdownListener = new VmShutdownListener("ContentStoreCleanerScalabilityRunner"); private ApplicationContext ctx; - private SingleEntryTransactionResourceInterceptor txnResourceInterceptor; - private HibernateHelper hibernateHelper; + private NodeHelper nodeHelper; private TransactionService transactionService; - private NodeDaoService nodeDaoService; - private DictionaryService dictionaryService; + private NodeDAO nodeDAO; private ContentStore contentStore; private ContentStoreCleaner cleaner; @@ -92,15 +81,10 @@ public class ContentStoreCleanerScalabilityRunner extends Repository { ctx = super.getApplicationContext(); - txnResourceInterceptor = (SingleEntryTransactionResourceInterceptor) ctx.getBean("sessionSizeResourceInterceptor"); - - SessionFactory sessionFactory = (SessionFactory) ctx.getBean("sessionFactory"); - hibernateHelper = new HibernateHelper(); - hibernateHelper.setSessionFactory(sessionFactory); + nodeHelper = new NodeHelper(); transactionService = (TransactionService) ctx.getBean("TransactionService"); - nodeDaoService = (NodeDaoService) ctx.getBean("nodeDaoService"); - dictionaryService = (DictionaryService) ctx.getBean("dictionaryService"); + nodeDAO = (NodeDAO) ctx.getBean("nodeDAO"); int orphanCount = 1000; @@ -108,11 +92,6 @@ public class ContentStoreCleanerScalabilityRunner extends Repository loadData(orphanCount); - long beforeIterate = System.currentTimeMillis(); -// iterateOverProperties(); - long afterIterate = System.currentTimeMillis(); - double aveIterate = (double) (afterIterate - beforeIterate) / (double) orphanCount / 1000D; - System.out.println("Ready to clean store: " + contentStore); synchronized(this) { @@ -125,7 +104,6 @@ public class ContentStoreCleanerScalabilityRunner extends Repository double aveClean = (double) (afterClean - beforeClean) / (double) orphanCount / 1000D; System.out.println(); - System.out.println(String.format("Iterating took %3f per 1000 content URLs in DB", aveIterate)); System.out.println(String.format("Cleaning took %3f per 1000 content URLs in DB", aveClean)); return 0; @@ -144,7 +122,7 @@ public class ContentStoreCleanerScalabilityRunner extends Repository // We don't need to write anything String contentUrl = FileContentStore.createNewFileStoreUrl(); ContentData contentData = new ContentData(contentUrl, MimetypeMap.MIMETYPE_TEXT_PLAIN, 10, "UTF-8"); - hibernateHelper.makeNode(contentData); + nodeHelper.makeNode(contentData); int count = doneCount.intValue(); count++; @@ -172,37 +150,6 @@ public class ContentStoreCleanerScalabilityRunner extends Repository } } - private void iterateOverProperties() - { - final NodePropertyHandler nodePropertyHandler = new NodePropertyHandler() - { - int count = 0; - public void handle(NodeRef nodeRef, QName nodeTypeQName, QName propertyQName, Serializable value) - { - count++; - if (count % 1000 == 0) - { - System.out.println(" " + (new Date()) + "Iterated over " + count + " content items"); - } - if (vmShutdownListener.isVmShuttingDown()) - { - throw new RuntimeException("VM Shut down"); - } - } - }; - final DataTypeDefinition contentDataType = dictionaryService.getDataType(DataTypeDefinition.CONTENT); - // execute in READ-WRITE txn - RetryingTransactionCallback getUrlsCallback = new RetryingTransactionCallback() - { - public Object execute() throws Exception - { - nodeDaoService.getPropertyValuesByActualType(contentDataType, nodePropertyHandler); - return null; - }; - }; - transactionService.getRetryingTransactionHelper().doInTransaction(getUrlsCallback); - } - private void clean() { ContentStoreCleanerListener listener = new ContentStoreCleanerListener() @@ -297,11 +244,11 @@ public class ContentStoreCleanerScalabilityRunner extends Repository } } - private class HibernateHelper extends HibernateDaoSupport + private class NodeHelper { private QName contentQName; - public HibernateHelper() + public NodeHelper() { contentQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "realContent"); } @@ -311,8 +258,18 @@ public class ContentStoreCleanerScalabilityRunner extends Repository public void makeNode(ContentData contentData) { StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore"); - Long nodeId = nodeDaoService.newNode(storeRef, GUID.generate(), ContentModel.TYPE_CONTENT).getFirst(); - nodeDaoService.addNodeProperty(nodeId, contentQName, contentData); + Long rootNodeId = nodeDAO.newStore(storeRef).getFirst(); + ChildAssocEntity assoc = nodeDAO.newNode( + rootNodeId, + ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, + storeRef, + null, + ContentModel.TYPE_CONTENT, + null, + null); + Long nodeId = assoc.getChildNode().getId(); + nodeDAO.addNodeProperty(nodeId, contentQName, contentData); } } } diff --git a/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleanerTest.java b/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleanerTest.java index 9389dcfcd4..1b6c632f67 100644 --- a/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleanerTest.java +++ b/source/java/org/alfresco/repo/content/cleanup/ContentStoreCleanerTest.java @@ -22,8 +22,10 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import junit.framework.TestCase; @@ -33,7 +35,6 @@ import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.domain.avm.AVMNodeDAO; import org.alfresco.repo.domain.contentdata.ContentDataDAO; import org.alfresco.repo.lock.JobLockService; -import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.ServiceRegistry; @@ -83,8 +84,7 @@ public class ContentStoreCleanerTest extends TestCase jobLockService = serviceRegistry.getJobLockService(); TransactionService transactionService = serviceRegistry.getTransactionService(); DictionaryService dictionaryService = serviceRegistry.getDictionaryService(); - NodeDaoService nodeDaoService = (NodeDaoService) ctx.getBean("nodeDaoService"); - AVMNodeDAO avmNodeDAO = (AVMNodeDAO) ctx.getBean("newAvmNodeDAO"); + AVMNodeDAO avmNodeDAO = (AVMNodeDAO) ctx.getBean("newAvmNodeDAO"); ContentDataDAO contentDataDAO = (ContentDataDAO) ctx.getBean("contentDataDAO"); // we need a store @@ -107,7 +107,6 @@ public class ContentStoreCleanerTest extends TestCase cleaner.setTransactionService(transactionService); cleaner.setDictionaryService(dictionaryService); cleaner.setContentService(contentService); - cleaner.setNodeDaoService(nodeDaoService); cleaner.setAvmNodeDAO(avmNodeDAO); } @@ -116,9 +115,28 @@ public class ContentStoreCleanerTest extends TestCase AuthenticationUtil.clearCurrentSecurityContext(); } + private void checkForExistence(Set urls, boolean mustExist) + { + for (String url : urls) + { + ContentReader rawReader = contentService.getRawReader(url); + if (mustExist && !rawReader.exists()) + { + fail("Content URL should have existed but did not: " + url); + } + else if (!mustExist && rawReader.exists()) + { + fail("Content URL should not have existed but did: " + url); + } + } + } + public void testEagerCleanupOnCommit() throws Exception { eagerCleaner.setEagerOrphanCleanup(true); + final Set urlsToExist = new HashSet(); + final Set urlsToMiss = new HashSet(); + // Create a new file RetryingTransactionCallback makeContentCallback = new RetryingTransactionCallback() { @@ -137,16 +155,17 @@ public class ContentStoreCleanerTest extends TestCase ContentWriter writer = contentService.getWriter(contentNodeRef, ContentModel.PROP_CONTENT, true); writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); writer.putContent("INITIAL CONTENT"); + // Store the URL + urlsToExist.add(writer.getContentUrl()); // Done return contentNodeRef; } }; final NodeRef contentNodeRef = transactionService.getRetryingTransactionHelper().doInTransaction(makeContentCallback); - ContentReader contentReader = contentService.getReader(contentNodeRef, ContentModel.PROP_CONTENT); - assertTrue("Expect content to exist", contentReader.exists()); + checkForExistence(urlsToExist, true); + checkForExistence(urlsToMiss, false); // Now update the node, but force a failure i.e. txn rollback - final List newContentUrls = new ArrayList(); RetryingTransactionCallback failUpdateCallback = new RetryingTransactionCallback() { public String execute() throws Throwable @@ -155,7 +174,7 @@ public class ContentStoreCleanerTest extends TestCase writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); writer.putContent("CONTENT FOR FAIL"); // This will have updated the metadata, so we can fail now - newContentUrls.add(writer.getContentUrl()); + urlsToMiss.add(writer.getContentUrl()); // Done throw new RuntimeException("FAIL"); } @@ -179,10 +198,8 @@ public class ContentStoreCleanerTest extends TestCase } // Make sure that the new content is not there // The original content must still be there - assertEquals("Expected one content URL to play with", 1, newContentUrls.size()); - ContentReader readerMissing = contentService.getRawReader(newContentUrls.get(0)); - assertFalse("Newly created content should have been removed.", readerMissing.exists()); - assertTrue("Original content should still be there.", contentReader.exists()); + checkForExistence(urlsToExist, true); + checkForExistence(urlsToMiss, false); // Now update the node successfully RetryingTransactionCallback successUpdateCallback = new RetryingTransactionCallback() @@ -192,16 +209,35 @@ public class ContentStoreCleanerTest extends TestCase ContentWriter writer = contentService.getWriter(contentNodeRef, ContentModel.PROP_CONTENT, true); writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); writer.putContent("CONTENT FOR SUCCESS"); + // We expect the URL to be there, but the original URL must be removed + urlsToMiss.addAll(urlsToExist); + urlsToExist.clear(); + urlsToExist.add(writer.getContentUrl()); // Done return writer.getContentUrl(); } }; - String newContentUrl = transactionService.getRetryingTransactionHelper().doInTransaction(successUpdateCallback); + transactionService.getRetryingTransactionHelper().doInTransaction(successUpdateCallback); // Make sure that the new content is there // The original content was disposed of - ContentReader contentReaderNew = contentService.getRawReader(newContentUrl); - assertTrue("Newly created content should be present.", contentReaderNew.exists()); - assertFalse("Original content should have been removed.", contentReader.exists()); + checkForExistence(urlsToExist, true); + checkForExistence(urlsToMiss, false); + + // Now get/set ContentData without a change + RetryingTransactionCallback pointlessUpdateCallback = new RetryingTransactionCallback() + { + public ContentData execute() throws Throwable + { + ContentData contentData = (ContentData) nodeService.getProperty(contentNodeRef, ContentModel.PROP_CONTENT); + nodeService.setProperty(contentNodeRef, ContentModel.PROP_CONTENT, contentData); + // Done + return contentData; + } + }; + transactionService.getRetryingTransactionHelper().doInTransaction(pointlessUpdateCallback); + // Expect no change from before + checkForExistence(urlsToExist, true); + checkForExistence(urlsToMiss, false); // Now delete the node RetryingTransactionCallback deleteNodeCallback = new RetryingTransactionCallback() @@ -209,13 +245,17 @@ public class ContentStoreCleanerTest extends TestCase public Object execute() throws Throwable { nodeService.deleteNode(contentNodeRef); + // All URLs must be cleaned up + urlsToMiss.addAll(urlsToExist); + urlsToExist.clear(); // Done return null; } }; transactionService.getRetryingTransactionHelper().doInTransaction(deleteNodeCallback); // The new content must have disappeared - assertFalse("Newly created content should be removed.", contentReaderNew.exists()); + checkForExistence(urlsToExist, true); + checkForExistence(urlsToMiss, false); } /** @@ -302,7 +342,8 @@ public class ContentStoreCleanerTest extends TestCase writer.putContent("INITIAL CONTENT"); ContentData contentData = writer.getContentData(); - // Delete the first node + // Delete the first node, bypassing archive + nodeService.addAspect(contentNodeRef, ContentModel.ASPECT_TEMPORARY, null); nodeService.deleteNode(contentNodeRef); // Done diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryModelType.java b/source/java/org/alfresco/repo/dictionary/DictionaryModelType.java index 09de1255a7..983c208145 100644 --- a/source/java/org/alfresco/repo/dictionary/DictionaryModelType.java +++ b/source/java/org/alfresco/repo/dictionary/DictionaryModelType.java @@ -597,7 +597,7 @@ public class DictionaryModelType implements ContentServicePolicies.OnContentUpda { if (logger.isTraceEnabled()) { - logger.trace("beforeCommit: pendingModelsCnt="+pendingModels.size()+" ["+AlfrescoTransactionSupport.getTransactionId()+"]"); + logger.trace("beforeCommit: pendinpolicy-context.xmlgModelsCnt="+pendingModels.size()+" ["+AlfrescoTransactionSupport.getTransactionId()+"]"); } for (NodeRef pendingNodeRef : pendingModels) diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryRepositoryBootstrap.java b/source/java/org/alfresco/repo/dictionary/DictionaryRepositoryBootstrap.java index 22c7025509..44c1dff2b0 100644 --- a/source/java/org/alfresco/repo/dictionary/DictionaryRepositoryBootstrap.java +++ b/source/java/org/alfresco/repo/dictionary/DictionaryRepositoryBootstrap.java @@ -38,6 +38,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransacti import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; @@ -45,11 +46,12 @@ import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.Pair; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationEvent; +import org.springframework.dao.ConcurrencyFailureException; import org.springframework.extensions.surf.util.AbstractLifecycleBean; -import org.alfresco.util.Pair; /** * Bootstrap the dictionary from specified locations within the repository @@ -253,28 +255,41 @@ public class DictionaryRepositoryBootstrap extends AbstractLifecycleBean impleme { for (NodeRef dictionaryModel : nodeRefs) { - // Ignore if the node is a working copy or archived, or if its inactive - if (! (nodeService.hasAspect(dictionaryModel, ContentModel.ASPECT_WORKING_COPY) || nodeService.hasAspect(dictionaryModel, ContentModel.ASPECT_ARCHIVED))) + try { - Boolean isActive = (Boolean)nodeService.getProperty(dictionaryModel, ContentModel.PROP_MODEL_ACTIVE); - - if ((isActive != null) && (isActive.booleanValue() == true)) + // Ignore if the node is a working copy or archived, or if its inactive + if (! (nodeService.hasAspect(dictionaryModel, ContentModel.ASPECT_WORKING_COPY) || nodeService.hasAspect(dictionaryModel, ContentModel.ASPECT_ARCHIVED))) { - M2Model model = createM2Model(dictionaryModel); - if (model != null) + Boolean isActive = (Boolean)nodeService.getProperty(dictionaryModel, ContentModel.PROP_MODEL_ACTIVE); + + if ((isActive != null) && (isActive.booleanValue() == true)) { - if (logger.isTraceEnabled()) + M2Model model = createM2Model(dictionaryModel); + if (model != null) { - logger.trace("onDictionaryInit: "+model.getName()+" ("+dictionaryModel+")"); - } - - for (M2Namespace namespace : model.getNamespaces()) - { - modelMap.put(namespace.getUri(), new Pair(repositoryLocation, model)); + if (logger.isTraceEnabled()) + { + logger.trace("onDictionaryInit: "+model.getName()+" ("+dictionaryModel+")"); + } + + for (M2Namespace namespace : model.getNamespaces()) + { + modelMap.put(namespace.getUri(), new Pair(repositoryLocation, model)); + } } } } } + catch (InvalidNodeRefException inre) + { + // ignore - model no longer exists + if (logger.isDebugEnabled()) + { + logger.debug("onDictionaryInit: "+inre+" (assume concurrency failure)"); + } + + throw new ConcurrencyFailureException(inre.getMessage()); + } } } } diff --git a/source/java/org/alfresco/repo/domain/AccessControlListDAO.java b/source/java/org/alfresco/repo/domain/AccessControlListDAO.java index cfb4058413..f455532a27 100644 --- a/source/java/org/alfresco/repo/domain/AccessControlListDAO.java +++ b/source/java/org/alfresco/repo/domain/AccessControlListDAO.java @@ -30,7 +30,8 @@ import org.alfresco.service.cmr.repository.StoreRef; /** * This abstracts the reading and writing of ACLs on nodes from particular node implementations. * - * @author britt + * @author andyh + * @author janv */ public interface AccessControlListDAO { @@ -68,21 +69,13 @@ public interface AccessControlListDAO /** * Update any associated ACLs - * - * @param startingPoint - * @param chnages */ public void updateChangedAcls(NodeRef startingPoint, List changes); /** * Update inheritance - * - * @param parent - * @param inheritFrom - * @param previousId - * @return */ - public List setInheritanceForChildren(NodeRef parent, Long inheritFrom); + public List setInheritanceForChildren(NodeRef parent, Long inheritFrom, Long sharedAclToReplace); public Long getIndirectAcl(NodeRef nodeRef); @@ -95,4 +88,6 @@ public interface AccessControlListDAO public DbAccessControlList getAccessControlList(StoreRef storeRef); public void setAccessControlList(StoreRef storeRef, DbAccessControlList acl); + + public void updateInheritance(Long childNodeId, Long oldParentNodeId, Long newParentNodeId); } diff --git a/source/java/org/alfresco/repo/domain/DbAccessControlEntry.java b/source/java/org/alfresco/repo/domain/DbAccessControlEntry.java deleted file mode 100644 index 3d87a64c1a..0000000000 --- a/source/java/org/alfresco/repo/domain/DbAccessControlEntry.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain; - -import org.alfresco.repo.security.permissions.ACEType; -import org.alfresco.repo.security.permissions.AccessControlEntry; - - - -/** - * The interface against which permission entries are persisted - * - * @author andyh - */ - -public interface DbAccessControlEntry -{ - /** - * @return Returns the identifier for this object - */ - public Long getId(); - - /** - * @return Returns the version number for optimistic locking - */ - public Long getVersion(); - - /** - * @return Returns the permission to which this entry applies - */ - public DbPermission getPermission(); - - /** - * @param permission the permission to which the entry applies - */ - public void setPermission(DbPermission permission); - - /** - * @return Returns the authority to which this entry applies - */ - public DbAuthority getAuthority(); - - /** - * @param authority the authority to which this entry applies - */ - public void setAuthority(DbAuthority authority); - - /** - * @return Returns true if this permission is allowed - */ - public boolean isAllowed(); - - /** - * Set if this permission is allowed, otherwise it is denied. - * - * @param allowed - */ - public void setAllowed(boolean allowed); - - /** - * Get the ACE type - * @return - */ - public ACEType getAceType(); - - /** - * Set the ACEType - * @param type - */ - public void setAceType(ACEType type); - - /** - * Get the ACE context - may be null and may well mostly be null - * @return - */ - public DbAccessControlEntryContext getContext(); - - /** - * Set the ACE context - * @param context - */ - public void setContext(DbAccessControlEntryContext context); - - /** - * Helper method to delete the instance and make sure that all - * inverse associations are properly maintained. - */ - public void delete(); -} diff --git a/source/java/org/alfresco/repo/domain/DbAccessControlEntryContext.java b/source/java/org/alfresco/repo/domain/DbAccessControlEntryContext.java deleted file mode 100644 index e0e63caa96..0000000000 --- a/source/java/org/alfresco/repo/domain/DbAccessControlEntryContext.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain; - -/** - * Context for permission evaluation - * - * @author andyh - * - */ -public interface DbAccessControlEntryContext -{ - /** - * Get the id for this object - * @return - */ - public Long getId(); - - /** - * Get the version for this object - * @return - */ - public Long getVersion(); - - - /** - * Get the class context. - * - * This is a space separated list of QNames - * with an optional + or minus - * - * +QName => Must be of this type or have the aspect - * -Qname => Must not be of this type or have the aspect - * +QName +QName +QName => Must have all of these types - * -QName -Qname => Must not have any of these types - * QName QName QName => Must have one of the types - * QName => requires exact type match - * QName~ => requires a match on the type or subtype - * - * Supports () for grouping - * - * @return - */ - public String getClassContext(); - - /** - * Set the class context - as described above - * - * @param classContext - */ - public void setClassContext(String classContext); - - /** - * Get the property context - * - * QName QName Qname => property types to which it applies - * - * @return - */ - public String getPropertyContext(); - - /** - * Get the property context strin as a above - * @param propertyContext - */ - public void setPropertyContext(String propertyContext); - - /** - * Get the key value pair context - * - * Serialized Map - * - * @return - */ - public String getKvpContext(); - - /** - * Get the key value pair context - * @param kvpContext - */ - public void setKvpContext(String kvpContext); - -} diff --git a/source/java/org/alfresco/repo/domain/DbAccessControlList.java b/source/java/org/alfresco/repo/domain/DbAccessControlList.java index 4171f54d31..42c0506561 100644 --- a/source/java/org/alfresco/repo/domain/DbAccessControlList.java +++ b/source/java/org/alfresco/repo/domain/DbAccessControlList.java @@ -18,152 +18,14 @@ */ package org.alfresco.repo.domain; -import org.alfresco.repo.security.permissions.ACLCopyMode; -import org.alfresco.repo.security.permissions.ACLType; +import org.alfresco.repo.domain.permissions.Acl; /** - * The interface to support persistence of node access control entries in hibernate + * The interface to support persistence of node access control entries * * @author andyh */ -public interface DbAccessControlList +public interface DbAccessControlList extends Acl { - /** - * Get the long key - * @return - */ - public Long getId(); - - /** - * Get the ACL ID - * @return - */ - public String getAclId(); - - /** - * Get the ACL version - * @return - */ - public long getAclVersion(); - - /** - * Is this the latest version of the acl identified by the acl id string? - * @return - */ - public boolean isLatest(); - - /** - * @return Returns the version number for optimistic locking - */ - public Long getVersion(); - - /** - * Get inheritance behaviour - * @return Returns the inheritance status of this list - */ - public boolean getInherits(); - - /** - * Get the ACL from which this one inherits - * - * @return - */ - public Long getInheritsFrom(); - - /** - * Get the type for this ACL - * - * @return - */ - public ACLType getAclType(); - - /** - * Get the ACL inherited from nodes which have this ACL - * - * @return - */ - public Long getInheritedAclId(); - - /** - * Is this ACL versioned - if not there will be no old versions of the ACL - * and the long id will remain unchanged. - * - * If an acl is versioned it can not be updated - a new copy has to be created, - * - * @return - */ - public boolean isVersioned(); - - /** - * Set the string ACL ID (not the auto generated long) - * @param id - */ - - public void setAclId(String id); - - - /** - * Set the ACL version (not the optimistic version used by hibernate) - * @param version - */ - public void setAclVersion(long version); - - /** - * Set if this ACL is the latest version of the ACL as identified by getAclId() - * @param isLatest - */ - public void setLatest(boolean isLatest); - - /** - * Set inheritance behaviour - * @param inherits true to set the permissions to inherit - */ - public void setInherits(boolean inherits); - - /** - * Set the ACL from which this one inherits - * @param id - */ - public void setInheritsFrom(Long id); - - /** - * Set the ACL Type - * @param type - */ - public void setAclType(ACLType type); - - /** - * Set the ACL that should be set when inheriting from this one. - * This ACL does not contain any object specific settings. - * @param acl - */ - public void setInheritedAclId(Long acl); - - /** - * Set if this ACL is versioned on write - * @param isVersioned - */ - public void setVersioned(boolean isVersioned); - - /** - * Set the change set - * @param aclChangeSet - */ - public void setAclChangeSet(DbAccessControlListChangeSet aclChangeSet); - - /** - * Get the change set - * @return - */ - public DbAccessControlListChangeSet getAclChangeSet(); - - // Stuff to fix up in AVM - - public DbAccessControlList getCopy(Long parent, ACLCopyMode node); - - public void setRequiresVersion(boolean requiresVersion); - - public boolean getRequiresVersion(); - } diff --git a/source/java/org/alfresco/repo/domain/DbAccessControlListChangeSet.java b/source/java/org/alfresco/repo/domain/DbAccessControlListChangeSet.java deleted file mode 100644 index f62ab33926..0000000000 --- a/source/java/org/alfresco/repo/domain/DbAccessControlListChangeSet.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain; - -public interface DbAccessControlListChangeSet -{ - /** - * Get the long key - * @return - */ - public Long getId(); - - /** - * @return Returns the version number for optimistic locking - */ - public Long getVersion(); - -} diff --git a/source/java/org/alfresco/repo/domain/DbAccessControlListMember.java b/source/java/org/alfresco/repo/domain/DbAccessControlListMember.java deleted file mode 100644 index 02b0c4a8b0..0000000000 --- a/source/java/org/alfresco/repo/domain/DbAccessControlListMember.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain; - -/** - * Realtes an ACE to an ACL with a position - * - * @author andyh - * - */ -public interface DbAccessControlListMember -{ - /** - * Get the ID for the membership entry - * @return - the id - */ - public Long getId(); - - /** - * Get the version for this membership entry - * @return - the version - */ - public Long getVersion(); - - /** - * Get the ACL to which the ACE belongs. - * @return - the acl id - */ - public DbAccessControlList getAccessControlList(); - - /** - * Get the ACE included in the ACL - * @return - the ace id - */ - public DbAccessControlEntry getAccessControlEntry(); - - /** - * Get the position group for this member in the ACL - * - * 0 - implies the ACE is om the object - * >0 - that it is inhertied in some way - * - * The lower values are checked first so take precidence. - * - * @return - the position of the ace in the acl - */ - public int getPosition(); - - /** - * Set the ACL - * @param acl - */ - public void setAccessControlList(DbAccessControlList acl); - - /** - * Set the ACE - * @param ace - */ - public void setAccessControlEntry(DbAccessControlEntry ace); - - /** - * Set the position for the ACL-ACE relationship - * @param position - */ - public void setPosition(int position); -} diff --git a/source/java/org/alfresco/repo/domain/DbAuthority.java b/source/java/org/alfresco/repo/domain/DbAuthority.java deleted file mode 100644 index 55bdf9ebf3..0000000000 --- a/source/java/org/alfresco/repo/domain/DbAuthority.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain; - -import java.io.Serializable; - -/** - * The interface against which recipients of permission are persisted - * @author andyh - */ -public interface DbAuthority extends Serializable -{ - /** - * Get the object id - * @return - */ - public Long getId(); - - /** - * @return Returns the version number for optimistic locking - */ - public Long getVersion(); - - /** - * @return Returns the authority - */ - public String getAuthority(); - - /** - * @param the authority - */ - public void setAuthority(String authority); - - /** - * Use a crc to enforce case sensitive unique key - * @param crc - */ - public void setCrc(Long crc); - - /** - * Get the CRC - * - * @return - */ - public Long getCrc(); - -} diff --git a/source/java/org/alfresco/repo/domain/DbAuthorityAlias.java b/source/java/org/alfresco/repo/domain/DbAuthorityAlias.java deleted file mode 100644 index bb5c614412..0000000000 --- a/source/java/org/alfresco/repo/domain/DbAuthorityAlias.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain; - -/** - * Hibernate persistence for authority aliases - * - * @author andyh - * - */ -public interface DbAuthorityAlias -{ - /** - * Get the object id. - * @return - */ - public Long getId(); - - /** - * Get the version used for optimistic locking - * @return - */ - public Long getVersion(); - - /** - * Get the authority for which this is an alias - * @return - */ - public DbAuthority getAuthority(); - - /** - * Get the alias for the authority - * @return - */ - public DbAuthority getAlias(); - - /** - * Set the authority - * @param authority - */ - public void setAuthority(DbAuthority authority); - - /** - * Set the alias - * @param alias - */ - public void setAlias(DbAuthority alias); -} diff --git a/source/java/org/alfresco/repo/domain/DbPermission.java b/source/java/org/alfresco/repo/domain/DbPermission.java deleted file mode 100644 index b4af765db1..0000000000 --- a/source/java/org/alfresco/repo/domain/DbPermission.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain; - -import java.io.Serializable; - -import org.alfresco.repo.domain.qname.QNameDAO; -import org.alfresco.service.namespace.QName; - -/** - * The interface against which permission references are persisted in hibernate. - * - * @author andyh - */ -public interface DbPermission extends Serializable -{ - /** - * Convenience method to get the type QName of the permission - * - * @param qnameDAO helper DAO - * @return the permission's type QName - */ - public QName getTypeQName(QNameDAO qnameDAO); - - /** - * @return Returns the automatically assigned ID - */ - public Long getId(); - - /** - * @return Returns the version number for optimistic locking - */ - public Long getVersion(); - - /** - * @return Returns the qualified name of this permission - */ - public Long getTypeQNameId(); - - /** - * @param typeQNameId the ID of the QName for this instance - */ - public void setTypeQNameId(Long typeQNameId); - - /** - * @return Returns the permission name - */ - public String getName(); - - /** - * @param name the name of the permission - */ - public void setName(String name); - - /** - * @return Returns a key combining the {@link #getTypeQnameId() type} - * and {@link #getName() name} - */ - public DbPermissionKey getKey(); -} diff --git a/source/java/org/alfresco/repo/domain/DbPermissionKey.java b/source/java/org/alfresco/repo/domain/DbPermissionKey.java deleted file mode 100644 index bb046db69b..0000000000 --- a/source/java/org/alfresco/repo/domain/DbPermissionKey.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain; - -import java.io.Serializable; - -import org.alfresco.util.EqualsHelper; - -/** - * Compound key for persistence of {@link org.alfresco.repo.domain.DbPermission}. - * - * @author Derek Hulley - */ -public class DbPermissionKey implements Serializable -{ - private static final long serialVersionUID = -1667797216480779296L; - - private Long typeQNameId; - private String name; - - public DbPermissionKey() - { - } - - public DbPermissionKey(Long typeQNameId, String name) - { - this.typeQNameId = typeQNameId; - this.name = name; - } - - public String toString() - { - return ("DbPermissionKey" + - "[ type=" + typeQNameId + - ", name=" + name + - "]"); - } - - public int hashCode() - { - return this.name.hashCode(); - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - else if (!(obj instanceof DbPermissionKey)) - { - return false; - } - DbPermissionKey that = (DbPermissionKey) obj; - return (EqualsHelper.nullSafeEquals(this.typeQNameId, that.typeQNameId) - && EqualsHelper.nullSafeEquals(this.name, that.name) - ); - } - - public Long getTypeQNameId() - { - return typeQNameId; - } - - /** - * Tamper-proof method only to be used by introspectors - */ - @SuppressWarnings("unused") - private void setTypeQName(Long typeQNameId) - { - this.typeQNameId = typeQNameId; - } - - public String getName() - { - return name; - } - - /** - * Tamper-proof method only to be used by introspectors - */ - @SuppressWarnings("unused") - private void setName(String name) - { - this.name = name; - } -} diff --git a/source/java/org/alfresco/repo/domain/DomainTestSuite.java b/source/java/org/alfresco/repo/domain/DomainTestSuite.java index a040e69f72..20274d4e63 100644 --- a/source/java/org/alfresco/repo/domain/DomainTestSuite.java +++ b/source/java/org/alfresco/repo/domain/DomainTestSuite.java @@ -24,11 +24,15 @@ import junit.framework.TestSuite; import org.alfresco.repo.domain.audit.AuditDAOTest; import org.alfresco.repo.domain.contentdata.ContentDataDAOTest; import org.alfresco.repo.domain.encoding.EncodingDAOTest; +import org.alfresco.repo.domain.locale.LocaleDAOTest; import org.alfresco.repo.domain.locks.LockDAOTest; import org.alfresco.repo.domain.mimetype.MimetypeDAOTest; +import org.alfresco.repo.domain.node.NodeDAOTest; import org.alfresco.repo.domain.patch.AppliedPatchDAOTest; +import org.alfresco.repo.domain.permissions.AclCrudDAOTest; import org.alfresco.repo.domain.propval.PropertyValueDAOTest; import org.alfresco.repo.domain.qname.QNameDAOTest; +import org.alfresco.repo.domain.usage.UsageDAOTest; /** * Suite for domain-related tests. @@ -41,6 +45,7 @@ public class DomainTestSuite extends TestSuite { TestSuite suite = new TestSuite(); + suite.addTestSuite(NodeDAOTest.class); suite.addTestSuite(ContentDataDAOTest.class); suite.addTestSuite(EncodingDAOTest.class); suite.addTestSuite(LockDAOTest.class); @@ -51,7 +56,9 @@ public class DomainTestSuite extends TestSuite suite.addTestSuite(PropertyValueDAOTest.class); suite.addTestSuite(AuditDAOTest.class); suite.addTestSuite(AppliedPatchDAOTest.class); - + suite.addTestSuite(AclCrudDAOTest.class); + suite.addTestSuite(UsageDAOTest.class); + return suite; } } diff --git a/source/java/org/alfresco/repo/domain/LocaleEntity.java b/source/java/org/alfresco/repo/domain/LocaleEntity.java deleted file mode 100644 index b36e89f8e6..0000000000 --- a/source/java/org/alfresco/repo/domain/LocaleEntity.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain; - -import java.util.Locale; - -/** - * Represents a persistable Locale entity. - * - * @author Derek Hulley - * @since 2.2.1 - */ -public interface LocaleEntity -{ - Long getId(); - - Locale getLocale(); - - /** - * @param locale the locale to set or null to represent the default locale - */ - void setLocale(Locale locale); - - public String getLocaleStr(); -} diff --git a/source/java/org/alfresco/repo/domain/Node.java b/source/java/org/alfresco/repo/domain/Node.java index d949513dfb..6367f9e70f 100644 --- a/source/java/org/alfresco/repo/domain/Node.java +++ b/source/java/org/alfresco/repo/domain/Node.java @@ -19,8 +19,10 @@ package org.alfresco.repo.domain; import java.util.Map; -import java.util.Set; +import org.alfresco.repo.domain.node.NodePropertyKey; +import org.alfresco.repo.domain.node.NodePropertyValue; +import org.alfresco.repo.domain.node.Transaction; import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; @@ -86,14 +88,12 @@ public interface Node public Long getTypeQNameId(); public void setTypeQNameId(Long typeQNameId); - - public DbAccessControlList getAccessControlList(); - - public void setAccessControlList(DbAccessControlList accessControlList); - - public Set getAspects(); - public Map getProperties(); + public Long getAclId(); + + public void setAclId(Long aclId); + + public Map getProperties(); public AuditableProperties getAuditableProperties(); diff --git a/source/java/org/alfresco/repo/domain/PropertyMapKey.java b/source/java/org/alfresco/repo/domain/PropertyMapKey.java deleted file mode 100644 index 4ca91c46e2..0000000000 --- a/source/java/org/alfresco/repo/domain/PropertyMapKey.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain; - -import java.io.Serializable; - -import org.alfresco.util.EqualsHelper; - -/** - * Compound key for persistence of {@link org.alfresco.repo.domain.Node} - * - * @author Derek Hulley - */ -public class PropertyMapKey implements Serializable, Comparable -{ - private static final long serialVersionUID = 3258695403221300023L; - - private Long qnameId; - private Long localeId; - private Integer listIndex; - - public PropertyMapKey() - { - } - - public String toString() - { - return ("PropertymapKey[" + - " qnameId=" + qnameId + - ", localeId=" + localeId + - ", listIndex=" + listIndex + - "]"); - } - - public int hashCode() - { - return - (qnameId == null ? 0 : qnameId.hashCode()) + - (listIndex == null ? 0 : listIndex.hashCode()); - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - else if (!(obj instanceof PropertyMapKey)) - { - return false; - } - PropertyMapKey that = (PropertyMapKey) obj; - return (EqualsHelper.nullSafeEquals(this.qnameId, that.qnameId) && - EqualsHelper.nullSafeEquals(this.listIndex, that.listIndex) && - EqualsHelper.nullSafeEquals(this.localeId, that.localeId) - ); - } - - /** - * throws ClassCastException if the object is not of the correct type - */ - public int compareTo(PropertyMapKey that) - { - // Comparision by priority: qnameId, listIndex, localeId - if (this.qnameId.equals(that.qnameId)) - { - if (this.listIndex.equals(that.listIndex)) - { - return this.localeId.compareTo(that.localeId); - } - else - { - return this.listIndex.compareTo(that.listIndex); - } - } - else - { - return this.qnameId.compareTo(that.qnameId); - } - } - - public Long getQnameId() - { - return qnameId; - } - - public void setQnameId(Long qnameId) - { - this.qnameId = qnameId; - } - - public Long getLocaleId() - { - return localeId; - } - - public void setLocaleId(Long localeId) - { - this.localeId = localeId; - } - - public Integer getListIndex() - { - return listIndex; - } - - public void setListIndex(Integer listIndex) - { - this.listIndex = listIndex; - } -} diff --git a/source/java/org/alfresco/repo/domain/PropertyValue.java b/source/java/org/alfresco/repo/domain/PropertyValue.java index a0d21a3ccf..d1d0024cd4 100644 --- a/source/java/org/alfresco/repo/domain/PropertyValue.java +++ b/source/java/org/alfresco/repo/domain/PropertyValue.java @@ -32,8 +32,6 @@ import java.util.Locale; import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.repo.attributes.Attribute; -import org.alfresco.repo.attributes.AttributeConverter; import org.alfresco.repo.domain.schema.SchemaBootstrap; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.AssociationRef; @@ -44,7 +42,6 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.Path; import org.alfresco.service.cmr.repository.Period; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; -import org.alfresco.service.cmr.repository.datatype.TypeConverter.Converter; import org.alfresco.service.namespace.QName; import org.alfresco.util.EqualsHelper; import org.alfresco.util.VersionNumber; @@ -214,6 +211,9 @@ public class PropertyValue implements Cloneable, Serializable return DefaultTypeConverter.INSTANCE.convert(Date.class, value); } }, + /** + * @deprecated column FK to alf_global_attributes has been removed (3.4) + */ DB_ATTRIBUTE { @Override @@ -222,14 +222,10 @@ public class PropertyValue implements Cloneable, Serializable return Integer.valueOf(8); } - /** class that is able to convert from persisted attributes to normal attributes */ - private AttributeConverter attributeConverter = new AttributeConverter(); - @Override Serializable convert(Serializable value) { - Attribute attribute = DefaultTypeConverter.INSTANCE.convert(Attribute.class, value); - return attributeConverter.toPersistent(attribute); + return null; } }, SERIALIZABLE @@ -258,49 +254,19 @@ public class PropertyValue implements Cloneable, Serializable protected ValueType getPersistedType(Serializable value) { // NOTE: since 2.2.1, PropertyValue is only used by AVM (which does not natively support MLText, other than single/default string) - if (value instanceof MLText) - { - MLText mlText = (MLText) value; - if (mlText.getDefaultValue() == null) - { - return ValueType.NULL; - } - else if (mlText.size() == 1) - { - return ValueType.STRING; - } - } - else if ((value == null) || (value instanceof String)) - { - return ValueType.STRING; - } - return ValueType.DB_ATTRIBUTE; + return ValueType.STRING; } - @SuppressWarnings("unchecked") @Override Serializable convert(Serializable value) { // NOTE: since 2.2.1, PropertyValue is only used by AVM (which does not natively support MLText, other than single/default string) - if (value != null) + MLText mlText = DefaultTypeConverter.INSTANCE.convert(MLText.class, value); + if (mlText.size() > 1) { - if (value instanceof String) - { - return value; - } - else if (value instanceof MLText) - { - if (((MLText)value).size() <= 1) - { - return (String)((Converter)DefaultTypeConverter.INSTANCE.getConverter(MLText.class, String.class)).convert((MLText)value); - } - else - { - throw new UnsupportedOperationException("PropertyValue MLText is not supported for AVM"); - } - } + throw new UnsupportedOperationException("PropertyValue MLText is not supported for AVM"); } - return DefaultTypeConverter.INSTANCE.convert(MLText.class, value); + return DefaultTypeConverter.INSTANCE.convert(String.class, mlText); } }, CONTENT @@ -507,7 +473,7 @@ public class PropertyValue implements Cloneable, Serializable */ abstract Serializable convert(Serializable value); - protected ArrayList convert(Collection collection) + protected ArrayList convert(Collection collection) { ArrayList arrayList = new ArrayList(collection.size()); for (Object object : collection) @@ -600,10 +566,6 @@ public class PropertyValue implements Cloneable, Serializable { return ValueType.VERSION_NUMBER; } - else if (value instanceof Attribute) - { - return ValueType.DB_ATTRIBUTE; - } else if (value instanceof MLText) { return ValueType.MLTEXT; @@ -677,7 +639,6 @@ public class PropertyValue implements Cloneable, Serializable private Float floatValue; private Double doubleValue; private String stringValue; - private Attribute attributeValue; private Serializable serializableValue; /** @@ -706,11 +667,11 @@ public class PropertyValue implements Cloneable, Serializable setPersistedValue(ValueType.NULL, null); setMultiValued(false); } - else if (value instanceof Collection) + else if (value instanceof Collection) { if(typeQName != null) { - Collection collection = (Collection) value; + Collection collection = (Collection) value; ValueType collectionValueType = makeValueType(typeQName); // convert the collection values - we need to do this to ensure that the // values provided conform to the given type @@ -798,7 +759,6 @@ public class PropertyValue implements Cloneable, Serializable EqualsHelper.nullSafeEquals(this.floatValue, that.floatValue) && EqualsHelper.nullSafeEquals(this.doubleValue, that.doubleValue) && EqualsHelper.nullSafeEquals(this.stringValue, that.stringValue) && - EqualsHelper.nullSafeEquals(this.attributeValue, that.attributeValue) && EqualsHelper.nullSafeEquals(this.serializableValue, that.serializableValue) ); @@ -920,8 +880,7 @@ public class PropertyValue implements Cloneable, Serializable this.stringValue = (String) value; break; case DB_ATTRIBUTE: - this.attributeValue = (Attribute) value; - break; + throw new IllegalArgumentException("DB_ATTRIBUTE is no longer supported."); case SERIALIZABLE: this.serializableValue = cloneSerializable(value); break; @@ -1011,7 +970,7 @@ public class PropertyValue implements Cloneable, Serializable return this.stringValue; } case DB_ATTRIBUTE: - return this.attributeValue; + return null; case SERIALIZABLE: return this.serializableValue; default: @@ -1054,7 +1013,7 @@ public class PropertyValue implements Cloneable, Serializable else if (this.isMultiValued) { // collections are always stored - Collection collection = (Collection) this.serializableValue; + Collection collection = (Collection) this.serializableValue; // convert the collection values - we need to do this to ensure that the // values provided conform to the given type ArrayList convertedCollection = requiredType.convert(collection); @@ -1082,10 +1041,11 @@ public class PropertyValue implements Cloneable, Serializable * * @see #getValue(QName) */ + @SuppressWarnings("unchecked") public Collection getCollection(QName typeQName) { Serializable value = getValue(typeQName); - if (value instanceof Collection) + if (value instanceof Collection) { return (Collection) value; } @@ -1152,15 +1112,6 @@ public class PropertyValue implements Cloneable, Serializable this.stringValue = value; } - public Attribute getAttributeValue() - { - return attributeValue; - } - public void setAttributeValue(Attribute value) - { - this.attributeValue = value; - } - public Serializable getSerializableValue() { return serializableValue; diff --git a/source/java/org/alfresco/repo/domain/PropertyValueTest.java b/source/java/org/alfresco/repo/domain/PropertyValueTest.java index c816d6a3ee..0965556839 100644 --- a/source/java/org/alfresco/repo/domain/PropertyValueTest.java +++ b/source/java/org/alfresco/repo/domain/PropertyValueTest.java @@ -59,7 +59,6 @@ public class PropertyValueTest extends TestCase mlText = new MLText(Locale.GERMAN, "hallo"); mlText.addValue(Locale.ITALIAN, "ciao"); propertyValue = new PropertyValue(DataTypeDefinition.MLTEXT, mlText); - assertNotNull("MLText not persisted as an attribute", propertyValue.getAttributeValue()); fail(); } diff --git a/source/java/org/alfresco/repo/domain/Transaction.java b/source/java/org/alfresco/repo/domain/Transaction.java deleted file mode 100644 index a0eff55153..0000000000 --- a/source/java/org/alfresco/repo/domain/Transaction.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain; - -/** - * Interface for persistent transaction objects. - * - * @author Derek Hulley - */ -public interface Transaction -{ - public Long getId(); - - public Long getVersion(); - - public String getChangeTxnId(); - - public void setChangeTxnId(String changeTxnId); - - public Long getCommitTimeMs(); - - public void setCommitTimeMs(Long commitTimeMs); - - public Server getServer(); - - public void setServer(Server server); -} diff --git a/source/java/org/alfresco/repo/domain/UsageDelta.java b/source/java/org/alfresco/repo/domain/UsageDelta.java deleted file mode 100644 index 30f6841cb0..0000000000 --- a/source/java/org/alfresco/repo/domain/UsageDelta.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain; - -import org.alfresco.repo.domain.Node; - -/** - * Interface for persistent usage delta objects. - * - */ -public interface UsageDelta -{ - public Node getNode(); - - public void setNode(Node node); - - public long getDeltaSize(); - - public void setDeltaSize(long usageDeltaSize); -} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/UsageDeltaDAO.java b/source/java/org/alfresco/repo/domain/UsageDeltaDAO.java deleted file mode 100644 index 2f1db5256b..0000000000 --- a/source/java/org/alfresco/repo/domain/UsageDeltaDAO.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain; - -import java.util.Set; - -import org.alfresco.service.cmr.repository.NodeRef; - -/** - * The interface to persist usage delta information. - * - */ -public interface UsageDeltaDAO -{ - /** - * Create a usage delta entry. - * - * @param deltaSize the size change - */ - public void insertDelta(NodeRef usageNodeRef, long deltaSize); - - /** - * Get the total delta size for a node. - * - * @param nodeRef the node reference - * @return sum of delta sizes (in bytes) - can be +ve or -ve - */ - public long getTotalDeltaSize(NodeRef usageNodeRef); - - /** - * Get the total delta size for a node and remove any deltas used in the calculation. - * - * @param nodeRef the node reference - * @return sum of delta sizes (in bytes) - can be +ve or -ve - */ - public long getAndRemoveTotalDeltaSize(NodeRef usageNodeRef); - - public Set getUsageDeltaNodes(); - - public int deleteDeltas(NodeRef nodeRef); - - public int deleteDeltas(Long nodeId); -} diff --git a/source/java/org/alfresco/repo/domain/avm/AVMNodeDAO.java b/source/java/org/alfresco/repo/domain/avm/AVMNodeDAO.java index a735babac0..beded68321 100644 --- a/source/java/org/alfresco/repo/domain/avm/AVMNodeDAO.java +++ b/source/java/org/alfresco/repo/domain/avm/AVMNodeDAO.java @@ -19,13 +19,13 @@ package org.alfresco.repo.domain.avm; import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.Map; +import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.service.namespace.QName; -import org.springframework.dao.ConcurrencyFailureException; +import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.service.namespace.QName; +import org.springframework.dao.ConcurrencyFailureException; /** * DAO services for @@ -39,9 +39,9 @@ import org.springframework.dao.ConcurrencyFailureException; */ public interface AVMNodeDAO { - // - // AVM Nodes - // + // + // AVM Nodes + // public AVMNodeEntity createNode(AVMNodeEntity nodeEntity); @@ -49,9 +49,9 @@ public interface AVMNodeDAO public void updateNode(AVMNodeEntity nodeEntity); - public void updateNodeModTimeAndGuid(AVMNodeEntity nodeEntity); + public void updateNodeModTimeAndGuid(AVMNodeEntity nodeEntity); - public void updateNodeModTimeAndContentData(AVMNodeEntity nodeEntity); + public void updateNodeModTimeAndContentData(AVMNodeEntity nodeEntity); public List getNodesNewInStore(long storeId); @@ -69,8 +69,6 @@ public interface AVMNodeDAO public List getAllLayeredFiles(); - public List getAVMNodesByAclId(long aclId); - public void clearNodeEntityCache(); /** @@ -89,47 +87,47 @@ public interface AVMNodeDAO // - // AVM Node Aspects + // AVM Node Aspects // /** * Add aspect to given Node * * @param nodeId the unique ID of the node entity - * @param qname the qname + * @param qname the qname * @throws ConcurrencyFailureException if the aspect already exists */ - public void createAspect(long nodeId, QName qname); + public void createAspect(long nodeId, QName qname); /** - * Get set of aspects for given Node + * Get set of aspects for given Node * * @param nodeId the unique ID of the node entity - * @return the set of qnames (never null) + * @return the set of qnames (never null) * @throws AlfrescoRuntimeException if the ID provided is invalid */ - public Set getAspects(long nodeId); + public Set getAspects(long nodeId); /** * Remove aspect from given Node * * @param nodeId the unique ID of the node entity - * @param qnameId the qname + * @param qnameId the qname * @throws ConcurrencyFailureException if the aspect does not exist */ - public void deleteAspect(long nodeId, QName qname); + public void deleteAspect(long nodeId, QName qname); public void deleteAspects(long nodeId); - // - // AVM Node Properties - // - - public void createOrUpdateNodeProperty(long nodeId, QName qname, PropertyValue value); + // + // AVM Node Properties + // - public Map getNodeProperties(long nodeId); + public void createOrUpdateNodeProperty(long nodeId, QName qname, PropertyValue value); - public void deleteNodeProperty(long nodeId, QName qname); + public Map getNodeProperties(long nodeId); + + public void deleteNodeProperty(long nodeId, QName qname); public void deleteNodeProperties(long nodeId); } diff --git a/source/java/org/alfresco/repo/domain/avm/AVMNodePropertyEntity.java b/source/java/org/alfresco/repo/domain/avm/AVMNodePropertyEntity.java index 015c1fb222..e973c27fe0 100644 --- a/source/java/org/alfresco/repo/domain/avm/AVMNodePropertyEntity.java +++ b/source/java/org/alfresco/repo/domain/avm/AVMNodePropertyEntity.java @@ -44,7 +44,6 @@ public class AVMNodePropertyEntity extends PropertyValue setQnameId(qnameId); this.setActualType(value.getActualType()); - this.setAttributeValue(value.getAttributeValue()); this.setBooleanValue(value.getBooleanValue()); this.setDoubleValue(value.getDoubleValue()); this.setFloatValue(value.getFloatValue()); diff --git a/source/java/org/alfresco/repo/domain/avm/AVMStorePropertyEntity.java b/source/java/org/alfresco/repo/domain/avm/AVMStorePropertyEntity.java index 9130ed12e8..ddaa9d6252 100644 --- a/source/java/org/alfresco/repo/domain/avm/AVMStorePropertyEntity.java +++ b/source/java/org/alfresco/repo/domain/avm/AVMStorePropertyEntity.java @@ -47,7 +47,6 @@ public class AVMStorePropertyEntity extends PropertyValue setQnameId(qnameId); this.setActualType(value.getActualType()); - this.setAttributeValue(value.getAttributeValue()); this.setBooleanValue(value.getBooleanValue()); this.setDoubleValue(value.getDoubleValue()); this.setFloatValue(value.getFloatValue()); diff --git a/source/java/org/alfresco/repo/domain/avm/AbstractAVMNodeDAOImpl.java b/source/java/org/alfresco/repo/domain/avm/AbstractAVMNodeDAOImpl.java index 62f5786b30..665ce1722b 100644 --- a/source/java/org/alfresco/repo/domain/avm/AbstractAVMNodeDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/avm/AbstractAVMNodeDAOImpl.java @@ -47,21 +47,21 @@ import org.springframework.extensions.surf.util.ParameterCheck; */ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO { - private static final String CACHE_REGION_AVM_NODE = "AVMNode"; + private static final String CACHE_REGION_AVM_NODE = "AVMNode"; private static final String CACHE_REGION_AVM_NODE_PROP = "AVMNodeProp"; - private final AVMNodeEntityCallbackDAO avmNodeEntityDaoCallback; + private final AVMNodeEntityCallbackDAO avmNodeEntityDaoCallback; private final AVMNodePropertyEntityCallbackDAO avmNodePropEntityDaoCallback; - private QNameDAO qnameDAO; - + private QNameDAO qnameDAO; + /** * Cache for the AVM node entity:
* KEY: ID (node)
* VALUE: AVMNodeEntity
* VALUE KEY: None
*/ - private EntityLookupCache avmNodeCache; + private EntityLookupCache avmNodeCache; /** * Cache for the AVM node property entity:
@@ -114,12 +114,12 @@ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO this.avmNodeAspectsCache = avmNodeAspectsCache; } - public void setQnameDAO(QNameDAO qnameDAO) - { - this.qnameDAO = qnameDAO; - } + public void setQnameDAO(QNameDAO qnameDAO) + { + this.qnameDAO = qnameDAO; + } + - /** * Default constructor. *

@@ -129,8 +129,8 @@ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO @SuppressWarnings("unchecked") public AbstractAVMNodeDAOImpl() { - this.avmNodeEntityDaoCallback = new AVMNodeEntityCallbackDAO(); - this.avmNodeCache = new EntityLookupCache(avmNodeEntityDaoCallback); + this.avmNodeEntityDaoCallback = new AVMNodeEntityCallbackDAO(); + this.avmNodeCache = new EntityLookupCache(avmNodeEntityDaoCallback); this.avmNodePropEntityDaoCallback = new AVMNodePropertyEntityCallbackDAO(); this.avmNodePropCache = new EntityLookupCache, AVMNodePropertyEntity, Serializable>(avmNodePropEntityDaoCallback); @@ -142,8 +142,8 @@ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO { ParameterCheck.mandatory("nodeEntity", nodeEntity); - nodeEntity.setVers(0L); - + nodeEntity.setVers(0L); + Pair entityPair = avmNodeCache.getOrCreateByValue(nodeEntity); return entityPair.getSecond(); } @@ -156,7 +156,7 @@ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO Pair entityPair = avmNodeCache.getByKey(nodeId); if (entityPair == null) { - return null; + return null; } return entityPair.getSecond(); } @@ -175,59 +175,59 @@ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO public void updateNode(AVMNodeEntity nodeEntity) { ParameterCheck.mandatory("nodeEntity", nodeEntity); - ParameterCheck.mandatory("nodeEntity.getId()", nodeEntity.getId()); - ParameterCheck.mandatory("nodeEntity.getVers()", nodeEntity.getVers()); + ParameterCheck.mandatory("nodeEntity.getId()", nodeEntity.getId()); + ParameterCheck.mandatory("nodeEntity.getVers()", nodeEntity.getVers()); - int updated = avmNodeCache.updateValue(nodeEntity.getId(), nodeEntity); - if (updated < 1) - { - throw new ConcurrencyFailureException("AVMNode with ID (" + nodeEntity.getId() + ") no longer exists or has been updated concurrently"); - } + int updated = avmNodeCache.updateValue(nodeEntity.getId(), nodeEntity); + if (updated < 1) + { + throw new ConcurrencyFailureException("AVMNode with ID (" + nodeEntity.getId() + ") no longer exists or has been updated concurrently"); + } } /** * {@inheritDoc} * @deprecated */ - public void updateNodeModTimeAndGuid(AVMNodeEntity nodeEntity) + public void updateNodeModTimeAndGuid(AVMNodeEntity nodeEntity) { - ParameterCheck.mandatory("nodeEntity", nodeEntity); - ParameterCheck.mandatory("nodeEntity.getId()", nodeEntity.getId()); - ParameterCheck.mandatory("nodeEntity.getGuid()", nodeEntity.getGuid()); - ParameterCheck.mandatory("nodeEntity.getModifiedDate()", nodeEntity.getModifiedDate()); - ParameterCheck.mandatory("nodeEntity.getVers()", nodeEntity.getVers()); + ParameterCheck.mandatory("nodeEntity", nodeEntity); + ParameterCheck.mandatory("nodeEntity.getId()", nodeEntity.getId()); + ParameterCheck.mandatory("nodeEntity.getGuid()", nodeEntity.getGuid()); + ParameterCheck.mandatory("nodeEntity.getModifiedDate()", nodeEntity.getModifiedDate()); + ParameterCheck.mandatory("nodeEntity.getVers()", nodeEntity.getVers()); - int updated = updateNodeEntityModTimeAndGuid(nodeEntity); - if (updated < 1) - { - throw new ConcurrencyFailureException("AVMNode with ID (" + nodeEntity.getId() + ") no longer exists or has been updated concurrently"); - } - - // update cache - avmNodeCache.removeByKey(nodeEntity.getId()); - avmNodeCache.getByKey(nodeEntity.getId()); - } - - /** - * {@inheritDoc} - * @deprecated - */ - public void updateNodeModTimeAndContentData(AVMNodeEntity nodeEntity) - { - ParameterCheck.mandatory("nodeEntity", nodeEntity); - ParameterCheck.mandatory("nodeEntity.getId()", nodeEntity.getId()); - ParameterCheck.mandatory("nodeEntity.getModifiedDate()", nodeEntity.getModifiedDate()); - ParameterCheck.mandatory("nodeEntity.getVers()", nodeEntity.getVers()); - - int updated = updateNodeEntityModTimeAndContentData(nodeEntity); - if (updated < 1) - { - throw new ConcurrencyFailureException("AVMNode with ID (" + nodeEntity.getId() + ") no longer exists or has been updated concurrently"); - } + int updated = updateNodeEntityModTimeAndGuid(nodeEntity); + if (updated < 1) + { + throw new ConcurrencyFailureException("AVMNode with ID (" + nodeEntity.getId() + ") no longer exists or has been updated concurrently"); + } // update cache - avmNodeCache.removeByKey(nodeEntity.getId()); - avmNodeCache.getByKey(nodeEntity.getId()); + avmNodeCache.removeByKey(nodeEntity.getId()); + avmNodeCache.getByKey(nodeEntity.getId()); + } + + /** + * {@inheritDoc} + * @deprecated + */ + public void updateNodeModTimeAndContentData(AVMNodeEntity nodeEntity) + { + ParameterCheck.mandatory("nodeEntity", nodeEntity); + ParameterCheck.mandatory("nodeEntity.getId()", nodeEntity.getId()); + ParameterCheck.mandatory("nodeEntity.getModifiedDate()", nodeEntity.getModifiedDate()); + ParameterCheck.mandatory("nodeEntity.getVers()", nodeEntity.getVers()); + + int updated = updateNodeEntityModTimeAndContentData(nodeEntity); + if (updated < 1) + { + throw new ConcurrencyFailureException("AVMNode with ID (" + nodeEntity.getId() + ") no longer exists or has been updated concurrently"); + } + + // update cache + avmNodeCache.removeByKey(nodeEntity.getId()); + avmNodeCache.getByKey(nodeEntity.getId()); } /** @@ -304,14 +304,6 @@ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO return getAllLayeredFileNodeEntities(); } - /** - * {@inheritDoc} - */ - public List getAVMNodesByAclId(long aclId) - { - return getAVMNodeEntityIdsByAclId(aclId); - } - /** * {@inheritDoc} */ @@ -363,28 +355,28 @@ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO return null; } - public int updateValue(Long key, AVMNodeEntity value) - { - return updateNodeEntity(value); - } - - public int deleteByKey(Long key) - { - return deleteNodeEntity(key); - } - - public int deleteByValue(AVMNodeEntity value) - { - // TODO - throw new UnsupportedOperationException("deleteByValue(AVMNodeEntity)"); - } + public int updateValue(Long key, AVMNodeEntity value) + { + return updateNodeEntity(value); + } + + public int deleteByKey(Long key) + { + return deleteNodeEntity(key); + } + + public int deleteByValue(AVMNodeEntity value) + { + // TODO + throw new UnsupportedOperationException("deleteByValue(AVMNodeEntity)"); + } } protected abstract AVMNodeEntity createNodeEntity(AVMNodeEntity nodeEntity); protected abstract AVMNodeEntity getNodeEntity(long nodeId); - protected abstract int updateNodeEntity(AVMNodeEntity nodeEntity); - protected abstract int updateNodeEntityModTimeAndGuid(AVMNodeEntity nodeEntity); - protected abstract int updateNodeEntityModTimeAndContentData(AVMNodeEntity nodeEntity); + protected abstract int updateNodeEntity(AVMNodeEntity nodeEntity); + protected abstract int updateNodeEntityModTimeAndGuid(AVMNodeEntity nodeEntity); + protected abstract int updateNodeEntityModTimeAndContentData(AVMNodeEntity nodeEntity); protected abstract int deleteNodeEntity(long nodeId); protected abstract void updateNodeEntitiesClearNewInStore(long storeId); protected abstract List getNodeEntitiesNewInStore(long storeId); @@ -393,91 +385,90 @@ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO protected abstract List getNodeEntityOrphans(int maxSize); protected abstract List getAllLayeredDirectoryNodeEntities(); protected abstract List getAllLayeredFileNodeEntities(); - protected abstract List getAVMNodeEntityIdsByAclId(long aclId); protected abstract void getPlainFileContentUrls(ContentUrlHandler handler); /** * {@inheritDoc} */ @SuppressWarnings("unchecked") - public Set getAspects(long nodeId) + public Set getAspects(long nodeId) { - Set aspects = (Set)avmNodeAspectsCache.get(nodeId); + Set aspects = (Set)avmNodeAspectsCache.get(nodeId); if (aspects != null) { return aspects; } - Set aspectQNames = null; - + Set aspectQNames = null; + // Get it from the DB - List aspectIds = getAspectEntities(nodeId); - if (aspectIds != null) + List aspectIds = getAspectEntities(nodeId); + if (aspectIds != null) { - // Convert to QNames - aspectQNames = qnameDAO.convertIdsToQNames(new HashSet(aspectIds)); + // Convert to QNames + aspectQNames = qnameDAO.convertIdsToQNames(new HashSet(aspectIds)); + } + else + { + aspectQNames = new HashSet(0); } - else - { - aspectQNames = new HashSet(0); - } - // Cache it - avmNodeAspectsCache.put(nodeId, aspectQNames); - - return aspectQNames; + // Cache it + avmNodeAspectsCache.put(nodeId, aspectQNames); + + return aspectQNames; } /** * {@inheritDoc} */ - public void createAspect(long nodeId, QName qname) + public void createAspect(long nodeId, QName qname) { - Set aspects = getAspects(nodeId); - if (aspects.contains(qname)) + Set aspects = getAspects(nodeId); + if (aspects.contains(qname)) { return; } - // Get the persistent ID for the QName - Pair qnamePair = qnameDAO.getOrCreateQName(qname); - if (qnamePair != null) - { - Long qnameId = qnamePair.getFirst(); - createAspectEntity(nodeId, qnameId); - - // Cache it - aspects.add(qname); - avmNodeAspectsCache.put(new Long(nodeId), aspects); - } + // Get the persistent ID for the QName + Pair qnamePair = qnameDAO.getOrCreateQName(qname); + if (qnamePair != null) + { + Long qnameId = qnamePair.getFirst(); + createAspectEntity(nodeId, qnameId); + + // Cache it + aspects.add(qname); + avmNodeAspectsCache.put(new Long(nodeId), aspects); + } } /** * {@inheritDoc} */ - public void deleteAspect(long nodeId, QName qname) + public void deleteAspect(long nodeId, QName qname) { - Set aspects = getAspects(nodeId); - if (! aspects.contains(qname)) + Set aspects = getAspects(nodeId); + if (! aspects.contains(qname)) { return; } - // Get the persistent ID for the QName - Pair qnamePair = qnameDAO.getQName(qname); - if (qnamePair != null) + // Get the persistent ID for the QName + Pair qnamePair = qnameDAO.getQName(qname); + if (qnamePair != null) { - Long qnameId = qnamePair.getFirst(); - - int deleted = deleteAspectEntity(nodeId, qnameId); - if (deleted < 1) - { - throw new ConcurrencyFailureException("AVMNodeAspect (" + nodeId + ", " + qnameId + ") no longer exists"); - } - - // Remove from cache - aspects.remove(qname); - avmNodeAspectsCache.put(new Long(nodeId), aspects); + Long qnameId = qnamePair.getFirst(); + + int deleted = deleteAspectEntity(nodeId, qnameId); + if (deleted < 1) + { + throw new ConcurrencyFailureException("AVMNodeAspect (" + nodeId + ", " + qnameId + ") no longer exists"); + } + + // Remove from cache + aspects.remove(qname); + avmNodeAspectsCache.put(new Long(nodeId), aspects); } } @@ -486,7 +477,7 @@ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO */ public void deleteAspects(long nodeId) { - Set naEntities = getAspects(nodeId); + Set naEntities = getAspects(nodeId); if (naEntities.size() == 0) { return; @@ -502,7 +493,7 @@ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO avmNodeAspectsCache.remove(nodeId); } - protected abstract List getAspectEntities(long nodeId); + protected abstract List getAspectEntities(long nodeId); protected abstract void createAspectEntity(long nodeId, long qnameId); protected abstract int deleteAspectEntity(long nodeId, long qnameId); protected abstract int deleteAspectEntities(long nodeId); @@ -510,17 +501,17 @@ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO /** * {@inheritDoc} */ - public void createOrUpdateNodeProperty(long nodeId, QName qname, PropertyValue value) + public void createOrUpdateNodeProperty(long nodeId, QName qname, PropertyValue value) { - ParameterCheck.mandatory("qname", qname); + ParameterCheck.mandatory("qname", qname); - // Get the persistent ID for the QName - Pair qnamePair = qnameDAO.getOrCreateQName(qname); - Long qnameId = qnamePair.getFirst(); - - AVMNodePropertyEntity propEntity = new AVMNodePropertyEntity(nodeId, qnameId, value); - - Pair key = new Pair(nodeId, propEntity.getQnameId()); + // Get the persistent ID for the QName + Pair qnamePair = qnameDAO.getOrCreateQName(qname); + Long qnameId = qnamePair.getFirst(); + + AVMNodePropertyEntity propEntity = new AVMNodePropertyEntity(nodeId, qnameId, value); + + Pair key = new Pair(nodeId, propEntity.getQnameId()); Pair, AVMNodePropertyEntity> entityPair = avmNodePropCache.getByKey(key); if (entityPair != null) @@ -540,70 +531,70 @@ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO /** * {@inheritDoc} */ - /* - public AVMNodePropertyEntity getNodeProperty(long nodeId, QName qname) + /* + public AVMNodePropertyEntity getNodeProperty(long nodeId, QName qname) { - // Get the persistent ID for the QName - Pair qnamePair = qnameDAO.getQName(qname); - if (qnamePair != null) + // Get the persistent ID for the QName + Pair qnamePair = qnameDAO.getQName(qname); + if (qnamePair != null) { - Long qnameId = qnamePair.getFirst(); - - Pair key = new Pair(nodeId, qnameId); - Pair, AVMNodePropertyEntity> entityPair = avmNodePropCache.getByKey(key); - if (entityPair == null) - { - return null; - } - return entityPair.getSecond(); + Long qnameId = qnamePair.getFirst(); + + Pair key = new Pair(nodeId, qnameId); + Pair, AVMNodePropertyEntity> entityPair = avmNodePropCache.getByKey(key); + if (entityPair == null) + { + return null; + } + return entityPair.getSecond(); } } - */ + */ /** * {@inheritDoc} */ - public Map getNodeProperties(long nodeId) + public Map getNodeProperties(long nodeId) { - // TODO not via cache - List npEntities = getNodePropertyEntities(nodeId); - Map nProps = new HashMap(npEntities.size()); - - for (AVMNodePropertyEntity npEntity : npEntities) - { - Pair qnamePair = qnameDAO.getQName(npEntity.getQnameId()); - if (qnamePair != null) - { - nProps.put(qnamePair.getSecond(), npEntity); - } - } - - return nProps; + // TODO not via cache + List npEntities = getNodePropertyEntities(nodeId); + Map nProps = new HashMap(npEntities.size()); + + for (AVMNodePropertyEntity npEntity : npEntities) + { + Pair qnamePair = qnameDAO.getQName(npEntity.getQnameId()); + if (qnamePair != null) + { + nProps.put(qnamePair.getSecond(), npEntity); + } + } + + return nProps; } /** * {@inheritDoc} */ - public void deleteNodeProperty(long nodeId, QName qname) + public void deleteNodeProperty(long nodeId, QName qname) { - // Get the persistent ID for the QName - Pair qnamePair = qnameDAO.getQName(qname); - if (qnamePair != null) + // Get the persistent ID for the QName + Pair qnamePair = qnameDAO.getQName(qname); + if (qnamePair != null) { - Long qnameId = qnamePair.getFirst(); - - Pair key = new Pair(nodeId, qnameId); - Pair, AVMNodePropertyEntity> entityPair = avmNodePropCache.getByKey(key); - if (entityPair == null) - { - return; - } - - int deleted = avmNodePropCache.deleteByKey(key); - if (deleted < 1) - { - throw new ConcurrencyFailureException("AVMNodeProperty (" + nodeId + ", " + qnameId + ") no longer exists"); - } + Long qnameId = qnamePair.getFirst(); + + Pair key = new Pair(nodeId, qnameId); + Pair, AVMNodePropertyEntity> entityPair = avmNodePropCache.getByKey(key); + if (entityPair == null) + { + return; + } + + int deleted = avmNodePropCache.deleteByKey(key); + if (deleted < 1) + { + throw new ConcurrencyFailureException("AVMNodeProperty (" + nodeId + ", " + qnameId + ") no longer exists"); + } } } @@ -612,15 +603,15 @@ public abstract class AbstractAVMNodeDAOImpl implements AVMNodeDAO */ public void deleteNodeProperties(long nodeId) { - Map nProps = getNodeProperties(nodeId); - if (nProps.size() == 0) + Map nProps = getNodeProperties(nodeId); + if (nProps.size() == 0) { return; } - for (QName propQName : nProps.keySet()) + for (QName propQName : nProps.keySet()) { - deleteNodeProperty(nodeId, propQName); + deleteNodeProperty(nodeId, propQName); } // TODO single delete + cache(s) diff --git a/source/java/org/alfresco/repo/domain/avm/ibatis/AVMNodeDAOImpl.java b/source/java/org/alfresco/repo/domain/avm/ibatis/AVMNodeDAOImpl.java index 71804f5ed9..2243c4fc51 100644 --- a/source/java/org/alfresco/repo/domain/avm/ibatis/AVMNodeDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/avm/ibatis/AVMNodeDAOImpl.java @@ -36,41 +36,40 @@ import com.ibatis.sqlmap.client.event.RowHandler; * iBatis-specific implementation of the AVMNode DAO. * * @author janv - * @since 3.2 + * @since 3.2 */ public class AVMNodeDAOImpl extends AbstractAVMNodeDAOImpl { private static Log logger = LogFactory.getLog(AVMNodeDAOImpl.class); - private static final String INSERT_AVM_NODE = "alfresco.avm.insert_AVMNode"; - private static final String SELECT_AVM_NODE_BY_ID = "alfresco.avm.select_AVMNodeById"; - private static final String UPDATE_AVM_NODE = "alfresco.avm.update_AVMNode"; - private static final String UPDATE_AVM_NODE_MODTIME_AND_GUID = "alfresco.avm.update_AVMNode_modTimeAndGuid"; - private static final String UPDATE_AVM_NODE_MODTIME_AND_CDATA = "alfresco.avm.update_AVMNode_modTimeAndContentData"; - private static final String DELETE_AVM_NODE = "alfresco.avm.delete_AVMNode"; + private static final String INSERT_AVM_NODE = "alfresco.avm.insert_AVMNode"; + private static final String SELECT_AVM_NODE_BY_ID = "alfresco.avm.select_AVMNodeById"; + private static final String UPDATE_AVM_NODE = "alfresco.avm.update_AVMNode"; + private static final String UPDATE_AVM_NODE_MODTIME_AND_GUID = "alfresco.avm.update_AVMNode_modTimeAndGuid"; + private static final String UPDATE_AVM_NODE_MODTIME_AND_CDATA = "alfresco.avm.update_AVMNode_modTimeAndContentData"; + private static final String DELETE_AVM_NODE = "alfresco.avm.delete_AVMNode"; - private static final String SELECT_AVM_NODES_NEW_IN_STORE = "alfresco.avm.select_AVMNodes_newInStore"; - private static final String SELECT_AVM_NODES_NEW_LAYERED_IN_STORE = "alfresco.avm.select_AVMNodes_newLayeredInStore"; - private static final String SELECT_AVM_NODE_IDS_NEW_LAYERED_IN_STORE = "alfresco.avm.select_AVMNodes_IDs_newLayeredInStore"; - private static final String UPDATE_AVM_NODES_CLEAR_NEW_IN_STORE = "alfresco.avm.update_AVMNodes_clearNewInStore"; - private static final String SELECT_AVM_NODES_NULL_PARENT_AND_ISROOT_TF= "alfresco.avm.select_AVMNodes_nullParentAndIsRootTF"; - private static final String SELECT_AVM_NODES_LAYERED_DIRECTORIES_AND_PRIMARY_TF = "alfresco.avm.select_AVMNodes_layeredDirectoriesAndPrimaryTF"; - private static final String SELECT_AVM_NODES_LAYERED_FILES = "alfresco.avm.select_AVMNodes_layeredFiles"; - private static final String SELECT_AVM_NODE_IDS_BY_ACL_ID = "alfresco.avm.select_AVMNodes_IDs_byAcl"; + private static final String SELECT_AVM_NODES_NEW_IN_STORE = "alfresco.avm.select_AVMNodes_newInStore"; + private static final String SELECT_AVM_NODES_NEW_LAYERED_IN_STORE = "alfresco.avm.select_AVMNodes_newLayeredInStore"; + private static final String SELECT_AVM_NODE_IDS_NEW_LAYERED_IN_STORE = "alfresco.avm.select_AVMNodes_IDs_newLayeredInStore"; + private static final String UPDATE_AVM_NODES_CLEAR_NEW_IN_STORE = "alfresco.avm.update_AVMNodes_clearNewInStore"; + private static final String SELECT_AVM_NODES_NULL_PARENT_AND_ISROOT_TF= "alfresco.avm.select_AVMNodes_nullParentAndIsRootTF"; + private static final String SELECT_AVM_NODES_LAYERED_DIRECTORIES_AND_PRIMARY_TF = "alfresco.avm.select_AVMNodes_layeredDirectoriesAndPrimaryTF"; + private static final String SELECT_AVM_NODES_LAYERED_FILES = "alfresco.avm.select_AVMNodes_layeredFiles"; - private static final String SELECT_AVM_CONTENT_URLS_FOR_PLAIN_FILES = "alfresco.avm.select_ContentUrlsForPlainFiles"; + private static final String SELECT_AVM_CONTENT_URLS_FOR_PLAIN_FILES = "alfresco.avm.select_ContentUrlsForPlainFiles"; - private static final String SELECT_AVM_NODE_ASPECTS = "alfresco.avm.select_AVMNodeAspects"; - private static final String INSERT_AVM_NODE_ASPECT = "alfresco.avm.insert_AVMNodeAspect"; - private static final String DELETE_AVM_NODE_ASPECT = "alfresco.avm.delete_AVMNodeAspect"; - private static final String DELETE_AVM_NODE_ASPECTS = "alfresco.avm.delete_AVMNodeAspects"; + private static final String SELECT_AVM_NODE_ASPECTS = "alfresco.avm.select_AVMNodeAspects"; + private static final String INSERT_AVM_NODE_ASPECT = "alfresco.avm.insert_AVMNodeAspect"; + private static final String DELETE_AVM_NODE_ASPECT = "alfresco.avm.delete_AVMNodeAspect"; + private static final String DELETE_AVM_NODE_ASPECTS = "alfresco.avm.delete_AVMNodeAspects"; - private static final String INSERT_AVM_NODE_PROP = "alfresco.avm.insert_AVMNodeProperty"; - private static final String UPDATE_AVM_NODE_PROP = "alfresco.avm.update_AVMNodeProperty"; - private static final String SELECT_AVM_NODE_PROP = "alfresco.avm.select_AVMNodeProperty"; - private static final String SELECT_AVM_NODE_PROPS = "alfresco.avm.select_AVMNodeProperties"; - private static final String DELETE_AVM_NODE_PROP = "alfresco.avm.delete_AVMNodeProperty"; - private static final String DELETE_AVM_NODE_PROPS = "alfresco.avm.delete_AVMNodeProperties"; + private static final String INSERT_AVM_NODE_PROP = "alfresco.avm.insert_AVMNodeProperty"; + private static final String UPDATE_AVM_NODE_PROP = "alfresco.avm.update_AVMNodeProperty"; + private static final String SELECT_AVM_NODE_PROP = "alfresco.avm.select_AVMNodeProperty"; + private static final String SELECT_AVM_NODE_PROPS = "alfresco.avm.select_AVMNodeProperties"; + private static final String DELETE_AVM_NODE_PROP = "alfresco.avm.delete_AVMNodeProperty"; + private static final String DELETE_AVM_NODE_PROPS = "alfresco.avm.delete_AVMNodeProperties"; private SqlMapClientTemplate template; @@ -96,29 +95,29 @@ public class AVMNodeDAOImpl extends AbstractAVMNodeDAOImpl } @Override - protected int updateNodeEntity(AVMNodeEntity updateNodeEntity) + protected int updateNodeEntity(AVMNodeEntity updateNodeEntity) { updateNodeEntity.incrementVers(); - return template.update(UPDATE_AVM_NODE, updateNodeEntity); + return template.update(UPDATE_AVM_NODE, updateNodeEntity); } @Override - protected int updateNodeEntityModTimeAndGuid(AVMNodeEntity updateNodeEntity) + protected int updateNodeEntityModTimeAndGuid(AVMNodeEntity updateNodeEntity) { updateNodeEntity.incrementVers(); // partial update - return template.update(UPDATE_AVM_NODE_MODTIME_AND_GUID, updateNodeEntity); + return template.update(UPDATE_AVM_NODE_MODTIME_AND_GUID, updateNodeEntity); } @Override - protected int updateNodeEntityModTimeAndContentData(AVMNodeEntity updateNodeEntity) + protected int updateNodeEntityModTimeAndContentData(AVMNodeEntity updateNodeEntity) { updateNodeEntity.incrementVers(); // partial update - return template.update(UPDATE_AVM_NODE_MODTIME_AND_CDATA, updateNodeEntity); + return template.update(UPDATE_AVM_NODE_MODTIME_AND_CDATA, updateNodeEntity); } @Override @@ -193,15 +192,6 @@ public class AVMNodeDAOImpl extends AbstractAVMNodeDAOImpl return (List) template.queryForList(SELECT_AVM_NODES_LAYERED_FILES); } - @SuppressWarnings("unchecked") - @Override - protected List getAVMNodeEntityIdsByAclId(long aclId) - { - Map params = new HashMap(1); - params.put("id", aclId); - return (List) template.queryForList(SELECT_AVM_NODE_IDS_BY_ACL_ID, params); - } - @Override protected void getPlainFileContentUrls(ContentUrlHandler handler) { @@ -241,11 +231,11 @@ public class AVMNodeDAOImpl extends AbstractAVMNodeDAOImpl @SuppressWarnings("unchecked") @Override - protected List getAspectEntities(long nodeId) + protected List getAspectEntities(long nodeId) { Map params = new HashMap(1); params.put("id", nodeId); - return (List) template.queryForList(SELECT_AVM_NODE_ASPECTS, params); + return (List) template.queryForList(SELECT_AVM_NODE_ASPECTS, params); } @Override diff --git a/source/java/org/alfresco/repo/domain/contentdata/AbstractContentDataDAOImpl.java b/source/java/org/alfresco/repo/domain/contentdata/AbstractContentDataDAOImpl.java index c12448deed..da5f203b65 100644 --- a/source/java/org/alfresco/repo/domain/contentdata/AbstractContentDataDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/contentdata/AbstractContentDataDAOImpl.java @@ -28,8 +28,8 @@ import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.cache.lookup.EntityLookupCache; import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAOAdaptor; import org.alfresco.repo.content.cleanup.EagerContentStoreCleaner; -import org.alfresco.repo.domain.LocaleDAO; import org.alfresco.repo.domain.encoding.EncodingDAO; +import org.alfresco.repo.domain.locale.LocaleDAO; import org.alfresco.repo.domain.mimetype.MimetypeDAO; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.TransactionListenerAdapter; @@ -387,11 +387,25 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO */ private ContentUrlEntity getOrCreateContentUrlEntity(String contentUrl, long size) { - // Create the content URL entity - ContentUrlEntity contentUrlEntity = getContentUrlEntity(contentUrl); - // If it exists, then we can just re-use it, but check that the size is consistent - if (contentUrlEntity != null) + // Try to insert the content first. Usually, the insert will not clash with anything + // as content URL re-use is far less frequent than new content creation. + ContentUrlEntity contentUrlEntity = null; + try { + contentUrlEntity = createContentUrlEntity(contentUrl, size); + } + catch (RuntimeException e) + { + // See if this was caused by an existing URL + contentUrlEntity = getContentUrlEntity(contentUrl); + // If it exists, then we can just re-use it, but check that the size is consistent + if (contentUrlEntity == null) + { + // The error was caused by something else. Perhaps another, as-yet-unseen + // row clashes with this. Just propagate the exception and let retrying + // happen as required. + throw e; + } // Reuse it long existingSize = contentUrlEntity.getSize(); if (size != existingSize) @@ -413,11 +427,6 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO } } } - else - { - // Create it - contentUrlEntity = createContentUrlEntity(contentUrl, size); - } // Done return contentUrlEntity; } diff --git a/source/java/org/alfresco/repo/domain/control/ControlDAO.java b/source/java/org/alfresco/repo/domain/control/ControlDAO.java index f60387bb8b..024f196365 100644 --- a/source/java/org/alfresco/repo/domain/control/ControlDAO.java +++ b/source/java/org/alfresco/repo/domain/control/ControlDAO.java @@ -52,8 +52,24 @@ public interface ControlDAO /** * Create a "Save Point" in the current transaction, for later selective rollback. - * Creation should be accompanied by a matching {@link #rollbackToSavepoint(String)} - * or {@link #releaseSavepoint(String)} using the same name. + * Creation must be accompanied by a matching {@link #rollbackToSavepoint(Savepoint)} + * or {@link #releaseSavepoint(Savepoint)}. + *

+     *  Savepoint savepoint = controlDAO.createSavepoint("functionF");
+     *  try
+     *  {
+     *      // Do something that could fail e.g. blind insert that might violate unique constraints
+     *      ...
+     *      // Success, so remove savepoint or risk crashing on long-running transactions
+     *      controlDAO.releaseSavepoint(savepoint);
+     *  }
+     *  catch (Throwable e)
+     *  {
+     *      controlDAO.rollbackToSavepoint(savepoint);
+     *      // Throw something that client code might be able to react to or try something else
+     *      ...
+     *  }
+     * 
* * @param savepoint the name of the save point * @return Returns the handle to the savepoint or null if the diff --git a/source/java/org/alfresco/repo/domain/encoding/AbstractEncodingDAOImpl.java b/source/java/org/alfresco/repo/domain/encoding/AbstractEncodingDAOImpl.java index 6175f8792e..0fb908297c 100644 --- a/source/java/org/alfresco/repo/domain/encoding/AbstractEncodingDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/encoding/AbstractEncodingDAOImpl.java @@ -18,11 +18,10 @@ */ package org.alfresco.repo.domain.encoding; -import java.io.Serializable; - -import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.cache.SimpleCache; import org.alfresco.util.Pair; +import org.alfresco.repo.cache.lookup.EntityLookupCache; +import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAOAdaptor; import org.springframework.extensions.surf.util.ParameterCheck; /** @@ -36,92 +35,89 @@ import org.springframework.extensions.surf.util.ParameterCheck; */ public abstract class AbstractEncodingDAOImpl implements EncodingDAO { - private static final Long CACHE_NULL_LONG = Long.MIN_VALUE; - private SimpleCache encodingEntityCache; - + private static final String CACHE_REGION_ENCODING = "Encoding"; + /** - * - * @param encodingEntityCache the cache of IDs to mimetypes + * Cache for the Locale values:
+ * KEY: ID
+ * VALUE: String
+ * VALUE KEY: String
*/ - public void setEncodingEntityCache(SimpleCache encodingEntityCache) + private EntityLookupCache encodingEntityCache; + + /** + * Set the cache that maintains the ID-Encoding mappings and vice-versa (bi-directional) + * + * @param encodingEntityCache the cache + */ + public void setEncodingEntityCache(SimpleCache encodingEntityCache) { - this.encodingEntityCache = encodingEntityCache; + this.encodingEntityCache = new EntityLookupCache( + encodingEntityCache, + CACHE_REGION_ENCODING, + new EncodingEntityCallbackDAO()); } - + public Pair getEncoding(Long id) { - // Check the cache - String encoding = (String) encodingEntityCache.get(id); - if (encoding != null) - { - return new Pair(id, encoding); - } - // Get it from the DB - EncodingEntity mimetypeEntity = getEncodingEntity(id); - if (mimetypeEntity == null) - { - throw new AlfrescoRuntimeException("The MimetypeEntity ID " + id + " doesn't exist."); - } - encoding = mimetypeEntity.getEncoding(); - // Cache it - encodingEntityCache.put(encoding, id); - encodingEntityCache.put(id, encoding); - // Done - return new Pair(id, encoding); + return encodingEntityCache.getByKey(id); } public Pair getEncoding(String encoding) { ParameterCheck.mandatory("encoding", encoding); - - // Check the cache - Long id = (Long) encodingEntityCache.get(encoding); - if (id != null) - { - if (id.equals(CACHE_NULL_LONG)) - { - return null; - } - else - { - return new Pair(id, encoding); - } - } - // It's not in the cache, so query - EncodingEntity result = getEncodingEntity(encoding); - if (result == null) - { - // Cache it - encodingEntityCache.put(encoding, CACHE_NULL_LONG); - // Done - return null; - } - else - { - id = result.getId(); - // Cache it - encodingEntityCache.put(id, encoding); - encodingEntityCache.put(encoding, id); - // Done - return new Pair(id, encoding); - } + return encodingEntityCache.getByValue(encoding); } public Pair getOrCreateEncoding(String encoding) { ParameterCheck.mandatory("encoding", encoding); - - Pair result = getEncoding(encoding); - if (result == null) + return encodingEntityCache.getOrCreateByValue(encoding); + } + + /** + * Callback for alf_encoding DAO + */ + private class EncodingEntityCallbackDAO extends EntityLookupCallbackDAOAdaptor + { + @Override + public String getValueKey(String value) { - EncodingEntity encodingEntity = createEncodingEntity(encoding); - Long id = encodingEntity.getId(); - result = new Pair(id, encoding); - // Cache it - encodingEntityCache.put(id, encoding); - encodingEntityCache.put(encoding, id); + return value; + } + + public Pair findByKey(Long id) + { + EncodingEntity entity = getEncodingEntity(id); + if (entity == null) + { + return null; + } + else + { + return new Pair(id, entity.getEncoding()); + } + } + + @Override + public Pair findByValue(String encoding) + { + EncodingEntity entity = getEncodingEntity(encoding); + if (entity == null) + { + return null; + } + else + { + return new Pair(entity.getId(), encoding); + } + } + + public Pair createValue(String encoding) + { + EncodingEntity entity = createEncodingEntity(encoding); + return new Pair(entity.getId(), encoding); } - return result; } /** diff --git a/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java deleted file mode 100644 index 9e0294ea6e..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java +++ /dev/null @@ -1,2578 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; -import java.io.UnsupportedEncodingException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -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.repo.cache.SimpleCache; -import org.alfresco.repo.domain.DbAccessControlEntry; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.DbAccessControlListChangeSet; -import org.alfresco.repo.domain.DbAccessControlListMember; -import org.alfresco.repo.domain.DbAuthority; -import org.alfresco.repo.domain.DbPermission; -import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.avm.AVMNodeDAO; -import org.alfresco.repo.domain.avm.AVMNodeEntity; -import org.alfresco.repo.domain.patch.PatchDAO; -import org.alfresco.repo.domain.qname.QNameDAO; -import org.alfresco.repo.security.permissions.ACEType; -import org.alfresco.repo.security.permissions.ACLCopyMode; -import org.alfresco.repo.security.permissions.ACLType; -import org.alfresco.repo.security.permissions.AccessControlEntry; -import org.alfresco.repo.security.permissions.AccessControlList; -import org.alfresco.repo.security.permissions.AccessControlListProperties; -import org.alfresco.repo.security.permissions.PermissionReference; -import org.alfresco.repo.security.permissions.SimpleAccessControlEntry; -import org.alfresco.repo.security.permissions.SimpleAccessControlEntryContext; -import org.alfresco.repo.security.permissions.SimpleAccessControlList; -import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties; -import org.alfresco.repo.security.permissions.impl.AclChange; -import org.alfresco.repo.security.permissions.impl.AclDaoComponent; -import org.alfresco.repo.security.permissions.impl.PermissionsDaoComponent; -import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport; -import org.alfresco.service.cmr.security.AccessStatus; -import org.alfresco.service.cmr.security.AuthorityType; -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.CacheMode; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.Session; -import org.hibernate.criterion.Criterion; -import org.hibernate.criterion.Restrictions; -import org.alfresco.util.Pair; -import org.springframework.orm.hibernate3.HibernateCallback; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; - -/** - * Hibernate DAO to manage ACL persistence - * - * @author andyh - */ -public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoComponent -{ - private static Log logger = LogFactory.getLog(AclDaoComponentImpl.class); - - static String QUERY_GET_PERMISSION = "permission.GetPermission"; - - static String QUERY_GET_AUTHORITY = "permission.GetAuthority"; - - static String QUERY_GET_ACE_WITH_NO_CONTEXT = "permission.GetAceWithNoContext"; - - // static String QUERY_GET_AUTHORITY_ALIAS = "permission.GetAuthorityAlias"; - - // static String QUERY_GET_AUTHORITY_ALIASES = "permission.GetAuthorityAliases"; - - static String QUERY_GET_ACES_AND_ACLS_BY_AUTHORITY = "permission.GetAcesAndAclsByAuthority"; - - static String QUERY_GET_ACES_BY_AUTHORITY = "permission.GetAcesByAuthority"; - - static String QUERY_GET_ACES_FOR_ACL = "permission.GetAcesForAcl"; - - static String QUERY_LOAD_ACL = "permission.LoadAcl"; - - static String QUERY_GET_ACLS_THAT_INHERIT_FROM_THIS_ACL = "permission.GetAclsThatInheritFromThisAcl"; - - static String QUERY_GET_AVM_NODES_BY_ACL = "permission.FindAvmNodesByACL"; - - static String QUERY_GET_LATEST_ACL_BY_ACLID = "permission.FindLatestAclByGuid"; - - /** Access to QName entities */ - private QNameDAO qnameDAO; - - /** Access to AVMNode queries */ - private AVMNodeDAO avmNodeDAO; - - /** Access to additional Patch queries */ - private PatchDAO patchDAO; - - /** a transactionally-safe cache to be injected */ - private SimpleCache aclCache; - - private boolean useOldPermissions; - - private enum WriteMode - { - /** - * Remove inherited ACEs after that set - */ - TRUNCATE_INHERITED, - /** - * Add inherited ACEs - */ - ADD_INHERITED, - /** - * The source of inherited ACEs is changing - */ - CHANGE_INHERITED, - /** - * Remove all inherited ACEs - */ - REMOVE_INHERITED, - /** - * Insert inherited ACEs - */ - INSERT_INHERITED, - /** - * Copy ACLs and update ACEs and inheritance - */ - COPY_UPDATE_AND_INHERIT, - /** - * Simlpe copy - */ - COPY_ONLY, CREATE_AND_INHERIT; - } - - /** - * - */ - public AclDaoComponentImpl() - { - super(); - // Wire up for annoying AVM hack to support copy and setting of ACLs as nodes are created - DbAccessControlListImpl.setAclDaoComponent(this); - } - - /** - * Set the DAO for accessing QName entities - * - * @param qnameDAO - */ - public void setQnameDAO(QNameDAO qnameDAO) - { - this.qnameDAO = qnameDAO; - } - - public void setPatchDAO(PatchDAO patchDAO) - { - this.patchDAO = patchDAO; - } - - public void setAvmNodeDAO(AVMNodeDAO avmNodeDAO) - { - this.avmNodeDAO = avmNodeDAO; - } - - /** - * Set the ACL cache - * - * @param aclCache - */ - public void setAclCache(SimpleCache aclCache) - { - this.aclCache = aclCache; - } - - public DbAccessControlList getDbAccessControlList(Long id) - { - if (id == null) - { - return null; - } - DbAccessControlList acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, id); - return acl; - } - - public Long createAccessControlList(AccessControlListProperties properties) - { - if (properties.getAclType() == null) - { - throw new IllegalArgumentException("ACL Type must be defined"); - } - switch (properties.getAclType()) - { - - case OLD: - if (properties.isVersioned() == Boolean.TRUE) - { - throw new IllegalArgumentException("Old acls can not be versioned"); - } - break; - case SHARED: - throw new IllegalArgumentException("Can not create shared acls direct - use get inherited"); - case DEFINING: - case LAYERED: - break; - case FIXED: - if (properties.getInherits() == Boolean.TRUE) - { - throw new IllegalArgumentException("Fixed ACLs can not inherit"); - } - case GLOBAL: - if (properties.getInherits() == Boolean.TRUE) - { - throw new IllegalArgumentException("Fixed ACLs can not inherit"); - } - default: - break; - } - return createAccessControlListImpl(properties, null, null); - } - - private Long createAccessControlListImpl(AccessControlListProperties properties, List aces, Long inherited) - { - DbAccessControlListImpl acl = new DbAccessControlListImpl(); - if (properties.getAclId() != null) - { - acl.setAclId(properties.getAclId()); - } - else - { - acl.setAclId(GUID.generate()); - } - acl.setAclType(properties.getAclType()); - acl.setAclVersion(Long.valueOf(1l)); - - switch (properties.getAclType()) - { - case FIXED: - case GLOBAL: - acl.setInherits(Boolean.FALSE); - case OLD: - case SHARED: - case DEFINING: - case LAYERED: - default: - if (properties.getInherits() != null) - { - acl.setInherits(properties.getInherits()); - } - else - { - acl.setInherits(Boolean.TRUE); - } - break; - - } - acl.setLatest(Boolean.TRUE); - - switch (properties.getAclType()) - { - case OLD: - acl.setVersioned(Boolean.FALSE); - break; - case FIXED: - case GLOBAL: - case SHARED: - case DEFINING: - case LAYERED: - default: - if (properties.isVersioned() != null) - { - acl.setVersioned(properties.isVersioned()); - } - else - { - acl.setVersioned(Boolean.TRUE); - } - break; - } - - acl.setAclChangeSet(getCurrentChangeSet()); - acl.setRequiresVersion(false); - Long created = (Long) getHibernateTemplate().save(acl); - DirtySessionMethodInterceptor.flushSession(getSession(), true); - - if ((aces != null) && aces.size() > 0) - { - List changes = new ArrayList(); - - List toAdd = new ArrayList(aces.size()); - List excluded = new ArrayList(aces.size()); - for (AccessControlEntry ace : aces) - { - - if ((ace.getPosition() != null) && (ace.getPosition() != 0)) - { - throw new IllegalArgumentException("Invalid position"); - } - - // Find authority - DbAuthority authority = getAuthority(ace.getAuthority(), true); - DbPermission permission = getPermission(ace.getPermission(), true); - - // Find context - - if (ace.getContext() != null) - { - throw new UnsupportedOperationException(); - } - - // Find ACE - DbAccessControlEntry entry = getAccessControlEntry(permission, authority, ace, true); - - // Wire up - // COW and remove any existing matches - - SimpleAccessControlEntry exclude = new SimpleAccessControlEntry(); - // match any access status - exclude.setAceType(ace.getAceType()); - exclude.setAuthority(ace.getAuthority()); - exclude.setPermission(ace.getPermission()); - exclude.setPosition(0); - - toAdd.add(entry); - excluded.add(exclude); - // Will remove from the cache - - } - Long toInherit = null; - if (inherited != null) - { - toInherit = getInheritedAccessControlList(inherited); - } - getWritable(created, toInherit, excluded, toAdd, toInherit, false, changes, WriteMode.CREATE_AND_INHERIT); - } - - return created; - } - - @SuppressWarnings("unchecked") - private void getWritable(final Long id, final Long parent, List exclude, List toAdd, Long inheritsFrom, boolean cascade, - List changes, WriteMode mode) - { - List inherited = null; - List positions = null; - - if ((mode == WriteMode.ADD_INHERITED) || (mode == WriteMode.INSERT_INHERITED) || (mode == WriteMode.CHANGE_INHERITED)) - { - inherited = new ArrayList(); - positions = new ArrayList(); - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACES_FOR_ACL); - query.setParameter("id", parent); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List members = (List) getHibernateTemplate().execute(callback); - - for (DbAccessControlListMember member : members) - { - if ((mode == WriteMode.INSERT_INHERITED) && (member.getPosition() == 0)) - { - inherited.add(member.getAccessControlEntry()); - positions.add(member.getPosition()); - } - else - { - inherited.add(member.getAccessControlEntry()); - positions.add(member.getPosition()); - } - } - } - - getWritable(id, parent, exclude, toAdd, inheritsFrom, inherited, positions, cascade, 0, changes, mode, false); - } - - /** - * Make a whole tree of ACLs copy on write if required Includes adding and removing ACEs which cna be optimised - * slighlty for copy on write (no need to add and then remove) - * - * @param id - * @param parent - * @param exclude - * @param toAdd - * @param inheritsFrom - * @param cascade - * @param depth - * @param changes - */ - @SuppressWarnings("unchecked") - private void getWritable(final Long id, final Long parent, List exclude, List toAdd, Long inheritsFrom, - List inherited, List positions, boolean cascade, int depth, List changes, WriteMode mode, boolean requiresVersion) - { - AclChange current = getWritable(id, parent, exclude, toAdd, inheritsFrom, inherited, positions, depth, mode, requiresVersion); - changes.add(current); - - boolean cascadeVersion = requiresVersion; - if (!cascadeVersion) - { - cascadeVersion = !current.getBefore().equals(current.getAfter()); - } - - if (cascade) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACLS_THAT_INHERIT_FROM_THIS_ACL); - query.setParameter("id", id); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List inheritors = (List) getHibernateTemplate().execute(callback); - for (Long nextId : inheritors) - { - // Check for those that inherit themselves to other nodes ... - if (nextId != id) - { - getWritable(nextId, current.getAfter(), exclude, toAdd, current.getAfter(), inherited, positions, cascade, depth + 1, changes, mode, cascadeVersion); - } - } - } - } - - /** - * COW for an individual ACL - * - * @param id - * @param parent - * @param exclude - * @param toAdd - * @param inheritsFrom - * @param depth - * @return - an AclChange - */ - @SuppressWarnings("unchecked") - private AclChange getWritable(final Long id, final Long parent, List exclude, List toAdd, Long inheritsFrom, - List inherited, List positions, int depth, WriteMode mode, boolean requiresVersion) - { - DbAccessControlList acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, id); - if (!acl.isLatest()) - { - aclCache.remove(id); - return new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType()); - } - - if (!acl.isVersioned()) - { - switch (mode) - { - case COPY_UPDATE_AND_INHERIT: - removeAcesFromAcl(id, exclude, depth); - addAcesToAcl(acl, toAdd, depth); - break; - case CHANGE_INHERITED: - replaceInherited(id, acl, inherited, positions, depth); - break; - case ADD_INHERITED: - addInherited(acl, inherited, positions, depth); - break; - case TRUNCATE_INHERITED: - truncateInherited(id, depth); - break; - case INSERT_INHERITED: - insertInherited(id, acl, inherited, positions, depth); - break; - case REMOVE_INHERITED: - removeInherited(id, depth); - break; - case CREATE_AND_INHERIT: - addAcesToAcl(acl, toAdd, depth); - addInherited(acl, inherited, positions, depth); - case COPY_ONLY: - default: - break; - } - if (inheritsFrom != null) - { - acl.setInheritsFrom(inheritsFrom); - } - aclCache.remove(id); - return new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType()); - } - else if ((acl.getAclChangeSet() == getCurrentChangeSet()) && (!requiresVersion) && (!acl.getRequiresVersion())) - { - switch (mode) - { - case COPY_UPDATE_AND_INHERIT: - removeAcesFromAcl(id, exclude, depth); - addAcesToAcl(acl, toAdd, depth); - break; - case CHANGE_INHERITED: - replaceInherited(id, acl, inherited, positions, depth); - break; - case ADD_INHERITED: - addInherited(acl, inherited, positions, depth); - break; - case TRUNCATE_INHERITED: - truncateInherited(id, depth); - break; - case INSERT_INHERITED: - insertInherited(id, acl, inherited, positions, depth); - break; - case REMOVE_INHERITED: - removeInherited(id, depth); - break; - case CREATE_AND_INHERIT: - addAcesToAcl(acl, toAdd, depth); - addInherited(acl, inherited, positions, depth); - case COPY_ONLY: - default: - break; - } - if (inheritsFrom != null) - { - acl.setInheritsFrom(inheritsFrom); - } - aclCache.remove(id); - return new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType()); - } - else - { - DbAccessControlList newAcl = new DbAccessControlListImpl(); - newAcl.setAclChangeSet(getCurrentChangeSet()); - newAcl.setAclId(acl.getAclId()); - newAcl.setAclType(acl.getAclType()); - newAcl.setAclVersion(acl.getAclVersion() + 1); - newAcl.setInheritedAclId(-1l); - newAcl.setInherits(acl.getInherits()); - newAcl.setInheritsFrom((inheritsFrom != null) ? inheritsFrom : acl.getInheritsFrom()); - newAcl.setLatest(Boolean.TRUE); - newAcl.setVersioned(Boolean.TRUE); - newAcl.setRequiresVersion(Boolean.FALSE); - Long created = (Long) getHibernateTemplate().save(newAcl); - DirtySessionMethodInterceptor.flushSession(getSession(), true); - - // Create new membership entries - excluding those in the given pattern - - // AcePatternMatcher excluder = new AcePatternMatcher(exclude); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACES_FOR_ACL); - query.setParameter("id", id); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List members = (List) getHibernateTemplate().execute(callback); - - for (DbAccessControlListMember member : members) - { - // if (mode == WriteMode.COPY_UPDATE_AND_INHERIT) - // { - // if ((member.getPosition() == depth) && ((excluder == null) || !excluder.matches(member.getACE(), - // member.getPosition()))) - // { - // DbAccessControlListMemberImpl newMember = new DbAccessControlListMemberImpl(); - // newMember.setACL(newAcl); - // newMember.setACE(member.getACE()); - // newMember.setPosition(member.getPosition()); - // getHibernateTemplate().save(newMember); - // } - // } - - // TODO: optimise copy cases :-) - DbAccessControlListMemberImpl newMember = new DbAccessControlListMemberImpl(); - newMember.setAccessControlList(newAcl); - newMember.setAccessControlEntry(member.getAccessControlEntry()); - newMember.setPosition(member.getPosition()); - getHibernateTemplate().save(newMember); - DirtySessionMethodInterceptor.flushSession(getSession(), true); - - } - - // add new - - switch (mode) - { - case COPY_UPDATE_AND_INHERIT: - // Done above - removeAcesFromAcl(newAcl.getId(), exclude, depth); - addAcesToAcl(newAcl, toAdd, depth); - break; - case CHANGE_INHERITED: - replaceInherited(newAcl.getId(), newAcl, inherited, positions, depth); - break; - case ADD_INHERITED: - addInherited(newAcl, inherited, positions, depth); - break; - case TRUNCATE_INHERITED: - truncateInherited(newAcl.getId(), depth); - break; - case INSERT_INHERITED: - insertInherited(newAcl.getId(), newAcl, inherited, positions, depth); - break; - case REMOVE_INHERITED: - removeInherited(newAcl.getId(), depth); - break; - case CREATE_AND_INHERIT: - addAcesToAcl(acl, toAdd, depth); - addInherited(acl, inherited, positions, depth); - case COPY_ONLY: - default: - break; - } - - // Fix up inherited ACL if required - - if (newAcl.getAclType() == ACLType.SHARED) - { - if (parent != null) - { - Long writableParentAcl = getWritable(parent, null, null, null, null, null, null, 0, WriteMode.COPY_ONLY, false).getAfter(); - DbAccessControlList parentAcl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, writableParentAcl); - parentAcl.setInheritedAclId(created); - } - } - - // fix up old version - acl.setLatest(Boolean.FALSE); - acl.setRequiresVersion(Boolean.FALSE); - aclCache.remove(id); - return new AclChangeImpl(id, created, acl.getAclType(), newAcl.getAclType()); - } - - } - - /** - * Helper to remove ACEs from an ACL - * - * @param id - * @param exclude - * @param depth - */ - @SuppressWarnings("unchecked") - private void removeAcesFromAcl(final Long id, final List exclude, final int depth) - { - AcePatternMatcher excluder = new AcePatternMatcher(exclude); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - if (exclude == null) - { - Criteria criteria = session.createCriteria(DbAccessControlListMemberImpl.class, "member"); - criteria.createAlias("accessControlList", "acl"); - criteria.add(Restrictions.eq("acl.id", id)); - criteria.createAlias("accessControlEntry", "ace"); - criteria.createAlias("ace.authority", "authority"); - criteria.createAlias("ace.permission", "permission"); - criteria.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP); - DirtySessionMethodInterceptor.setCriteriaFlushMode(session, criteria); - return criteria.list(); - } - else - { - Criteria criteria = session.createCriteria(DbAccessControlListMemberImpl.class, "member"); - criteria.createAlias("accessControlList", "acl"); - criteria.add(Restrictions.eq("acl.id", id)); - // build or - if (exclude.size() == 1) - { - AccessControlEntry excluded = exclude.get(0); - if ((excluded.getPosition() != null) && excluded.getPosition() >= 0) - { - criteria.add(Restrictions.eq("position", Integer.valueOf(depth))); - } - if ((excluded.getAccessStatus() != null) || (excluded.getAceType() != null) || (excluded.getAuthority() != null) || (excluded.getPermission() != null)) - { - criteria.createAlias("accessControlEntry", "ace"); - if (excluded.getAccessStatus() != null) - { - criteria.add(Restrictions.eq("ace.allowed", excluded.getAccessStatus() == AccessStatus.ALLOWED ? Boolean.TRUE : Boolean.FALSE)); - } - if (excluded.getAceType() != null) - { - criteria.add(Restrictions.eq("ace.applies", Integer.valueOf(excluded.getAceType().getId()))); - } - if (excluded.getAuthority() != null) - { - criteria.createAlias("ace.authority", "authority"); - criteria.add(Restrictions.eq("authority.authority", excluded.getAuthority())); - } - if (excluded.getPermission() != null) - { - criteria.createAlias("ace.permission", "permission"); - criteria.add(Restrictions.eq("permission.name", excluded.getPermission().getName())); - // TODO: Add typeQname - } - } - } - else - { - - criteria.createAlias("accessControlEntry", "ace"); - criteria.createAlias("ace.authority", "authority"); - criteria.createAlias("ace.permission", "permission"); - List toOr = new LinkedList(); - LOOP: for (AccessControlEntry excluded : exclude) - { - List toAnd = new LinkedList(); - if ((excluded.getPosition() != null) && excluded.getPosition() >= 0) - { - toAnd.add(Restrictions.eq("position", Integer.valueOf(depth))); - } - if (excluded.getAccessStatus() != null) - { - toAnd.add(Restrictions.eq("ace.allowed", excluded.getAccessStatus() == AccessStatus.ALLOWED ? Boolean.TRUE : Boolean.FALSE)); - } - if (excluded.getAceType() != null) - { - toAnd.add(Restrictions.eq("ace.applies", Integer.valueOf(excluded.getAceType().getId()))); - } - if (excluded.getAuthority() != null) - { - toAnd.add(Restrictions.eq("authority.authority", excluded.getAuthority())); - } - if (excluded.getPermission() != null) - { - toAnd.add(Restrictions.eq("permission.name", excluded.getPermission().getName())); - // TODO: Add typeQname - } - - Criterion accumulated = null; - for (Criterion current : toAnd) - { - if (accumulated == null) - { - accumulated = current; - } - else - { - accumulated = Restrictions.and(accumulated, current); - } - } - if (accumulated == null) - { - // matches all - toOr = null; - break LOOP; - } - else - { - toOr.add(accumulated); - } - } - Criterion accumulated = null; - for (Criterion current : toOr) - { - if (accumulated == null) - { - accumulated = current; - } - else - { - accumulated = Restrictions.or(accumulated, current); - } - } - if (accumulated == null) - { - // no action - } - else - { - criteria.add(accumulated); - } - - } - - criteria.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP); - DirtySessionMethodInterceptor.setCriteriaFlushMode(session, criteria); - return criteria.list(); - - } - } - }; - - List> results = (List>) getHibernateTemplate().execute(callback); - - boolean removed = false; - for (Map result : results) - { - DbAccessControlListMember member = (DbAccessControlListMember) result.get("member"); - if ((exclude != null) && excluder.matches(qnameDAO, result, depth)) - { - getHibernateTemplate().delete(member); - removed = true; - } - } - if (removed) - { - DirtySessionMethodInterceptor.flushSession(getSession(), true); - } - - } - - /** - * Helper to add ACEs to an ACL - * - * @param acl - * @param toAdd - * @param depth - */ - private void addAcesToAcl(DbAccessControlList acl, List toAdd, int depth) - { - if (toAdd != null) - { - for (DbAccessControlEntry add : toAdd) - { - DbAccessControlListMemberImpl newMember = new DbAccessControlListMemberImpl(); - newMember.setAccessControlList(acl); - newMember.setAccessControlEntry(add); - newMember.setPosition(depth); - getHibernateTemplate().save(newMember); - } - DirtySessionMethodInterceptor.flushSession(getSession(), true); - } - } - - private void replaceInherited(Long id, DbAccessControlList acl, List inherited, List positions, int depth) - { - truncateInherited(id, depth); - addInherited(acl, inherited, positions, depth); - } - - @SuppressWarnings("unchecked") - private void truncateInherited(final Long id, int depth) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACES_FOR_ACL); - query.setParameter("id", id); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List members = (List) getHibernateTemplate().execute(callback); - - boolean removed = false; - for (DbAccessControlListMember member : members) - { - if (member.getPosition() > depth) - { - getHibernateTemplate().delete(member); - removed = true; - } - } - if (removed) - { - DirtySessionMethodInterceptor.flushSession(getSession(), true); - } - } - - @SuppressWarnings("unchecked") - private void removeInherited(final Long id, int depth) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACES_FOR_ACL); - query.setParameter("id", id); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List members = (List) getHibernateTemplate().execute(callback); - - boolean changed = false; - for (DbAccessControlListMember member : members) - { - if (member.getPosition() == depth + 1) - { - getHibernateTemplate().delete(member); - changed = true; - } - else if (member.getPosition() > (depth + 1)) - { - member.setPosition(member.getPosition() - 1); - changed = true; - } - } - if (changed) - { - DirtySessionMethodInterceptor.flushSession(getSession(), true); - } - } - - private void addInherited(DbAccessControlList acl, List inherited, List positions, int depth) - { - if (inherited != null) - { - for (int i = 0; i < inherited.size(); i++) - { - DbAccessControlEntry add = inherited.get(i); - Integer position = positions.get(i); - - DbAccessControlListMemberImpl newMember = new DbAccessControlListMemberImpl(); - newMember.setAccessControlList(acl); - newMember.setAccessControlEntry(add); - newMember.setPosition(position.intValue() + depth + 1); - getHibernateTemplate().save(newMember); - - } - DirtySessionMethodInterceptor.flushSession(getSession(), true); - } - } - - @SuppressWarnings("unchecked") - private void insertInherited(final Long id, DbAccessControlList acl, List inherited, List positions, int depth) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACES_FOR_ACL); - query.setParameter("id", id); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List members = (List) getHibernateTemplate().execute(callback); - - boolean changed = false; - for (DbAccessControlListMember member : members) - { - if (member.getPosition() > depth) - { - member.setPosition(member.getPosition() + 1); - changed = true; - } - } - if (changed) - { - DirtySessionMethodInterceptor.flushSession(getSession(), true); - } - - for (int i = 0; i < inherited.size(); i++) - { - DbAccessControlEntry add = inherited.get(i); - Integer position = positions.get(i); - - DbAccessControlListMemberImpl newMember = new DbAccessControlListMemberImpl(); - newMember.setAccessControlList(acl); - newMember.setAccessControlEntry(add); - newMember.setPosition(position.intValue() + depth + 1); - getHibernateTemplate().save(newMember); - - } - DirtySessionMethodInterceptor.flushSession(getSession(), true); - - } - - /** - * Used when deleting a user. No ACL is updated - the user has gone the aces and all related info is deleted. - */ - @SuppressWarnings("unchecked") - public List deleteAccessControlEntries(final String authority) - { - List acls = new ArrayList(); - Set aces = new HashSet(); - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACES_AND_ACLS_BY_AUTHORITY); - query.setParameter("authority", authority); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List results = (List) getHibernateTemplate().execute(callback); - - // fix up members and extract acls and aces - - for (Object[] ids : results) - { - String authorityFound = (String) ids[3]; - if (authorityFound.equals(authority)) - { - // Delete acl entry - DbAccessControlListMember member = (DbAccessControlListMember) getHibernateTemplate().get(DbAccessControlListMemberImpl.class, (Long) ids[0]); - Long aclId = ((Long) ids[1]); - aclCache.remove(aclId); - DbAccessControlList list = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, aclId); - acls.add(new AclChangeImpl(aclId, aclId, list.getAclType(), list.getAclType())); - getHibernateTemplate().delete(member); - aces.add((Long) ids[2]); - } - } - - // remove ACEs - - for (Long id : aces) - { - // Delete acl entry - DbAccessControlEntry ace = (DbAccessControlEntry) getHibernateTemplate().get(DbAccessControlEntryImpl.class, id); - getHibernateTemplate().delete(ace); - } - - // Tidy up any unreferenced ACEs - - callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACES_BY_AUTHORITY); - query.setParameter("authority", authority); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List unreferenced = (List) getHibernateTemplate().execute(callback); - - for (DbAccessControlEntry ace : unreferenced) - { - getHibernateTemplate().delete(ace); - } - - // remove authority - DbAuthority toRemove = getAuthority(authority, false); - if (toRemove != null) - { - getHibernateTemplate().delete(toRemove); - } - - // TODO: Remove affected ACLs from the cache - DirtySessionMethodInterceptor.flushSession(getSession(), true); - return acls; - } - - @SuppressWarnings("unchecked") - public void onDeleteAccessControlList(final long id) - { - // The acl has gone - remove any members it may have - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACES_FOR_ACL); - query.setParameter("id", id); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List members = (List) getHibernateTemplate().execute(callback); - - for (DbAccessControlListMember member : members) - { - getHibernateTemplate().delete(member); - } - DirtySessionMethodInterceptor.flushSession(getSession(), true); - aclCache.remove(id); - } - - @SuppressWarnings("unchecked") - public List deleteAccessControlList(final Long id) - { - if (logger.isDebugEnabled()) - { - HibernateCallback check = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Criteria criteria = getSession().createCriteria(NodeImpl.class, "node"); - criteria.createAlias("node.accessControlList", "acl"); - criteria.add(Restrictions.eq("acl.id", id)); - criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); - DirtySessionMethodInterceptor.setCriteriaFlushMode(session, criteria); - return criteria.list(); - } - }; - List nodes = (List) getHibernateTemplate().execute(check); - for (Node node : nodes) - { - logger.debug("Found " + node.getId() + " " + node.getUuid() + " " + node.getAccessControlList()); - } - } - - List acls = new ArrayList(); - - final DbAccessControlList acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, id); - if (!acl.isLatest()) - { - throw new UnsupportedOperationException("Old ALC versions can not be updated"); - } - if (acl.getAclType() == ACLType.SHARED) - { - throw new UnsupportedOperationException("Delete is not supported for shared acls - they are deleted with the defining acl"); - } - - if ((acl.getAclType() == ACLType.DEFINING) || (acl.getAclType() == ACLType.LAYERED)) - { - if ((acl.getInheritedAclId() != null) && (acl.getInheritedAclId() != -1)) - { - final DbAccessControlList inherited = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, acl.getInheritedAclId()); - // Will remove from the cache - getWritable(inherited.getId(), acl.getInheritsFrom(), null, null, null, true, acls, WriteMode.REMOVE_INHERITED); - DbAccessControlList unusedInherited = null; - for (AclChange change : acls) - { - if (change.getBefore() == inherited.getId()) - { - unusedInherited = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, change.getAfter()); - } - } - - final Long newId = unusedInherited.getId(); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACLS_THAT_INHERIT_FROM_THIS_ACL); - query.setParameter("id", newId); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List inheritors = (List) getHibernateTemplate().execute(callback); - for (Long nextId : inheritors) - { - // Will remove from the cache - getWritable(nextId, acl.getInheritsFrom(), null, null, acl.getInheritsFrom(), true, acls, WriteMode.REMOVE_INHERITED); - } - - callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACES_FOR_ACL); - query.setParameter("id", newId); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List members = (List) getHibernateTemplate().execute(callback); - - for (DbAccessControlListMember member : members) - { - getHibernateTemplate().delete(member); - } - - getHibernateTemplate().delete(unusedInherited); - if (inherited.isVersioned()) - { - inherited.setLatest(Boolean.FALSE); - } - else - { - getHibernateTemplate().delete(inherited); - } - } - } - else - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACLS_THAT_INHERIT_FROM_THIS_ACL); - query.setParameter("id", id); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List inheritors = (List) getHibernateTemplate().execute(callback); - for (Long nextId : inheritors) - { - // Will remove from the cache - getWritable(nextId, acl.getInheritsFrom(), null, null, null, true, acls, WriteMode.REMOVE_INHERITED); - } - } - - // delete - if (acl.isVersioned()) - { - acl.setLatest(Boolean.FALSE); - } - else - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACES_FOR_ACL); - query.setParameter("id", id); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List members = (List) getHibernateTemplate().execute(callback); - - for (DbAccessControlListMember member : members) - { - getHibernateTemplate().delete(member); - } - - getHibernateTemplate().delete(acl); - DirtySessionMethodInterceptor.flushSession(getSession(), true); - } - - // remove the deleted acl from the cache - aclCache.remove(id); - acls.add(new AclChangeImpl(id, null, acl.getAclType(), null)); - return acls; - } - - public List deleteLocalAccessControlEntries(Long id) - { - List changes = new ArrayList(); - SimpleAccessControlEntry pattern = new SimpleAccessControlEntry(); - pattern.setPosition(Integer.valueOf(0)); - // Will remove from the cache - getWritable(id, null, Collections.singletonList(pattern), null, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT); - return changes; - } - - public List deleteInheritedAccessControlEntries(Long id) - { - List changes = new ArrayList(); - SimpleAccessControlEntry pattern = new SimpleAccessControlEntry(); - pattern.setPosition(Integer.valueOf(-1)); - // Will remove from the cache - getWritable(id, null, Collections.singletonList(pattern), null, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT); - return changes; - } - - public List deleteAccessControlEntries(Long id, AccessControlEntry pattern) - { - List changes = new ArrayList(); - // Will remove from the cache - getWritable(id, null, Collections.singletonList(pattern), null, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT); - return changes; - } - - /** - * Search for access control lists - * - * @param pattern - * @return the ids of the ACLs found - */ - public Long[] findAccessControlList(AccessControlEntry pattern) - { - throw new UnsupportedOperationException(); - } - - public AccessControlList getAccessControlList(Long id) - { - AccessControlList acl = aclCache.get(id); - if (acl == null) - { - acl = getAccessControlListImpl(id); - aclCache.put(id, acl); - } - else - { - // System.out.println("Used cache for "+id); - } - return acl; - } - - /** - * @param id - * @return the access control list - */ - @SuppressWarnings("unchecked") - public AccessControlList getAccessControlListImpl(final Long id) - { - SimpleAccessControlList acl = new SimpleAccessControlList(); - AccessControlListProperties properties = getAccessControlListProperties(id); - if (properties == null) - { - return null; - } - - acl.setProperties(properties); - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_LOAD_ACL); - query.setParameter("id", id); - query.setCacheMode(CacheMode.IGNORE); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List results = (List) getHibernateTemplate().execute(callback); - - List entries = new ArrayList(results.size()); - for (Object[] result : results) - // for (DbAccessControlListMember member : members) - { - Boolean aceIsAllowed = (Boolean) result[0]; - Integer aceType = (Integer) result[1]; - String authority = (String) result[2]; - Long permissionId = (Long) result[3]; - Integer position = (Integer) result[4]; - - SimpleAccessControlEntry sacEntry = new SimpleAccessControlEntry(); - sacEntry.setAccessStatus(aceIsAllowed ? AccessStatus.ALLOWED : AccessStatus.DENIED); - sacEntry.setAceType(ACEType.getACETypeFromId(aceType)); - sacEntry.setAuthority(authority); - // if (entry.getContext() != null) - // { - // SimpleAccessControlEntryContext context = new SimpleAccessControlEntryContext(); - // context.setClassContext(entry.getContext().getClassContext()); - // context.setKVPContext(entry.getContext().getKvpContext()); - // context.setPropertyContext(entry.getContext().getPropertyContext()); - // sacEntry.setContext(context); - // } - DbPermission perm = (DbPermission) getSession().get(DbPermissionImpl.class, permissionId); - QName permTypeQName = qnameDAO.getQName(perm.getTypeQNameId()).getSecond(); // Has an ID so must exist - SimplePermissionReference permissionRefernce = SimplePermissionReference.getPermissionReference(permTypeQName, perm.getName()); - sacEntry.setPermission(permissionRefernce); - sacEntry.setPosition(position); - - entries.add(sacEntry); - - } - - Collections.sort(entries); - - acl.setEntries(entries); - - return acl; - } - - public AccessControlListProperties getAccessControlListProperties(Long id) - { - DbAccessControlList acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, id); - if (acl == null) - { - return null; - } - SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); - properties.setAclId(acl.getAclId()); - properties.setAclType(acl.getAclType()); - properties.setAclVersion(acl.getAclVersion()); - properties.setInherits(acl.getInherits()); - properties.setLatest(acl.isLatest()); - properties.setVersioned(acl.isVersioned()); - properties.setId(id); - return properties; - } - - public Long getInheritedAccessControlList(Long id) - { - DbAccessControlList acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, id); - if (acl.getAclType() == ACLType.OLD) - { - return null; - } - if ((acl.getInheritedAclId() != null) && (acl.getInheritedAclId() != -1)) - { - return acl.getInheritedAclId(); - } - - if ((acl.getAclType() == ACLType.DEFINING) || (acl.getAclType() == ACLType.LAYERED)) - { - List changes = new ArrayList(); - // created shared acl - SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); - properties.setAclType(ACLType.SHARED); - properties.setInherits(Boolean.TRUE); - properties.setVersioned(acl.isVersioned()); - Long sharedId = createAccessControlListImpl(properties, null, null); - @SuppressWarnings("unused") - DbAccessControlList shared = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, sharedId); - getWritable(sharedId, id, null, null, id, true, changes, WriteMode.ADD_INHERITED); - acl.setInheritedAclId(sharedId); - return sharedId; - } - else - { - acl.setInheritedAclId(acl.getId()); - return acl.getInheritedAclId(); - } - } - - public List invalidateAccessControlEntries(final String authority) - { - throw new UnsupportedOperationException(); - } - - public List mergeInheritedAccessControlList(Long inherited, Long target) - { - - // TODO: For now we do a replace - we could do an insert if both inherit from the same acl - - List changes = new ArrayList(); - - DbAccessControlList targetAcl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, target); - - DbAccessControlList inheritedAcl = null; - if (inherited != null) - { - inheritedAcl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, inherited); - } - else - { - // Assume we are just resetting it to inherit as before - if (targetAcl.getInheritsFrom() != null) - { - inheritedAcl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, targetAcl.getInheritsFrom()); - if (inheritedAcl == null) - { - // TODO: Try previous versions - throw new IllegalStateException("No old inheritance definition to use"); - } - else - { - // find the latest version of the acl - if (!inheritedAcl.isLatest()) - { - final String searchAclId = inheritedAcl.getAclId(); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_LATEST_ACL_BY_ACLID); - query.setParameter("aclId", searchAclId); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.uniqueResult(); - } - }; - Long actualInheritor = (Long) getHibernateTemplate().execute(callback); - inheritedAcl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, actualInheritor); - if (inheritedAcl == null) - { - // TODO: Try previous versions - throw new IllegalStateException("No ACL found"); - } - } - } - } - else - { - // There is no inheritance to set - return changes; - } - } - - // recursion test - // if inherited already inherits from the target - - DbAccessControlList test = inheritedAcl; - while (test != null) - { - if (test.getId() == target) - { - throw new IllegalStateException("Cyclical ACL detected"); - } - Long parent = test.getInheritsFrom(); - if ((parent == null) || (parent == -1l)) - { - test = null; - } - else - { - test = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, test.getInheritsFrom()); - } - } - - if ((targetAcl.getAclType() != ACLType.DEFINING) && (targetAcl.getAclType() != ACLType.LAYERED)) - { - throw new IllegalArgumentException("Only defining ACLs can have their inheritance set"); - } - - if (!targetAcl.getInherits()) - { - return changes; - } - - Long actualInheritedId = inheritedAcl.getId(); - - if ((inheritedAcl.getAclType() == ACLType.DEFINING) || (inheritedAcl.getAclType() == ACLType.LAYERED)) - { - actualInheritedId = getInheritedAccessControlList(actualInheritedId); - } - // Will remove from the cache - getWritable(target, actualInheritedId, null, null, actualInheritedId, true, changes, WriteMode.CHANGE_INHERITED); - - return changes; - - } - - @SuppressWarnings("unchecked") - public List setAccessControlEntry(final Long id, final AccessControlEntry ace) - { - DbAccessControlList target = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, id); - if (target.getAclType() == ACLType.SHARED) - { - throw new IllegalArgumentException("Shared ACLs are immutable"); - } - - List changes = new ArrayList(); - - if ((ace.getPosition() != null) && (ace.getPosition() != 0)) - { - throw new IllegalArgumentException("Invalid position"); - } - - // Find authority - DbAuthority authority = getAuthority(ace.getAuthority(), true); - DbPermission permission = getPermission(ace.getPermission(), true); - - // Find context - - if (ace.getContext() != null) - { - throw new UnsupportedOperationException(); - } - - // Find ACE - DbAccessControlEntry entry = getAccessControlEntry(permission, authority, ace, true); - - // Wire up - // COW and remove any existing matches - - SimpleAccessControlEntry exclude = new SimpleAccessControlEntry(); - // match any access status - exclude.setAceType(ace.getAceType()); - exclude.setAuthority(ace.getAuthority()); - exclude.setPermission(ace.getPermission()); - exclude.setPosition(0); - List toAdd = new ArrayList(1); - toAdd.add(entry); - // Will remove from the cache - getWritable(id, null, Collections.singletonList(exclude), toAdd, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT); - - return changes; - } - - private long getCrc(String str) - { - try - { - CRC32 crc = new CRC32(); - crc.update(str.getBytes("UTF-8")); - return crc.getValue(); - } - catch (UnsupportedEncodingException e) - { - throw new RuntimeException("UTF-8 encoding is not supported"); - } - } - - public List enableInheritance(Long id, Long parent) - { - List changes = new ArrayList(); - - DbAccessControlList acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, id); - - switch (acl.getAclType()) - { - case FIXED: - case GLOBAL: - throw new IllegalArgumentException("Fixed and global permissions can not inherit"); - case OLD: - acl.setInherits(Boolean.TRUE); - aclCache.remove(id); - changes.add(new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType())); - DirtySessionMethodInterceptor.flushSession(getSession(), true); - return changes; - case SHARED: - // TODO support a list of children and casacade if given - throw new IllegalArgumentException( - "Shared acls should be replace by creating a definig ACL, wiring it up for inhertitance, and then applying inheritance to any children. It can not be done by magic "); - case DEFINING: - case LAYERED: - default: - if (!acl.getInherits()) - { - // Will remove from the cache - getWritable(id, null, null, null, null, false, changes, WriteMode.COPY_ONLY); - acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, changes.get(0).getAfter()); - acl.setInherits(Boolean.TRUE); - DirtySessionMethodInterceptor.flushSession(getSession(), true); - } - else - { - // Will remove from the cache - getWritable(id, null, null, null, null, false, changes, WriteMode.COPY_ONLY); - } - - List merged = mergeInheritedAccessControlList(parent, changes.get(0).getAfter()); - changes.addAll(merged); - return changes; - } - } - - public List disableInheritance(Long id, boolean setInheritedOnAcl) - { - DbAccessControlList acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, id); - List changes = new ArrayList(1); - switch (acl.getAclType()) - { - case FIXED: - case GLOBAL: - return Collections. singletonList(new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType())); - case OLD: - - acl.setInherits(Boolean.FALSE); - aclCache.remove(id); - changes.add(new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType())); - DirtySessionMethodInterceptor.flushSession(getSession(), true); - return changes; - case SHARED: - // TODO support a list of children and casacade if given - throw new IllegalArgumentException("Shared ACL must inherit"); - case DEFINING: - case LAYERED: - default: - return disableInheritanceImpl(id, setInheritedOnAcl, acl); - } - } - - public Long getCopy(Long toCopy, Long toInheritFrom, ACLCopyMode mode) - { - DbAccessControlList aclToCopy; - Long inheritedId; - DbAccessControlList aclToInheritFrom; - switch (mode) - { - case INHERIT: - - if (toCopy.equals(toInheritFrom)) - { - return getInheritedAccessControlList(toCopy); - } - else - { - throw new UnsupportedOperationException(); - } - case COW: - aclToCopy = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, toCopy); - aclToCopy.setRequiresVersion(true); - aclCache.remove(toCopy); - inheritedId = getInheritedAccessControlList(toCopy); - if ((inheritedId != null) && (!inheritedId.equals(toCopy))) - { - DbAccessControlList inheritedAcl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, inheritedId); - inheritedAcl.setRequiresVersion(true); - aclCache.remove(inheritedId); - } - DirtySessionMethodInterceptor.flushSession(getSession(), true); - return toCopy; - case REDIRECT: - if ((toInheritFrom != null) && (toInheritFrom == toCopy)) - { - return getInheritedAccessControlList(toInheritFrom); - } - aclToCopy = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, toCopy); - aclToInheritFrom = null; - if (toInheritFrom != null) - { - aclToInheritFrom = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, toInheritFrom); - } - - switch (aclToCopy.getAclType()) - { - case DEFINING: - // This is not called on the redirecting node as only LAYERED change permissins when redirected - // So this needs to make a copy in the same way layered does - case LAYERED: - if (toInheritFrom == null) - { - return toCopy; - } - // manages cache clearing beneath - List changes = mergeInheritedAccessControlList(toInheritFrom, toCopy); - for (AclChange change : changes) - { - if (change.getBefore().equals(toCopy)) - { - return change.getAfter(); - } - } - throw new UnsupportedOperationException(); - case SHARED: - if (aclToInheritFrom != null) - { - return getInheritedAccessControlList(toInheritFrom); - } - else - { - throw new UnsupportedOperationException(); - } - case FIXED: - case GLOBAL: - case OLD: - return toCopy; - default: - throw new UnsupportedOperationException(); - } - case COPY: - aclToCopy = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, toCopy); - aclToInheritFrom = null; - if (toInheritFrom != null) - { - aclToInheritFrom = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, toInheritFrom); - } - - switch (aclToCopy.getAclType()) - { - case DEFINING: - SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); - properties.setAclType(ACLType.DEFINING); - properties.setInherits(aclToCopy.getInherits()); - // Accept default versioning - Long id = createAccessControlList(properties); - - AccessControlList indirectAcl = getAccessControlList(toCopy); - for (AccessControlEntry entry : indirectAcl.getEntries()) - { - if (entry.getPosition() == 0) - { - setAccessControlEntry(id, entry); - } - } - if (aclToInheritFrom != null) - { - mergeInheritedAccessControlList(toInheritFrom, id); - } - DirtySessionMethodInterceptor.flushSession(getSession(), true); - return id; - case SHARED: - if (aclToInheritFrom != null) - { - return getInheritedAccessControlList(toInheritFrom); - } - else - { - return null; - } - case FIXED: - case GLOBAL: - case LAYERED: - case OLD: - return toCopy; - default: - throw new UnsupportedOperationException(); - } - default: - throw new UnsupportedOperationException(); - } - - } - - public DbAccessControlList getDbAccessControlListCopy(Long toCopy, Long toInheritFrom, ACLCopyMode mode) - { - Long id = getCopy(toCopy, toInheritFrom, mode); - if (id == null) - { - return null; - } - DbAccessControlList acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, id); - return acl; - } - - public List getAvmNodesByACL(final Long id) - { - - List avmNodeIds = avmNodeDAO.getAVMNodesByAclId(id); - return avmNodeIds; - } - - @SuppressWarnings("unchecked") - private List disableInheritanceImpl(Long id, boolean setInheritedOnAcl, DbAccessControlList acl) - { - List changes = new ArrayList(); - - if (!acl.getInherits()) - { - return Collections. emptyList(); - } - // Manges caching - getWritable(id, null, null, null, null, false, changes, WriteMode.COPY_ONLY); - acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, changes.get(0).getAfter()); - final Long inheritsFrom = acl.getInheritsFrom(); - acl.setInherits(Boolean.FALSE); - // Keep inherits from so we can reinstate if required - // acl.setInheritsFrom(-1l); - // Manges caching - getWritable(acl.getId(), null, null, null, null, true, changes, WriteMode.TRUNCATE_INHERITED); - - // set Inherited - TODO: UNTESTED - - if ((inheritsFrom != null) && (inheritsFrom != -1) && setInheritedOnAcl) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACES_FOR_ACL); - query.setParameter("id", inheritsFrom); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List members = (List) getHibernateTemplate().execute(callback); - - for (DbAccessControlListMember member : members) - { - SimpleAccessControlEntry entry = new SimpleAccessControlEntry(); - entry.setAccessStatus(member.getAccessControlEntry().isAllowed() ? AccessStatus.ALLOWED : AccessStatus.DENIED); - entry.setAceType(member.getAccessControlEntry().getAceType()); - entry.setAuthority(member.getAccessControlEntry().getAuthority().getAuthority()); - if (member.getAccessControlEntry().getContext() != null) - { - SimpleAccessControlEntryContext context = new SimpleAccessControlEntryContext(); - context.setClassContext(member.getAccessControlEntry().getContext().getClassContext()); - context.setKVPContext(member.getAccessControlEntry().getContext().getKvpContext()); - context.setPropertyContext(member.getAccessControlEntry().getContext().getPropertyContext()); - entry.setContext(context); - } - DbPermission perm = member.getAccessControlEntry().getPermission(); - QName permTypeQName = qnameDAO.getQName(perm.getTypeQNameId()).getSecond(); // Has an ID so must exist - SimplePermissionReference permissionRefernce = SimplePermissionReference.getPermissionReference(permTypeQName, perm.getName()); - entry.setPermission(permissionRefernce); - entry.setPosition(Integer.valueOf(0)); - - setAccessControlEntry(id, entry); - } - } - DirtySessionMethodInterceptor.flushSession(getSession(), true); - return changes; - - } - - private static final String RESOURCE_KEY_ACL_CHANGE_SET_ID = "hibernate.acl.change.set.id"; - - /** - * Support to get the current ACL change set and bind this to the transaction. So we only make one new version of an - * ACL per change set. If something is in the current change set we can update it. - */ - private DbAccessControlListChangeSet getCurrentChangeSet() - { - DbAccessControlListChangeSet changeSet = null; - Serializable changeSetId = (Serializable) AlfrescoTransactionSupport.getResource(RESOURCE_KEY_ACL_CHANGE_SET_ID); - if (changeSetId == null) - { - changeSet = new DbAccessControlListChangeSetImpl(); - changeSetId = getHibernateTemplate().save(changeSet); - DirtySessionMethodInterceptor.flushSession(getSession(), true); - changeSet = (DbAccessControlListChangeSetImpl) getHibernateTemplate().get(DbAccessControlListChangeSetImpl.class, changeSetId); - // bind the id - AlfrescoTransactionSupport.bindResource(RESOURCE_KEY_ACL_CHANGE_SET_ID, changeSetId); - if (logger.isDebugEnabled()) - { - logger.debug("New change set = " + changeSetId); - } - } - else - { - changeSet = (DbAccessControlListChangeSet) getHibernateTemplate().get(DbAccessControlListChangeSetImpl.class, changeSetId); - if (logger.isDebugEnabled()) - { - logger.debug("Existing change set = " + changeSetId); - } - } - return changeSet; - } - - private static class AcePatternMatcher - { - private List patterns; - - AcePatternMatcher(List patterns) - { - this.patterns = patterns; - } - - boolean matches(QNameDAO qnameDAO, Map result, int position) - { - if (patterns == null) - { - return true; - } - - DbAccessControlListMember member = (DbAccessControlListMember) result.get("member"); - DbAccessControlEntry entry = (DbAccessControlEntry) result.get("ace"); - - for (AccessControlEntry pattern : patterns) - { - if (checkPattern(qnameDAO, result, position, member, entry, pattern)) - { - return true; - } - } - return false; - - } - - /** - * @param qnameDAO - * @param result - * @param position - * @param member - * @param entry - * @return - */ - private boolean checkPattern(QNameDAO qnameDAO, Map result, int position, DbAccessControlListMember member, DbAccessControlEntry entry, - AccessControlEntry pattern) - { - if (pattern.getAccessStatus() != null) - { - if (pattern.getAccessStatus() != (entry.isAllowed() ? AccessStatus.ALLOWED : AccessStatus.DENIED)) - { - return false; - } - } - - if (pattern.getAceType() != null) - { - if (pattern.getAceType() != entry.getAceType()) - { - return false; - } - } - - if (pattern.getAuthority() != null) - { - DbAuthority authority = (DbAuthority) result.get("authority"); - if ((pattern.getAuthorityType() != AuthorityType.WILDCARD) && !pattern.getAuthority().equals(authority.getAuthority())) - { - return false; - } - } - - if (pattern.getContext() != null) - { - throw new IllegalArgumentException("Context not yet supported"); - } - - if (pattern.getPermission() != null) - { - DbPermission permission = (DbPermission) result.get("permission"); - final QName patternQName = pattern.getPermission().getQName(); - final QName permTypeQName = qnameDAO.getQName(permission.getTypeQNameId()).getSecond(); // Has an ID so - // must exist - if ((patternQName != null) && (!patternQName.equals(permTypeQName))) - { - return false; - } - final String patternName = pattern.getPermission().getName(); - if ((patternName != null) && (!patternName.equals(permission.getName()))) - { - return false; - } - } - - if (pattern.getPosition() != null) - { - if (pattern.getPosition().intValue() >= 0) - { - if (member.getPosition() != position) - { - return false; - } - } - else if (pattern.getPosition().intValue() == -1) - { - if (member.getPosition() <= position) - { - return false; - } - } - - } - return true; - } - } - - /** - * 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(); - } - - /** - * NO-OP - */ - public void beforeCommit() - { - } - - static class AclChangeImpl implements AclChange - { - private Long before; - - private Long after; - - private ACLType typeBefore; - - private ACLType typeAfter; - - AclChangeImpl(Long before, Long after, ACLType typeBefore, ACLType typeAfter) - { - this.before = before; - this.after = after; - this.typeAfter = typeAfter; - this.typeBefore = typeBefore; - } - - public Long getAfter() - { - return after; - } - - public Long getBefore() - { - return before; - } - - /** - * @param after - */ - public void setAfter(Long after) - { - this.after = after; - } - - /** - * @param before - */ - public void setBefore(Long before) - { - this.before = before; - } - - public ACLType getTypeAfter() - { - return typeAfter; - } - - /** - * @param typeAfter - */ - public void setTypeAfter(ACLType typeAfter) - { - this.typeAfter = typeAfter; - } - - public ACLType getTypeBefore() - { - return typeBefore; - } - - /** - * @param typeBefore - */ - public void setTypeBefore(ACLType typeBefore) - { - this.typeBefore = typeBefore; - } - - @Override - public String toString() - { - StringBuilder builder = new StringBuilder(); - builder.append("(").append(getBefore()).append(",").append(getTypeBefore()).append(")"); - builder.append(" - > "); - builder.append("(").append(getAfter()).append(",").append(getTypeAfter()).append(")"); - return builder.toString(); - } - - } - - /** - * Get the total number of head nodes in the repository - * - * @return count - */ - public Long getAVMHeadNodeCount() - { - try - { - Session session = getSession(); - int isolationLevel = session.connection().getTransactionIsolation(); - try - { - session.connection().setTransactionIsolation(1); - Query query = getSession().getNamedQuery("permission.GetAVMHeadNodeCount"); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - Long answer = (Long) query.uniqueResult(); - return answer; - } - finally - { - session.connection().setTransactionIsolation(isolationLevel); - } - } - catch (SQLException e) - { - throw new AlfrescoRuntimeException("Failed to set TX isolation level", e); - } - - } - - /** - * Get the max acl id - * - * @return - max acl id - */ - public Long getMaxAclId() - { - try - { - Session session = getSession(); - int isolationLevel = session.connection().getTransactionIsolation(); - try - { - session.connection().setTransactionIsolation(1); - Query query = getSession().getNamedQuery("permission.GetMaxAclId"); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - Long answer = (Long) query.uniqueResult(); - return answer; - } - finally - { - session.connection().setTransactionIsolation(isolationLevel); - } - } - catch (SQLException e) - { - throw new AlfrescoRuntimeException("Failed to set TX isolation level", e); - } - } - - /** - * Does the underlyinf connection support isolation level 1 (dirty read) - * - * @return true if we can do a dirty db read and so track changes (Oracle can not) - */ - public boolean supportsProgressTracking() - { - try - { - Session session = getSession(); - return session.connection().getMetaData().supportsTransactionIsolationLevel(1); - } - catch (SQLException e) - { - return false; - } - - } - - /** - * Get the acl count canges so far for progress tracking - * - * @param above - * @return - the count - */ - public Long getAVMNodeCountWithNewACLS(Long above) - { - try - { - Session session = getSession(); - int isolationLevel = session.connection().getTransactionIsolation(); - try - { - session.connection().setTransactionIsolation(1); - Query query = getSession().getNamedQuery("permission.GetAVMHeadNodeCountWherePermissionsHaveChanged"); - query.setParameter("above", above); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - Long answer = (Long) query.uniqueResult(); - return answer; - } - finally - { - session.connection().setTransactionIsolation(isolationLevel); - } - } - catch (SQLException e) - { - throw new AlfrescoRuntimeException("Failed to set TX isolation level", e); - } - } - - /** - * How many nodes are noew in store (approximate) - * - * @return - the number of new nodes - approximate - */ - public Long getNewInStore() - { - Long count = patchDAO.getAVMNodesCountWhereNewInStore(); - return count; - } - - /** - * Find layered directories Used to improve performance during patching and cascading the effect of permission - * changes between layers - * - * @return - layered directories - */ - public List getLayeredDirectories() - { - List ldNodeEntities = avmNodeDAO.getAllLayeredDirectories(); - - ArrayList indirections = new ArrayList(ldNodeEntities.size()); - - for (AVMNodeEntity ldNodeEntity : ldNodeEntities) - { - - Long from = ldNodeEntity.getId(); - String to = ldNodeEntity.getIndirection(); - Integer version = ldNodeEntity.getIndirectionVersion(); - indirections.add(new Indirection(from, to, version)); - } - return indirections; - } - - /** - * Find layered files Used to improve performance during patching and cascading the effect of permission changes - * between layers - * - * @return - layered files - */ - public List getLayeredFiles() - { - List lfNodeEntities = avmNodeDAO.getAllLayeredFiles(); - - ArrayList indirections = new ArrayList(lfNodeEntities.size()); - - for (AVMNodeEntity lfNodeEntity : lfNodeEntities) - { - Long from = lfNodeEntity.getId(); - String to = lfNodeEntity.getIndirection(); - Integer version = lfNodeEntity.getIndirectionVersion(); - indirections.add(new Indirection(from, to, version)); - } - return indirections; - } - - public List getAvmIndirections() - { - List dirList = getLayeredDirectories(); - List fileList = getLayeredFiles(); - ArrayList answer = new ArrayList(dirList.size() + fileList.size()); - answer.addAll(dirList); - answer.addAll(fileList); - return answer; - } - - public void flush() - { - getSession().flush(); - } - - /** - * Support to describe AVM indirections for permission performance improvements when permissions are set. - * - * @author andyh - */ - public static class Indirection - { - Long from; - - String to; - - Integer toVersion; - - Indirection(Long from, String to, Integer toVersion) - { - this.from = from; - this.to = to; - this.toVersion = toVersion; - } - - /** - * @return - from id - */ - public Long getFrom() - { - return from; - } - - /** - * @return - to id - */ - public String getTo() - { - return to; - } - - /** - * @return - version - */ - public Integer getToVersion() - { - return toVersion; - } - - } - - /** - * How many DM nodes are there? - * - * @return - the count - */ - public Long getDmNodeCount() - { - try - { - Session session = getSession(); - int isolationLevel = session.connection().getTransactionIsolation(); - try - { - session.connection().setTransactionIsolation(1); - Query query = getSession().getNamedQuery("permission.GetDmNodeCount"); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - Long answer = (Long) query.uniqueResult(); - return answer; - } - finally - { - session.connection().setTransactionIsolation(isolationLevel); - } - } - catch (SQLException e) - { - throw new AlfrescoRuntimeException("Failed to set TX isolation level", e); - } - - } - - /** - * How many DM nodes are three with new ACls (to track patch progress) - * - * @param above - * @return - the count - */ - public Long getDmNodeCountWithNewACLS(Long above) - { - try - { - Session session = getSession(); - int isolationLevel = session.connection().getTransactionIsolation(); - try - { - session.connection().setTransactionIsolation(1); - Query query = getSession().getNamedQuery("permission.GetDmNodeCountWherePermissionsHaveChanged"); - query.setParameter("above", above); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - Long answer = (Long) query.uniqueResult(); - return answer; - } - finally - { - session.connection().setTransactionIsolation(isolationLevel); - } - } - catch (SQLException e) - { - throw new AlfrescoRuntimeException("Failed to set TX isolation level", e); - } - } - - public void updateAuthority(String before, String after) - { - DbAuthority dbAuthority = getAuthority(before, false); - // If there is no entry and alias is not required - there is nothing it would match - if (dbAuthority != null) - { - dbAuthority.setAuthority(after); - dbAuthority.setCrc(getCrc(after)); - DirtySessionMethodInterceptor.flushSession(getSession(), true); - aclCache.clear(); - } - } - - private DbAuthority getAuthority(final String authority, boolean create) - { - // Find auth - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_AUTHORITY); - query.setParameter("authority", authority); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - - DbAuthority dbAuthority = null; - List authorities = (List) getHibernateTemplate().execute(callback); - for (DbAuthority found : authorities) - { - if (found.getAuthority().equals(authority)) - { - dbAuthority = found; - break; - } - } - if (create && (dbAuthority == null)) - { - dbAuthority = createDbAuthority(authority); - } - return dbAuthority; - } - - private DbPermission getPermission(final PermissionReference permissionReference, boolean create) - { - // Find permission - - final QName permissionQName = permissionReference.getQName(); - final String permissionName = permissionReference.getName(); - final Pair permissionQNamePair = qnameDAO.getOrCreateQName(permissionQName); - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_PERMISSION); - query.setParameter("permissionTypeQNameId", permissionQNamePair.getFirst()); - query.setParameter("permissionName", permissionName); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.uniqueResult(); - } - }; - DbPermission dbPermission = (DbPermission) getHibernateTemplate().execute(callback); - if (create && (dbPermission == null)) - { - DbPermissionImpl newPermission = new DbPermissionImpl(); - newPermission.setTypeQNameId(permissionQNamePair.getFirst()); - newPermission.setName(permissionName); - dbPermission = newPermission; - getHibernateTemplate().save(newPermission); - DirtySessionMethodInterceptor.flushSession(getSession(), true); - } - return dbPermission; - } - - private DbAccessControlEntry getAccessControlEntry(final DbPermission permission, final DbAuthority authority, final AccessControlEntry ace, boolean create) - { - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ACE_WITH_NO_CONTEXT); - query.setParameter("permissionId", permission.getId()); - query.setParameter("authorityId", authority.getId()); - query.setParameter("allowed", (ace.getAccessStatus() == AccessStatus.ALLOWED) ? true : false); - query.setParameter("applies", ace.getAceType().getId()); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.uniqueResult(); - } - }; - DbAccessControlEntry entry = (DbAccessControlEntry) getHibernateTemplate().execute(callback); - if (create && (entry == null)) - { - DbAccessControlEntryImpl newEntry = new DbAccessControlEntryImpl(); - newEntry.setAceType(ace.getAceType()); - newEntry.setAllowed((ace.getAccessStatus() == AccessStatus.ALLOWED) ? true : false); - newEntry.setAuthority(authority); - newEntry.setPermission(permission); - entry = newEntry; - getHibernateTemplate().save(newEntry); - DirtySessionMethodInterceptor.flushSession(getSession(), true); - } - return entry; - } - - public void createAuthority(String authority) - { - createDbAuthority(authority); - } - - public DbAuthority createDbAuthority(String authority) - { - DbAuthority dbAuthority = new DbAuthorityImpl(); - dbAuthority.setAuthority(authority); - dbAuthority.setCrc(getCrc(authority)); - getHibernateTemplate().save(dbAuthority); - DirtySessionMethodInterceptor.flushSession(getSession(), true); - return dbAuthority; - } - - /* - * (non-Javadoc) - * - * @see org.alfresco.repo.security.permissions.impl.AclDaoComponent#setAccessControlEntries(java.lang.Long, - * java.util.List) - */ - public List setAccessControlEntries(Long id, List aces) - { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see org.alfresco.repo.security.permissions.impl.AclDaoComponent#createAccessControlList(org.alfresco.repo.security.permissions.AccessControlListProperties, - * java.util.List, long) - */ - public Long createAccessControlList(AccessControlListProperties properties, List aces, Long inherited) - { - return createAccessControlListImpl(properties, aces, inherited); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.security.permissions.impl.AclDaoComponent#getDefaultProperties() - */ - public SimpleAccessControlListProperties getDefaultProperties() - { - if(useOldPermissions) - { - return OldADMPermissionsDaoComponentImpl.getDefaultProperties(); - } - else - { - return DMPermissionsDaoComponentImpl.getDefaultProperties(); - } - } - - /** - * @param permissionsDaoComponent the permissionsDaoComponent to set - */ - public void setUseOldPermissions(boolean useOldPermissions) - { - this.useOldPermissions = useOldPermissions; - } - - -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/DMAccessControlListDAO.java b/source/java/org/alfresco/repo/domain/hibernate/DMAccessControlListDAO.java deleted file mode 100644 index 531fb57ad8..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/DMAccessControlListDAO.java +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.alfresco.repo.domain.AccessControlListDAO; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.hibernate.AVMAccessControlListDAO.CounterSet; -import org.alfresco.repo.node.db.NodeDaoService; -import org.alfresco.repo.security.permissions.ACLType; -import org.alfresco.repo.security.permissions.AccessControlEntry; -import org.alfresco.repo.security.permissions.AccessControlList; -import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties; -import org.alfresco.repo.security.permissions.impl.AclChange; -import org.alfresco.repo.security.permissions.impl.AclDaoComponent; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; -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.QNamePattern; -import org.alfresco.service.namespace.RegexQNamePattern; -import org.alfresco.util.Pair; - -/** - * DAO layer for the improved ACL implemtentation. This layer is responsible for setting ACLs and any cascade behaviour - * required. It also implements the migration from the old implementation to the new. - * - * @author andyh - */ -public class DMAccessControlListDAO implements AccessControlListDAO -{ - /** - * The DAO for Nodes. - */ - private NodeDaoService nodeDaoService; - - private NodeService nodeService; - - private AclDaoComponent aclDaoComponent; - - private HibernateSessionHelper hibernateSessionHelper; - - /** - * Set the node dao service - * - * @param nodeDaoService - */ - public void setNodeDaoService(NodeDaoService nodeDaoService) - { - this.nodeDaoService = nodeDaoService; - } - - /** - * Set the ACL DAO components - * - * @param aclDaoComponent - */ - public void setAclDaoComponent(AclDaoComponent aclDaoComponent) - { - this.aclDaoComponent = aclDaoComponent; - } - - /** - * Set the hibernate session helper for session size management - * - * @param hibernateSessionHelper - */ - public void setHibernateSessionHelper(HibernateSessionHelper hibernateSessionHelper) - { - this.hibernateSessionHelper = hibernateSessionHelper; - } - - /** - * Set the node service. - * - * @param nodeService - */ - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - public void forceCopy(NodeRef nodeRef) - { - // Nothing to do - } - - private Node getNodeNotNull(NodeRef nodeRef) - { - Pair nodePair = nodeDaoService.getNodePair(nodeRef); - if (nodePair == null) - { - throw new InvalidNodeRefException(nodeRef); - } - Node node = (Node) hibernateSessionHelper.getHibernateTemplate().get(NodeImpl.class, nodePair.getFirst()); - return node; - } - - public DbAccessControlList getAccessControlList(NodeRef nodeRef) - { - Node node = getNodeNotNull(nodeRef); - return node.getAccessControlList(); - } - - public DbAccessControlList getAccessControlList(StoreRef storeRef) - { - return null; - } - - public Long getIndirectAcl(NodeRef nodeRef) - { - return getAccessControlList(nodeRef).getId(); - } - - public Long getInheritedAcl(NodeRef nodeRef) - { - Pair nodePair = nodeDaoService.getNodePair(nodeRef); - if (nodePair == null) - { - return null; - } - Pair parentAssocRefPair = nodeDaoService.getPrimaryParentAssoc(nodePair.getFirst()); - if (parentAssocRefPair == null || parentAssocRefPair.getSecond().getParentRef() == null) - { - return null; - } - DbAccessControlList acl = getAccessControlList(parentAssocRefPair.getSecond().getParentRef()); - if (acl != null) - { - return acl.getId(); - } - else - { - return null; - } - } - - public Map patchAcls() - { - CounterSet result = new CounterSet(); - List stores = nodeService.getStores(); - - for (StoreRef store : stores) - { - if (!store.getProtocol().equals(StoreRef.PROTOCOL_AVM)) - { - CounterSet update; - update = fixOldDmAcls(nodeService.getRootNode(store), null, true); - result.add(update); - } - } - - HashMap toReturn = new HashMap(); - toReturn.put(ACLType.DEFINING, Integer.valueOf(result.get(ACLType.DEFINING).getCounter())); - toReturn.put(ACLType.FIXED, Integer.valueOf(result.get(ACLType.FIXED).getCounter())); - toReturn.put(ACLType.GLOBAL, Integer.valueOf(result.get(ACLType.GLOBAL).getCounter())); - toReturn.put(ACLType.LAYERED, Integer.valueOf(result.get(ACLType.LAYERED).getCounter())); - toReturn.put(ACLType.OLD, Integer.valueOf(result.get(ACLType.OLD).getCounter())); - toReturn.put(ACLType.SHARED, Integer.valueOf(result.get(ACLType.SHARED).getCounter())); - return toReturn; - } - - private CounterSet fixOldDmAcls(NodeRef nodeRef, Long inherited, boolean isRoot) - { - hibernateSessionHelper.mark(); - try - { - return fixOldDmAclsImpl(nodeRef, inherited, isRoot); - } - finally - { - hibernateSessionHelper.resetAndRemoveMark(); - } - } - - private CounterSet fixOldDmAclsImpl(NodeRef nodeRef, Long inherited, boolean isRoot) - { - CounterSet result = new CounterSet(); - // Do the children first - - DbAccessControlList existingAcl = getAccessControlList(nodeRef); - Long toInherit = null; - Long idToInheritFrom = null; - - if (existingAcl != null) - { - if (existingAcl.getAclType() == ACLType.OLD) - { - result.increment(ACLType.DEFINING); - SimpleAccessControlListProperties properties = aclDaoComponent.getDefaultProperties(); - properties.setInherits(existingAcl.getInherits()); - AccessControlList existing = aclDaoComponent.getAccessControlList(existingAcl.getId()); - Long actuallyInherited = null; - if (existingAcl.getInherits()) - { - if (inherited != null) - { - actuallyInherited = inherited; - } - } - Long id = aclDaoComponent.createAccessControlList(properties, existing.getEntries(), actuallyInherited); - - DbAccessControlList newAcl = aclDaoComponent.getDbAccessControlList(id); - - idToInheritFrom = id; - - setAccessControlList(nodeRef, newAcl); - } - else - { - // Already fixed up - return result; - } - } - else - { - // Set default ACL on roots with no settings - if (isRoot) - { - result.increment(ACLType.DEFINING); - SimpleAccessControlListProperties properties = aclDaoComponent.getDefaultProperties(); - Long id = aclDaoComponent.createAccessControlList(properties); - - DbAccessControlList newAcl = aclDaoComponent.getDbAccessControlList(id); - - idToInheritFrom = id; - - setAccessControlList(nodeRef, newAcl); - } - else - { - // Unset - simple inherit - DbAccessControlList inheritedAcl = aclDaoComponent.getDbAccessControlList(inherited); - setAccessControlList(nodeRef, inheritedAcl); - } - } - - List children = nodeService.getChildAssocs(nodeRef, RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL, false); - if (children.size() > 0) - { - hibernateSessionHelper.reset(); - - // Only make inherited if required - if (toInherit == null) - { - if (idToInheritFrom == null) - { - toInherit = inherited; - } - else - { - toInherit = aclDaoComponent.getInheritedAccessControlList(idToInheritFrom); - } - } - - } - for (ChildAssociationRef child : children) - { - - if (child.isPrimary()) - { - CounterSet update = fixOldDmAcls(child.getChildRef(), toInherit, false); - result.add(update); - } - } - - return result; - } - - public void setAccessControlList(NodeRef nodeRef, Long aclId) - { - Node node = getNodeNotNull(nodeRef); - DbAccessControlList acl = aclDaoComponent.getDbAccessControlList(aclId); - if (acl == null) - { - throw new IllegalArgumentException("The ACL ID provided is invalid: " + aclId); - } - node.setAccessControlList(acl); - } - - public void setAccessControlList(NodeRef nodeRef, DbAccessControlList acl) - { - Node node = getNodeNotNull(nodeRef); - node.setAccessControlList(acl); - } - - public void setAccessControlList(StoreRef storeRef, DbAccessControlList acl) - { - throw new UnsupportedOperationException(); - } - - public List setInheritanceForChildren(NodeRef parent, Long inheritFrom) - { - List changes = new ArrayList(); - setFixedAcls(parent, inheritFrom, null, changes, false); - return changes; - } - - public void updateChangedAcls(NodeRef startingPoint, List changes) - { - // Nothing to do: no nodes change as a result of ACL changes - } - - /** - * Support to set a shared ACL on a node and all of its children - * - * @param nodeRef - * the parent node - * @param inheritFrom - * the parent node's ACL - * @param mergeFrom - * the shared ACL, if already known. If null, will be retrieved / created lazily - * @param changes - * the list in which to record changes - * @param set - * set the shared ACL on the parent ? - */ - public void setFixedAcls(NodeRef nodeRef, Long inheritFrom, Long mergeFrom, List changes, boolean set) - { - if (nodeRef == null) - { - return; - } - else - { - if (set) - { - // Lazily retrieve/create the shared ACL - if (mergeFrom == null) - { - mergeFrom = aclDaoComponent.getInheritedAccessControlList(inheritFrom); - } - setAccessControlList(nodeRef, aclDaoComponent.getDbAccessControlList(mergeFrom)); - } - - List children = nodeService.getChildAssocs(nodeRef, RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL, false); - - for (ChildAssociationRef child : children) - { - if (child.isPrimary()) - { - // Lazily retrieve/create the shared ACL - if (mergeFrom == null) - { - mergeFrom = aclDaoComponent.getInheritedAccessControlList(inheritFrom); - } - - DbAccessControlList acl = getAccessControlList(child.getChildRef()); - - if (acl == null) - { - hibernateSessionHelper.mark(); - try - { - setFixedAcls(child.getChildRef(), inheritFrom, mergeFrom, changes, true); - } - finally - { - hibernateSessionHelper.resetAndRemoveMark(); - } - } - else if (acl.getAclType() == ACLType.LAYERED) - { - throw new UnsupportedOperationException(); - } - else if (acl.getAclType() == ACLType.DEFINING) - { - if (acl.getInherits()) - { - @SuppressWarnings("unused") - List newChanges = aclDaoComponent.mergeInheritedAccessControlList(mergeFrom, acl.getId()); - } - } - else - { - hibernateSessionHelper.mark(); - try - { - setFixedAcls(child.getChildRef(), inheritFrom, mergeFrom, changes, true); - } - finally - { - hibernateSessionHelper.resetAndRemoveMark(); - } - } - } - } - } - } -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlEntryContextImpl.java b/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlEntryContextImpl.java deleted file mode 100644 index 40ccffa1d5..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlEntryContextImpl.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; - -import org.alfresco.repo.domain.DbAccessControlEntryContext; - -public class DbAccessControlEntryContextImpl implements DbAccessControlEntryContext, Serializable -{ - /** - * - */ - private static final long serialVersionUID = -4479587461724827683L; - - private String classContext; - - private String kvpContext; - - private String propertyContext; - - private Long id; - - private Long version; - - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(128); - sb.append("DbAccessControlEntryContextImpl").append("[ id=").append(id).append(", version=").append(version).append(", classContext=").append(classContext).append( - ", kvpContext=").append(kvpContext).append(", propertyContext=").append(propertyContext); - return sb.toString(); - } - - @Override - public int hashCode() - { - final int PRIME = 31; - int result = 1; - result = PRIME * result + ((classContext == null) ? 0 : classContext.hashCode()); - result = PRIME * result + ((kvpContext == null) ? 0 : kvpContext.hashCode()); - result = PRIME * result + ((propertyContext == null) ? 0 : propertyContext.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final DbAccessControlEntryContextImpl other = (DbAccessControlEntryContextImpl) obj; - if (classContext == null) - { - if (other.classContext != null) - return false; - } - else if (!classContext.equals(other.classContext)) - return false; - if (kvpContext == null) - { - if (other.kvpContext != null) - return false; - } - else if (!kvpContext.equals(other.kvpContext)) - return false; - if (propertyContext == null) - { - if (other.propertyContext != null) - return false; - } - else if (!propertyContext.equals(other.propertyContext)) - return false; - return true; - } - - public String getClassContext() - { - return classContext; - } - - public Long getId() - { - return id; - } - - public String getKvpContext() - { - return kvpContext; - } - - public String getPropertyContext() - { - return propertyContext; - } - - public Long getVersion() - { - return version; - } - - public void setClassContext(String classContext) - { - this.classContext = classContext; - } - - public void setKvpContext(String kvpContext) - { - this.kvpContext = kvpContext; - - } - - public void setPropertyContext(String propertyContext) - { - this.propertyContext = propertyContext; - - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setId(Long id) - { - this.id = id; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setVersion(Long version) - { - this.version = version; - } - -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlEntryImpl.java b/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlEntryImpl.java deleted file mode 100644 index 5070ca2446..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlEntryImpl.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; - -import org.alfresco.repo.domain.DbAccessControlEntry; -import org.alfresco.repo.domain.DbAccessControlEntryContext; -import org.alfresco.repo.domain.DbAuthority; -import org.alfresco.repo.domain.DbPermission; -import org.alfresco.repo.domain.DbPermissionKey; -import org.alfresco.repo.security.permissions.ACEType; -import org.hibernate.Session; - -/** - * Persisted permission entries - * - * @author andyh - */ -public class DbAccessControlEntryImpl implements DbAccessControlEntry, Serializable -{ - private static final long serialVersionUID = -418837862334064582L; - - private Long id; - - private Long version; - - /** The permission to which this applies (non null - all is a special string) */ - private DbPermission permission; - - /** The recipient to which this applies (non null - all is a special string) */ - private DbAuthority authority; - - /** Is this permission allowed? */ - private boolean allowed; - - private int aceType; - - private DbAccessControlEntryContext context; - - public DbAccessControlEntryImpl() - { - super(); - } - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(128); - sb.append("DbAccessControlEntryImpl") - .append("[ id=").append(id) - .append(", version=").append(version) - .append(", permission=").append(permission.getKey()) - .append(", authority=").append(authority.getAuthority()) - .append(", allowed=").append(allowed) - .append(", aceType=").append(ACEType.getACETypeFromId(aceType)) - .append(", context=").append(context) - .append("]"); - return sb.toString(); - } - - @Override - public int hashCode() - { - final int PRIME = 31; - int result = 1; - result = PRIME * result + aceType; - result = PRIME * result + (allowed ? 1231 : 1237); - result = PRIME * result + ((authority == null) ? 0 : authority.hashCode()); - result = PRIME * result + ((context == null) ? 0 : context.hashCode()); - result = PRIME * result + ((permission == null) ? 0 : permission.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final DbAccessControlEntryImpl other = (DbAccessControlEntryImpl) obj; - if (aceType != other.aceType) - return false; - if (allowed != other.allowed) - return false; - if (authority == null) - { - if (other.authority != null) - return false; - } - else if (!authority.equals(other.authority)) - return false; - if (context == null) - { - if (other.context != null) - return false; - } - else if (!context.equals(other.context)) - return false; - if (permission == null) - { - if (other.permission != null) - return false; - } - else if (!permission.equals(other.permission)) - return false; - return true; - } - - - public Long getId() - { - return id; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setId(Long id) - { - this.id = id; - } - - public Long getVersion() - { - return version; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setVersion(Long version) - { - this.version = version; - } - - public DbPermission getPermission() - { - return permission; - } - - public void setPermission(DbPermission permissionReference) - { - this.permission = permissionReference; - } - - public DbAuthority getAuthority() - { - return authority; - } - - public void setAuthority(DbAuthority recipient) - { - this.authority = recipient; - } - - public boolean isAllowed() - { - return allowed; - } - - public void setAllowed(boolean allowed) - { - this.allowed = allowed; - } - - public ACEType getAceType() - { - return ACEType.getACETypeFromId(aceType); - } - - public void setAceType(ACEType aceType) - { - this.aceType = aceType.getId(); - } - - - @SuppressWarnings("unused") - private void setApplies(int applies) - { - this.aceType = applies; - } - - @SuppressWarnings("unused") - private int getApplies() - { - return aceType; - } - - - public DbAccessControlEntryContext getContext() - { - return context; - } - - public void setContext(DbAccessControlEntryContext context) - { - this.context = context; - } - - public void delete() - { - throw new UnsupportedOperationException("TODO"); - } - - - - public static DbAccessControlEntry find(Session session, ACEType type, boolean allow, String authority, DbPermissionKey permissionKey) - { - // Query query = session - // .getNamedQuery(PermissionsDaoComponentImpl.QUERY_GET_PERMISSION) - // .setString("permissionTypeQName", qname.toString()) - // .setString("permissionName", name); - // return (DbPermission) query.uniqueResult(); - throw new UnsupportedOperationException("TODO"); - } -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListChangeSetImpl.java b/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListChangeSetImpl.java deleted file mode 100644 index b3f2acefdb..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListChangeSetImpl.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; - -import org.alfresco.repo.domain.DbAccessControlListChangeSet; - -public class DbAccessControlListChangeSetImpl implements DbAccessControlListChangeSet, Serializable -{ - /** - * - */ - private static final long serialVersionUID = 3433168181194696611L; - private Long id; - private Long version; - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(128); - sb.append("DBAccessControlListChangeSetImpl") - .append("[ id=").append(id) - .append(", version=").append(version) - .append("]"); - return sb.toString(); - } - - - - public Long getId() - { - return id; - } - - public Long getVersion() - { - return version; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setId(Long id) - { - this.id = id; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setVersion(Long version) - { - this.version = version; - } - -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListImpl.java b/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListImpl.java deleted file mode 100644 index 375eac0b32..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListImpl.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.alfresco.repo.domain.DbAccessControlEntry; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.DbAccessControlListChangeSet; -import org.alfresco.repo.domain.DbAccessControlListMember; -import org.alfresco.repo.domain.DbAuthority; -import org.alfresco.repo.domain.DbPermission; -import org.alfresco.repo.domain.DbPermissionKey; -import org.alfresco.repo.security.permissions.ACLCopyMode; -import org.alfresco.repo.security.permissions.ACLType; -import org.alfresco.repo.security.permissions.AccessControlEntry; -import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties; -import org.alfresco.repo.security.permissions.impl.AclDaoComponent; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.CallbackException; -import org.hibernate.Query; -import org.hibernate.Session; -import org.springframework.orm.hibernate3.HibernateCallback; - -/** - * The hibernate persisted class for node permission entries. - * - * @author andyh - */ -public class DbAccessControlListImpl extends LifecycleAdapter implements DbAccessControlList, Serializable -{ - private static AclDaoComponent s_aclDaoComponent; - - private static final long serialVersionUID = 3123277428227075648L; - - private static Log logger = LogFactory.getLog(DbAccessControlListImpl.class); - - private Long id; - - private Long version; - - private String aclId; - - private long aclVersion; - - private boolean latest; - - private boolean inherits; - - private int aclType; - - private Long inheritedAclId; - - private boolean versioned; - - private DbAccessControlListChangeSet aclChangeSet; - - private Long inheritsFrom; - - private boolean requiresVersion; - - public static void setAclDaoComponent(AclDaoComponent aclDaoComponent) - { - s_aclDaoComponent = aclDaoComponent; - } - - public DbAccessControlListImpl() - { - } - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(128); - sb.append("DbAccessControlListImpl").append("[ id=").append(id).append(", version=").append(version).append(", aclId=").append(aclId).append(", aclVersion=").append( - aclVersion).append(", latest=").append(latest).append(", inherits=").append(inherits).append(", aclType=").append(ACLType.getACLTypeFromId(aclType)).append( - ", inheritedAclId=").append(inheritedAclId).append(", versioned=").append(versioned).append(", changesetId=").append(aclChangeSet).append(", inheritsFrom=") - .append(inheritsFrom).append(", requiresVersion=").append(requiresVersion).append("]"); - return sb.toString(); - } - - - - /** - * Support cascade delete of ACLs from DM nodes (which cascade delete the ACL) - */ - @Override - public boolean onDelete(Session session) throws CallbackException - { - s_aclDaoComponent.onDeleteAccessControlList(id); - return super.onDelete(session); - } - - public Long getId() - { - return id; - } - - /** - * Hibernate use - */ - @SuppressWarnings("unused") - private void setId(Long id) - { - this.id = id; - } - - public Long getVersion() - { - return version; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setVersion(Long version) - { - this.version = version; - } - - public boolean getInherits() - { - return inherits; - } - - public void setInherits(boolean inherits) - { - this.inherits = inherits; - } - - public String getAclId() - { - return aclId; - } - - public void setAclId(String aclId) - { - this.aclId = aclId; - } - - public ACLType getAclType() - { - return ACLType.getACLTypeFromId(aclType); - } - - public void setAclType(ACLType aclType) - { - this.aclType = aclType.getId(); - } - - /** - * Hibernate - */ - - private int getType() - { - return aclType; - } - - private void setType(int aclType) - { - this.aclType = aclType; - } - - public long getAclVersion() - { - return aclVersion; - } - - public void setAclVersion(long aclVersion) - { - this.aclVersion = aclVersion; - } - - public Long getInheritedAclId() - { - return inheritedAclId; - } - - public void setInheritedAclId(Long inheritedAclId) - { - this.inheritedAclId = inheritedAclId; - } - - public boolean isLatest() - { - return latest; - } - - public void setLatest(boolean latest) - { - this.latest = latest; - } - - public boolean isVersioned() - { - return versioned; - } - - public void setVersioned(boolean versioned) - { - this.versioned = versioned; - } - - public DbAccessControlListChangeSet getAclChangeSet() - { - return aclChangeSet; - } - - public void setAclChangeSet(DbAccessControlListChangeSet aclChangeSet) - { - this.aclChangeSet = aclChangeSet; - } - - public static DbAccessControlList find(Session session) - { - // TODO: Needs to use a query - throw new UnsupportedOperationException("TODO"); - } - - public Long getInheritsFrom() - { - return inheritsFrom; - } - - public void setInheritsFrom(Long id) - { - this.inheritsFrom = id; - } - - public DbAccessControlList getCopy(Long parentAcl, ACLCopyMode mode) - { - return s_aclDaoComponent.getDbAccessControlListCopy(this.getId(), parentAcl, mode); - } - - public static DbAccessControlList createLayeredAcl(Long indirectedAcl) - { - SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); - properties.setAclType(ACLType.LAYERED); - Long id = s_aclDaoComponent.createAccessControlList(properties); - if (indirectedAcl != null) - { - s_aclDaoComponent.mergeInheritedAccessControlList(indirectedAcl, id); - } - return s_aclDaoComponent.getDbAccessControlList(id); - } - - public boolean getRequiresVersion() - { - return requiresVersion; - } - - public void setRequiresVersion(boolean requiresVersion) - { - this.requiresVersion = requiresVersion; - } - -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListMemberImpl.java b/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListMemberImpl.java deleted file mode 100644 index 65e7a4ebf5..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListMemberImpl.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; - -import org.alfresco.repo.domain.DbAccessControlEntry; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.DbAccessControlListMember; -import org.hibernate.Session; - -/** - * Hibernate support to store acl-acxe entries - */ -public class DbAccessControlListMemberImpl implements DbAccessControlListMember, Serializable -{ - /** - * - */ - private static final long serialVersionUID = 1L; - - private Long id; - - private Long version; - - private DbAccessControlList acl; - - private DbAccessControlEntry ace; - - private int position; - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(128); - sb.append("DbAccessControlListMemberImpl").append("[ id=").append(id).append(", version=").append(version).append(", acl=").append(acl).append(", ace=").append(ace) - .append(", position=").append(position).append("]"); - return sb.toString(); - } - - @Override - public int hashCode() - { - final int PRIME = 31; - int result = 1; - result = PRIME * result + ((ace == null) ? 0 : ace.hashCode()); - result = PRIME * result + ((acl == null) ? 0 : acl.hashCode()); - result = PRIME * result + position; - return result; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final DbAccessControlListMemberImpl other = (DbAccessControlListMemberImpl) obj; - if (ace == null) - { - if (other.ace != null) - return false; - } - else if (!ace.equals(other.ace)) - return false; - if (acl == null) - { - if (other.acl != null) - return false; - } - else if (!acl.equals(other.acl)) - return false; - if (position != other.position) - return false; - return true; - } - - public DbAccessControlEntry getAccessControlEntry() - { - return ace; - } - - public DbAccessControlList getAccessControlList() - { - return acl; - } - - public Long getId() - { - return id; - } - - public int getPosition() - { - return position; - } - - public Long getVersion() - { - return version; - } - - public void setAccessControlEntry(DbAccessControlEntry ace) - { - this.ace = ace; - } - - public void setAccessControlList(DbAccessControlList acl) - { - this.acl = acl; - } - - public void setPosition(int position) - { - this.position = position; - } - - @SuppressWarnings("unused") - private void setId(Long id) - { - this.id = id; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setVersion(Long version) - { - this.version = version; - } - - /** - * - * @param session - * @param acl => can be null - implies all entries that match ace - * @param ace => can be null - implies all entries that match acl - * @param position => -1 is all positions - * - * Note: both acl and ace may not be null; - * - * @return - */ - public static DbAccessControlListMember find(Session session, DbAccessControlList acl, DbAccessControlEntry ace, int position) - { - // TODO: Needs to use a query - throw new UnsupportedOperationException("TODO"); - } - -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/DbAuthorityAliasImpl.java b/source/java/org/alfresco/repo/domain/hibernate/DbAuthorityAliasImpl.java deleted file mode 100644 index 4bbe2c8f59..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/DbAuthorityAliasImpl.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; - -import org.alfresco.repo.domain.DbAuthority; -import org.alfresco.repo.domain.DbAuthorityAlias; -import org.hibernate.Session; - -public class DbAuthorityAliasImpl implements DbAuthorityAlias, Serializable -{ - /** - * - */ - private static final long serialVersionUID = -774180120537804154L; - private Long id; - private Long version; - private DbAuthority authority; - private DbAuthority alias; - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(128); - sb.append("DbAuthorityAliasImpl") - .append("[ id=").append(id) - .append(", version=").append(version) - .append(", authority=").append(authority) - .append(", alias=").append(alias) - .append("]"); - return sb.toString(); - } - - @Override - public int hashCode() - { - final int PRIME = 31; - int result = 1; - result = PRIME * result + ((alias == null) ? 0 : alias.hashCode()); - result = PRIME * result + ((authority == null) ? 0 : authority.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final DbAuthorityAliasImpl other = (DbAuthorityAliasImpl) obj; - if (alias == null) - { - if (other.alias != null) - return false; - } - else if (!alias.equals(other.alias)) - return false; - if (authority == null) - { - if (other.authority != null) - return false; - } - else if (!authority.equals(other.authority)) - return false; - return true; - } - - public DbAuthority getAlias() - { - return alias; - } - - public DbAuthority getAuthority() - { - return authority; - } - - public Long getId() - { - return id; - } - - public Long getVersion() - { - return version; - } - - public void setAlias(DbAuthority alias) - { - this.alias = alias; - } - - public void setAuthority(DbAuthority authority) - { - this.authority = authority; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setId(Long id) - { - this.id = id; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setVersion(Long version) - { - this.version = version; - } - - - /** - * Helper method to find an authority alias based on the authority and alias - * - * @param session the Hibernate session to use - * @param authority the authority name - * @return Returns an existing instance or null if not found - */ - public static DbAuthorityAlias find(Session session, String authority, String alias) - { - // TODO: Needs to use a query - throw new UnsupportedOperationException("TODO"); - } -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/DbAuthorityImpl.java b/source/java/org/alfresco/repo/domain/hibernate/DbAuthorityImpl.java deleted file mode 100644 index c0ac5544cc..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/DbAuthorityImpl.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; - -import org.alfresco.repo.domain.DbAuthority; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.Session; - -/** - * The persisted class for authorities. - * - * @author andyh - */ -public class DbAuthorityImpl implements DbAuthority, Serializable -{ - private static final long serialVersionUID = -5582068692208928127L; - - private static Log logger = LogFactory.getLog(DbAuthorityImpl.class); - - private Long id; - - private Long version; - - private String authority; - - private Long crc; - - public DbAuthorityImpl() - { - } - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(128); - sb.append("DbAuthorityImpl").append("[ id=").append(id).append(", version=").append(version).append(", authority=").append(authority).append("]"); - return sb.toString(); - } - - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (!(o instanceof DbAuthority)) - { - return false; - } - DbAuthority other = (DbAuthority) o; - return this.getAuthority().equals(other.getAuthority()); - } - - @Override - public int hashCode() - { - return getAuthority().hashCode(); - } - - public Long getId() - { - return id; - } - - @SuppressWarnings("unused") - private void setId(Long id) - { - this.id = id; - } - - @SuppressWarnings("unused") - public void setCrc(Long crc) - { - this.crc = crc; - } - - public Long getVersion() - { - return version; - } - - public Long getCrc() - { - return crc; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setVersion(Long version) - { - this.version = version; - } - - public String getAuthority() - { - return authority; - } - - public void setAuthority(String authority) - { - this.authority = authority; - } - - /** - * Helper method to find an authority based on its natural key - * - * @param session - * the Hibernate session to use - * @param authority - * the authority name - * @return Returns an existing instance or null if not found - */ - public static DbAuthority find(Session session, String authority) - { - // TODO: Needs to use a query - throw new UnsupportedOperationException("TODO"); - } -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/DbPermissionImpl.java b/source/java/org/alfresco/repo/domain/hibernate/DbPermissionImpl.java deleted file mode 100644 index a4d720a4d1..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/DbPermissionImpl.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; - -import org.alfresco.repo.domain.DbPermission; -import org.alfresco.repo.domain.DbPermissionKey; -import org.alfresco.repo.domain.qname.QNameDAO; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.EqualsHelper; -import org.hibernate.Session; - -/** - * The persisted class for permissions. - * - * @author andyh - */ -public class DbPermissionImpl implements DbPermission, Serializable -{ - private static final long serialVersionUID = -6352566900815035461L; - - private Long id; - private Long version; - private Long typeQNameId; - private String name; - - private transient ReadLock refReadLock; - private transient WriteLock refWriteLock; - private transient QName typeQName; - - public DbPermissionImpl() - { - super(); - ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - refReadLock = lock.readLock(); - refWriteLock = lock.writeLock(); - } - - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(128); - sb.append("DbPermissionImpl") - .append("[ id=").append(id) - .append(", version=").append(version) - .append(", typeQName=").append(typeQNameId) - .append(", name=").append(getName()) - .append("]"); - return sb.toString(); - } - - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (!(o instanceof DbPermission)) - { - return false; - } - DbPermission other = (DbPermission) o; - return (EqualsHelper.nullSafeEquals(typeQNameId, other.getTypeQNameId())) - && (EqualsHelper.nullSafeEquals(name, other.getName()) - ); - } - - @Override - public int hashCode() - { - return typeQNameId.hashCode() + (37 * name.hashCode()); - } - - public QName getTypeQName(QNameDAO qnameDAO) - { - refReadLock.lock(); - try - { - if (typeQName != null) - { - return typeQName; - } - } - finally - { - refReadLock.unlock(); - } - refWriteLock.lock(); - try - { - typeQName = qnameDAO.getQName(typeQNameId).getSecond(); - return typeQName; - } - finally - { - refWriteLock.unlock(); - } - } - - public Long getId() - { - return id; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setId(Long id) - { - this.id = id; - } - - public Long getVersion() - { - return version; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setVersion(Long version) - { - this.version = version; - } - - public Long getTypeQNameId() - { - return typeQNameId; - } - - public void setTypeQNameId(Long typeQNameId) - { - refWriteLock.lock(); - try - { - this.typeQNameId = typeQNameId; - this.typeQName = null; - } - finally - { - refWriteLock.unlock(); - } - } - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - public DbPermissionKey getKey() - { - return new DbPermissionKey(typeQNameId, name); - } - - /** - * Helper method to find a permission based on its natural key - * - * @param session - * the Hibernate session to use - * @param qname - * the type qualified name - * @param name - * the name of the permission - * @return Returns an existing instance or null if not found - */ - public static DbPermission find(Session session, QName qname, String name) - { - // Query query = session - // .getNamedQuery(PermissionsDaoComponentImpl.QUERY_GET_PERMISSION) - // .setString("permissionTypeQName", qname.toString()) - // .setString("permissionName", name); - // return (DbPermission) query.uniqueResult(); - throw new UnsupportedOperationException("TODO"); - } -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateHelper.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateHelper.java deleted file mode 100644 index ccededfc41..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/HibernateHelper.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import org.alfresco.repo.domain.DbAccessControlEntry; -import org.hibernate.Query; -import org.hibernate.ScrollMode; -import org.hibernate.ScrollableResults; -import org.hibernate.Session; - -/** - * Helper methods related to Hibernate - * - * @author Derek Hulley - */ -public class HibernateHelper -{ - /** - * Helper method to scroll through the results of a query and delete all the - * resulting access control entries, performing batch flushes. - * - * @param session the session to use for the deletions - * @param query the query with all parameters set and that will return - * {@link org.alfresco.repo.domain.DbAccessControlEntry access control entry} instances - * @return Returns the number of entries deleted - */ - public static int deleteDbAccessControlEntries(Session session, Query query) - { - ScrollableResults entities = null; - int count = 0; - try - { - entities = query.scroll(ScrollMode.FORWARD_ONLY); - - while (entities.next()) - { - DbAccessControlEntry entry = (DbAccessControlEntry) entities.get(0); - entry.delete(); - if (++count % 50 == 0) - { - session.flush(); - session.clear(); - } - } - } - finally - { - if(entities != null) - { - entities.close(); - } - } - - return count; - } -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateLocaleDAOImpl.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateLocaleDAOImpl.java deleted file mode 100644 index 567f834b16..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/HibernateLocaleDAOImpl.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; -import java.util.Locale; - -import org.springframework.extensions.surf.util.I18NUtil; -import org.alfresco.repo.cache.SimpleCache; -import org.alfresco.repo.domain.LocaleDAO; -import org.alfresco.repo.domain.LocaleEntity; -import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; -import org.alfresco.util.Pair; -import org.springframework.extensions.surf.util.ParameterCheck; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.Query; -import org.hibernate.Session; -import org.springframework.orm.hibernate3.HibernateCallback; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; - -/** - * Hibernate-specific implementation of the Locale DAO interface. - *

- * Since Locales are system-wide and immutable, we can cache lookups in both - * directions. - * - * @author Derek Hulley - * @since 2.2.1 - */ -public class HibernateLocaleDAOImpl extends HibernateDaoSupport implements LocaleDAO -{ - private static Log logger = LogFactory.getLog(HibernateLocaleDAOImpl.class); - - private static final String QUERY_GET_LOCALE_BY_VALUE = "locale.GetLocaleByValue"; - private static final Long CACHE_ID_MISS = Long.valueOf(-1L); - - /** - * A bi-directional cache of LocaleStr->ID and ID->LocaleStr. - */ - private SimpleCache localeIdCache; - - public void setLocaleIdCache(SimpleCache localeIdCache) - { - this.localeIdCache = localeIdCache; - } - - public Pair getLocalePair(Locale locale) - { - ParameterCheck.mandatory("locale", locale); - return getLocalePairImpl(locale); - } - - public Pair getDefaultLocalePair() - { - return getLocalePairImpl(null); - } - - public Pair getLocalePair(Long id) - { - ParameterCheck.mandatory("id", id); - - // First check the cache - String localeStr = (String) localeIdCache.get(id); - if (localeStr == null) - { - // Search for it - LocaleEntity localeEntity = (LocaleEntity) getHibernateTemplate().load(LocaleEntityImpl.class, id); - if (localeEntity == null) - { - throw new IllegalArgumentException("Locale entity ID " + id + " is not valid."); - } - localeStr = localeEntity.getLocaleStr(); - localeIdCache.put(id, localeStr); - localeIdCache.put(localeStr, id); - } - - // Convert the locale string to a locale - Locale locale = DefaultTypeConverter.INSTANCE.convert(Locale.class, localeStr); - Pair localePair = new Pair(id, locale); - // done - return localePair; - } - - public Pair getOrCreateLocalePair(Locale locale) - { - ParameterCheck.mandatory("locale", locale); - - String localeStr = DefaultTypeConverter.INSTANCE.convert(String.class, locale); - Pair localePair = getLocalePairImpl(locale); - if (localePair != null) - { - return localePair; - } - LocaleEntity localeEntity = new LocaleEntityImpl(); - localeEntity.setLocale(locale); - Long id = (Long) getHibernateTemplate().save(localeEntity); - // Add the cache entry - localeIdCache.put(id, localeStr); - localeIdCache.put(localeStr, id); - - // Force a flush - DirtySessionMethodInterceptor.flushSession(getSession(), true); - - // Done - if (logger.isDebugEnabled()) - { - logger.debug("Persisted locale entity: " + localeEntity); - } - return new Pair(id, locale); - } - - public Pair getOrCreateDefaultLocalePair() - { - String localeStr = LocaleEntityImpl.DEFAULT_LOCALE_SUBSTITUTE; - Pair localePair = getDefaultLocalePair(); - if (localePair != null) - { - return localePair; - } - LocaleEntity localeEntity = new LocaleEntityImpl(); - localeEntity.setLocale(null); - Long id = (Long) getHibernateTemplate().save(localeEntity); - // Add the cache entry - localeIdCache.put(id, localeStr); - localeIdCache.put(localeStr, id); - // Done - if (logger.isDebugEnabled()) - { - logger.debug("Persisted locale entity: " + localeEntity); - } - Locale locale = localeEntity.getLocale(); - return new Pair(id, locale); - } - - private Pair getLocalePairImpl(Locale locale) - { - // Null means look for the default - final String localeStr; - if (locale == null) - { - localeStr = LocaleEntityImpl.DEFAULT_LOCALE_SUBSTITUTE; - locale = I18NUtil.getLocale(); - } - else - { - localeStr = DefaultTypeConverter.INSTANCE.convert(String.class, locale); - } - - Pair localePair; - // First see if it is cached - Long id = (Long) localeIdCache.get(localeStr); - if (id == null) - { - // Look it up from the DB - // It's not in the cache, so query - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateLocaleDAOImpl.QUERY_GET_LOCALE_BY_VALUE) - .setString("localeStr", localeStr); - DirtySessionMethodInterceptor.flushSession(session); - return query.uniqueResult(); - } - }; - LocaleEntity entity = (LocaleEntity) getHibernateTemplate().execute(callback); - if (entity != null) - { - id = entity.getId(); - // Add this to the cache - localeIdCache.put(localeStr, id); - localeIdCache.put(id, localeStr); - localePair = new Pair(id, locale); - } - else - { - // We did a search but it is not there - localeIdCache.put(localeStr, HibernateLocaleDAOImpl.CACHE_ID_MISS); - localePair = null; - } - } - else if (id.equals(HibernateLocaleDAOImpl.CACHE_ID_MISS)) - { - // We have searched before and it is not present - localePair = null; - } - else - { - // We have searched before and found something. - localePair = new Pair(id, locale); - } - // Done - return localePair; - } -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/HibernateUsageDeltaDAO.java b/source/java/org/alfresco/repo/domain/hibernate/HibernateUsageDeltaDAO.java deleted file mode 100644 index 691c2a60e6..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/HibernateUsageDeltaDAO.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.UsageDelta; -import org.alfresco.repo.domain.UsageDeltaDAO; -import org.alfresco.repo.node.db.NodeDaoService; -import org.alfresco.repo.transaction.TransactionalDao; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.util.GUID; -import org.alfresco.util.Pair; -import org.springframework.dao.ConcurrencyFailureException; -import org.springframework.extensions.surf.util.ParameterCheck; -import org.hibernate.Query; -import org.hibernate.Session; -import org.springframework.orm.hibernate3.HibernateCallback; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; - -/** - * Hibernate-specific implementation of the persistence-independent Usage Delta DAO interface - * - */ -public class HibernateUsageDeltaDAO extends HibernateDaoSupport implements UsageDeltaDAO, TransactionalDao -{ -// private static final String QUERY_GET_DELTAS = "usage.GetDeltas"; - private static final String QUERY_GET_TOTAL_DELTA_SIZE = "usage.GetTotalDeltaSize"; - private static final String QUERY_GET_USAGE_DELTA_NODES = "usage.GetUsageDeltaNodes"; - private static final String QUERY_DELETE_DELTAS_FOR_NODE = "usage.DeleteUsageDeltasForNode"; - - /** a uuid identifying this unique instance */ - private final String uuid; - private NodeDaoService nodeDaoService; - - public void setNodeDaoService(NodeDaoService nodeDaoService) - { - this.nodeDaoService = nodeDaoService; - } - - /** - * - */ - public HibernateUsageDeltaDAO() - { - this.uuid = GUID.generate(); - } - - /** - * Checks equality by type and uuid - */ - public boolean equals(Object obj) - { - if (obj == null) - { - return false; - } - else if (!(obj instanceof HibernateUsageDeltaDAO)) - { - return false; - } - HibernateUsageDeltaDAO that = (HibernateUsageDeltaDAO) obj; - return this.uuid.equals(that.uuid); - } - - /** - * @see #uuid - */ - public int hashCode() - { - return uuid.hashCode(); - } - - /** - * NO-OP - */ - public void beforeCommit() - { - } - - /** - * 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(); - } - - private Long getNodeIdNotNull(NodeRef nodeRef) throws InvalidNodeRefException - { - ParameterCheck.mandatory("nodeRef", nodeRef); - - Pair nodePair = nodeDaoService.getNodePair(nodeRef); - if (nodePair == null) - { - throw new InvalidNodeRefException("Node does not exist: " + nodeRef, nodeRef); - } - return nodePair.getFirst(); - } - - public int deleteDeltas(NodeRef nodeRef) - { - Long nodeId = getNodeIdNotNull(nodeRef); - return deleteDeltas(nodeId); - } - - @SuppressWarnings("unchecked") - public int deleteDeltas(final Long nodeId) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_DELETE_DELTAS_FOR_NODE); - query.setParameter("nodeId", nodeId); - return query.executeUpdate(); - } - }; - - // execute - Integer delCount = (Integer) getHibernateTemplate().execute(callback); - - return (delCount == null ? 0 : delCount.intValue()); - } - - @SuppressWarnings("unchecked") - private Object[] getTotalDeltaSizeImpl(NodeRef nodeRef) - { - final Long nodeId = getNodeIdNotNull(nodeRef); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_TOTAL_DELTA_SIZE); - query.setParameter("nodeId", nodeId); - query.setReadOnly(true); - return query.uniqueResult(); - } - }; - - // execute read-only tx - return (Object[])getHibernateTemplate().execute(callback); - } - - public long getTotalDeltaSize(NodeRef nodeRef) - { - Object[] result = getTotalDeltaSizeImpl(nodeRef); - Long queryResult = (Long)result[1]; - return (queryResult == null ? 0 : queryResult.longValue()); - } - - /** - * Guard against deleting deltas committed by another transaction after calculating the delta sum above. - * If the expected number of deletes is different from the actual number of deletes then deltas from - * another committed transaction are probably being removed. - */ - @SuppressWarnings("unchecked") - public long getAndRemoveTotalDeltaSize(NodeRef nodeRef) - { - Object[] result = getTotalDeltaSizeImpl(nodeRef); - Long queryResult = (Long)result[1]; - Number deltaCount = (Number)result[0]; - - long expectedNumDeletes = deltaCount == null ? 0 : deltaCount.intValue(); - - int numDeltasRemoved = deleteDeltas(nodeRef); - - if(expectedNumDeletes != numDeltasRemoved) { - throw new ConcurrencyFailureException("More than expected number of usage delta deletes has occurred for node id " - + nodeRef.getId() + " in store " + nodeRef.getStoreRef()); - } - - return (queryResult == null ? 0 : queryResult.longValue()); - } - - public void insertDelta(NodeRef usageNodeRef, long deltaSize) - { - Long nodeId = getNodeIdNotNull(usageNodeRef); - Node node = (Node) getHibernateTemplate().get(NodeImpl.class, nodeId); - - UsageDelta delta = new UsageDeltaImpl(); - // delta properties - delta.setNode(node); - delta.setDeltaSize(deltaSize); - - // Save - getSession().save(delta); - } - - @SuppressWarnings("unchecked") - public Set getUsageDeltaNodes() - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_USAGE_DELTA_NODES); - query.setReadOnly(true); - return query.list(); - } - }; - // execute read-only tx - List queryResults = (List)getHibernateTemplate().execute(callback); - Set results = new HashSet(queryResults.size(), 1.0F); - for (Node node : queryResults) - { - results.add(node.getNodeRef()); - } - return results; - } -} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/hibernate/Locale.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/Locale.hbm.xml deleted file mode 100644 index bdcab5fbf5..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/Locale.hbm.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - select - locale - from - org.alfresco.repo.domain.hibernate.LocaleEntityImpl as locale - where - locale.localeStr = :localeStr - - - diff --git a/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml index 998220a221..f978bcb2d0 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml @@ -13,7 +13,7 @@ dynamic-update="false" dynamic-insert="false" select-before-update="false" - optimistic-lock="version" > + optimistic-lock="none" > @@ -45,7 +45,7 @@ dynamic-insert="false" select-before-update="false" lazy="true" - optimistic-lock="version" > + optimistic-lock="none" > @@ -82,17 +82,8 @@ - - + + - + - + @@ -120,19 +111,6 @@ - - - - - @@ -149,7 +127,7 @@ dynamic-insert="false" dynamic-update="false" lazy="true" - optimistic-lock="version" + optimistic-lock="none" table="alf_child_assoc" > @@ -191,43 +169,6 @@ - - - - - - - - - - - - - - - - - - - - select store @@ -239,25 +180,6 @@ store.identifier = :identifier - - select - store - from - org.alfresco.repo.domain.hibernate.StoreImpl as store - - - - select - node, - acl - from - org.alfresco.repo.domain.hibernate.NodeImpl as node - left outer join node.accessControlList as acl - where - node.store.id = :storeId and - node.uuid = :uuid - - select assoc, @@ -285,44 +207,6 @@ assoc.parent.id = :parentId - - delete - from - org.alfresco.repo.domain.hibernate.NodeAssocImpl as assoc - where - assoc.source.id = :nodeId or - assoc.target.id = :nodeId - - - - select - child.id - from - org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc - join assoc.child as child - where - assoc.parent.id = :parentId - order by - child.id - - - - select - assoc - from - org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc - where - assoc.parent.id = :parentId and - assoc.child.id = :childId and - assoc.typeQNameId = :typeQNameId and - assoc.qnameNamespaceId = :qnameNamespaceId and - assoc.qnameLocalName = :qnameLocalName and - assoc.qnameCrc = :qnameCrc - order by - assoc.index, - assoc.id - - select assoc @@ -335,465 +219,6 @@ assoc.id - - select - assoc - from - org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc - where - assoc.parent.id = :parentId and - assoc.typeQNameId = :typeQNameId and - assoc.childNodeNameCrc = :childNodeNameCrc and - assoc.childNodeName = :childNodeName - order by - assoc.index, - assoc.id - - - - select - assoc.id, - assoc.typeQNameId, - assoc.qnameNamespaceId, - assoc.qnameLocalName, - assoc.qnameCrc, - assoc.childNodeName, - assoc.childNodeNameCrc, - assoc.isPrimary, - assoc.index, - child.id, - store.protocol, - store.identifier, - child.uuid - from - org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc - join assoc.child as child - join child.store as store - where - assoc.parent.id = :parentId and - assoc.typeQNameId = :typeQNameId and - assoc.childNodeNameCrc in (:childNodeNameCrcs) - order by - assoc.index, - assoc.id - - - - select - assoc.id, - assoc.typeQNameId, - assoc.qnameNamespaceId, - assoc.qnameLocalName, - assoc.qnameCrc, - assoc.childNodeName, - assoc.childNodeNameCrc, - assoc.isPrimary, - assoc.index, - child.id, - store.protocol, - store.identifier, - child.uuid - from - org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc - join assoc.child as child - join child.store as store - where - assoc.parent.id = :parentId - order by - assoc.index, - assoc.id - - - - select - assoc.id, - assoc.typeQNameId, - assoc.qnameNamespaceId, - assoc.qnameLocalName, - assoc.qnameCrc, - assoc.childNodeName, - assoc.childNodeNameCrc, - assoc.isPrimary, - assoc.index, - child.id, - store.protocol, - store.identifier, - child.uuid - from - org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc - join assoc.child as child - join child.store as store - where - assoc.parent.id = :parentId and - assoc.qnameNamespaceId = :qnameNamespaceId and - assoc.qnameLocalName = :qnameLocalName and - assoc.qnameCrc = :qnameCrc - order by - assoc.index, - assoc.id - - - - - - - - - - - - - - - - - select - a.id, - a.type_qname_id, - a.qname_ns_id, - a.qname_localname, - a.qname_crc, - a.child_node_name, - a.child_node_name_crc, - a.is_primary, - a.assoc_index, - n.id, - s.protocol, - s.identifier, - n.uuid - from - (select * from alf_child_assoc a where parent_node_id = :parentId and type_qname_id in (:childAssocTypeQNameIds)) a - inner join alf_node n on a.child_node_id=n.id - inner join alf_store s on n.store_id=s.id - order by a.assoc_index, a.id - - - - select - assoc.id, - assoc.typeQNameId, - assoc.qnameNamespaceId, - assoc.qnameLocalName, - assoc.qnameCrc, - assoc.childNodeName, - assoc.childNodeNameCrc, - assoc.isPrimary, - assoc.index, - child.id, - store.protocol, - store.identifier, - child.uuid - from - org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc - join assoc.child as child - join child.store as store - where - assoc.parent.id = :parentId and - assoc.typeQNameId = :typeQNameId and - assoc.qnameNamespaceId = :qnameNamespaceId and - assoc.qnameLocalName = :qnameLocalName and - assoc.qnameCrc = :qnameCrc - order by - assoc.index, - assoc.id - - - - select - assoc.id, - assoc.typeQNameId, - assoc.qnameNamespaceId, - assoc.qnameLocalName, - assoc.qnameCrc, - assoc.childNodeName, - assoc.childNodeNameCrc, - assoc.isPrimary, - assoc.index, - child.id, - store.protocol, - store.identifier, - child.uuid - from - org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc - join assoc.child as child - join child.store as store - where - assoc.parent.id = :parentId and - child.typeQNameId in (:childTypeQNameIds) - order by - assoc.index, - assoc.id - - - - select - assoc.id, - assoc.typeQNameId, - assoc.qnameNamespaceId, - assoc.qnameLocalName, - assoc.qnameCrc, - assoc.childNodeName, - assoc.childNodeNameCrc, - assoc.isPrimary, - assoc.index, - child.id, - store.protocol, - store.identifier, - child.uuid - from - org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc - join assoc.child as child - join child.store as store - where - assoc.parent.id = :parentId and - assoc.isPrimary = true - order by - assoc.index, - assoc.id - - - - select - assoc.id, - assoc.typeQNameId, - assoc.qnameNamespaceId, - assoc.qnameLocalName, - assoc.qnameCrc, - assoc.childNodeName, - assoc.childNodeNameCrc, - assoc.isPrimary, - assoc.index, - child.id, - store.protocol, - store.identifier, - child.uuid - from - org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc - join assoc.parent as parent - join assoc.child as child - join child.store as store - where - assoc.parent.id = :parentId and - assoc.isPrimary = true and - child.store.id != parent.store.id - order by - assoc.index, - assoc.id - - - - - select - parent.id, - parentStore.protocol, - parentStore.identifier, - parent.uuid - from - org.alfresco.repo.domain.hibernate.ChildAssocImpl as assoc - join assoc.parent as parent - join parent.store as parentStore - join assoc.child as child - join child.store as childStore - where - parentStore.id = :parentStoreId and - childStore.id != :parentStoreId and - parent.id > :minNodeId and - assoc.isPrimary = true - order by - parent.id - - - - select - node.id, - node.store.protocol, - node.store.identifier, - node.uuid - from - org.alfresco.repo.domain.hibernate.NodeImpl as node - join node.aspects as aspects - where - node.id > :minNodeId and - aspects.id = :aspectQNameId - order by - node.id - - - - select - assoc - from - org.alfresco.repo.domain.hibernate.NodeAssocImpl as assoc - where - assoc.source.id = :sourceId and - assoc.target.id = :targetId and - assoc.typeQNameId = :assocTypeQNameId - - - - select - assoc - from - org.alfresco.repo.domain.hibernate.NodeAssocImpl as assoc - where - assoc.source.id = :nodeId or - assoc.target.id = :nodeId - - - - select - assoc - from - org.alfresco.repo.domain.hibernate.NodeAssocImpl as assoc - join assoc.source as source - join assoc.target as target - where - assoc.source.id = :sourceId - - - - select - assoc - from - org.alfresco.repo.domain.hibernate.NodeAssocImpl as assoc - join assoc.source as source - join assoc.target as target - where - assoc.target.id = :targetId - - - - - SELECT - {n.*} - FROM - alf_node n - JOIN alf_store s on s.id = n.store_id - JOIN alf_node_properties p ON n.id = p.node_id - WHERE - s.protocol = :storeProtocol AND - s.identifier = :storeIdentifier AND - p.qname_id = :propQNameID AND - p.string_value = :propStringValue - - - - - - - SELECT - p1.string_value AS owner, - n.audit_creator AS creator, - p2.string_value AS contenturl - FROM - alf_node n - JOIN alf_store s ON (s.id = n.store_id AND n.type_qname_id = :contentTypeQNameID) - LEFT JOIN alf_node_properties p1 ON (p1.node_id = n.id AND p1.qname_id = :ownerPropQNameID) - JOIN alf_node_properties p2 ON (p2.node_id = n.id AND p2.qname_id = :contentPropQNameID) - WHERE - s.protocol = :storeProtocol AND - s.identifier = :storeIdentifier AND - p2.string_value IS NOT NULL AND - (p1.string_value != 'System' OR (p1.string_value IS NULL AND n.audit_creator != 'System')) - - - - - - - SELECT - p1.string_value AS owner, - n.audit_creator AS creator, - cd.id AS contentDataId - FROM - alf_node n - JOIN alf_store s ON (s.id = n.store_id AND n.type_qname_id = :contentTypeQNameID) - LEFT JOIN alf_node_properties p1 ON (p1.node_id = n.id AND p1.qname_id = :ownerPropQNameID) - JOIN alf_node_properties p2 ON (p2.node_id = n.id AND p2.qname_id = :contentPropQNameID) - JOIN alf_content_data cd ON (p2.long_value = cd.id) - WHERE - s.protocol = :storeProtocol AND - s.identifier = :storeIdentifier AND - (p1.string_value != 'System' OR (p1.string_value IS NULL AND n.audit_creator != 'System')) - - - - - - SELECT - n.uuid AS uuid - FROM - alf_node n - JOIN alf_store s ON (s.id = n.store_id AND n.type_qname_id = :personTypeQNameID) - LEFT JOIN alf_node_properties p1 ON (p1.node_id = n.id AND p1.qname_id = :sizeCurrentPropQNameID) - WHERE - s.protocol = :storeProtocol AND - s.identifier = :storeIdentifier AND - n.node_deleted = :isDeleted AND - p1.persisted_type_n IS NULL - - - - - - SELECT - p1.string_value AS username, - n.uuid AS uuid - FROM - alf_node n - JOIN alf_store s ON (s.id = n.store_id AND n.type_qname_id = :personTypeQNameID) - JOIN alf_node_properties p1 ON (p1.node_id = n.id AND p1.qname_id = :usernamePropQNameID) - JOIN alf_node_properties p2 ON (p2.node_id = n.id AND p2.qname_id = :sizeCurrentPropQNameID) - WHERE - s.protocol = :storeProtocol AND - s.identifier = :storeIdentifier AND - p2.persisted_type_n = 0 AND - p1.string_value != 'System' - - - - - - SELECT - p1.string_value AS username, - n.uuid AS uuid - FROM - alf_node n - JOIN alf_store s ON (s.id = n.store_id AND n.type_qname_id = :personTypeQNameID) - JOIN alf_node_properties p1 ON (p1.node_id = n.id AND p1.qname_id = :usernamePropQNameID) - JOIN alf_node_properties p2 ON (p2.node_id = n.id AND p2.qname_id = :sizeCurrentPropQNameID) - WHERE - s.protocol = :storeProtocol AND - s.identifier = :storeIdentifier AND - p2.persisted_type_n != 0 AND - p1.string_value != 'System' - - - - select - node - from - org.alfresco.repo.domain.hibernate.NodeImpl as node - join - node.properties prop - where - ( - prop.actualType = :actualType or - prop.actualType = 9 - ) and - prop.persistedType != 0 - - - - select distinct - node - from - org.alfresco.repo.domain.hibernate.NodeImpl as node - join node.properties as props - where - props.serializableValue is not null - - - - - - - - - SELECT - n.id, - s.protocol, - s.identifier, - n.uuid - FROM - alf_node n - JOIN alf_store s ON (s.id = n.store_id) - LEFT OUTER JOIN alf_child_assoc a ON (a.child_node_id = n.id AND a.type_qname_id = :assocTypeQNameID) - WHERE - s.protocol = :storeProtocol AND - s.identifier = :storeIdentifier AND - n.type_qname_id = :nodeTypeQNameID AND - n.node_deleted = :isDeleted AND - a.child_node_id IS NULL - - - - - - - - - - - - - - - - - select - z1.id, - z1.type_qname_id, - z1.qname_ns_id, - z1.qname_localname, - z1.qname_crc, - z1.child_node_name, - z1.child_node_name_crc, - z1.is_primary, - z1.assoc_index, - n.id, - s.protocol, - s.identifier, - n.uuid - FROM - (alf_node n - JOIN alf_store s ON (s.id = n.store_id) - JOIN alf_child_assoc z1 ON (z1.parent_node_id = :parentId and z1.child_node_id = n.id)) - LEFT OUTER JOIN - (alf_child_assoc a - JOIN alf_child_assoc z2 ON (z2.parent_node_id = :parentId AND z2.child_node_id = a.parent_node_id )) - ON (a.child_node_id = n.id AND a.type_qname_id = :assocTypeQNameID) - WHERE - a.child_node_id IS NULL - diff --git a/source/java/org/alfresco/repo/domain/hibernate/NodeAccessControlListDAO.java b/source/java/org/alfresco/repo/domain/hibernate/NodeAccessControlListDAO.java deleted file mode 100644 index 16fedacf71..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/NodeAccessControlListDAO.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . */ - -package org.alfresco.repo.domain.hibernate; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.alfresco.repo.domain.AccessControlListDAO; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.node.db.NodeDaoService; -import org.alfresco.repo.security.permissions.ACLType; -import org.alfresco.repo.security.permissions.impl.AclChange; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.util.Pair; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; - -/** - * The Node implementation for getting and setting ACLs. - * - * @author britt - */ -public class NodeAccessControlListDAO extends HibernateDaoSupport implements AccessControlListDAO -{ - /** - * The DAO for Nodes. - */ - private NodeDaoService fNodeDAOService; - - /** - * Default constructor. - */ - public NodeAccessControlListDAO() - { - } - - public void setNodeDaoService(NodeDaoService nodeDAOService) - { - fNodeDAOService = nodeDAOService; - } - - private Pair getNodePairNotNull(NodeRef nodeRef) - { - Pair nodePair = fNodeDAOService.getNodePair(nodeRef); - if (nodePair == null) - { - throw new InvalidNodeRefException(nodeRef); - } - return nodePair; - } - - public DbAccessControlList getAccessControlList(NodeRef nodeRef) - { - Pair nodePair = getNodePairNotNull(nodeRef); - Long aclId = fNodeDAOService.getNodeAccessControlList(nodePair.getFirst()); - // Now get the entity - DbAccessControlList acl; - if (aclId == null) - { - return null; - } - else - { - acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, aclId); - } - return acl; - } - - public void setAccessControlList(NodeRef nodeRef, DbAccessControlList acl) - { - Pair nodePair = getNodePairNotNull(nodeRef); - Long aclId = (acl == null) ? null : acl.getId(); - fNodeDAOService.setNodeAccessControlList(nodePair.getFirst(), aclId); - } - - public void updateChangedAcls(NodeRef startingPoint, List changes) - { - // Nothing to do here - } - - public List setInheritanceForChildren(NodeRef parent, Long inheritFrom) - { - // Nothing to do here - return Collections. emptyList(); - } - - public Long getIndirectAcl(NodeRef nodeRef) - { - DbAccessControlList acl = getAccessControlList(nodeRef); - return (acl == null) ? null : acl.getId(); - } - - public Long getInheritedAcl(NodeRef nodeRef) - { - Pair nodePair = fNodeDAOService.getNodePair(nodeRef); - if (nodePair == null) - { - throw new InvalidNodeRefException(nodeRef); - } - Pair caPair = fNodeDAOService.getPrimaryParentAssoc(nodePair.getFirst()); - if ((caPair != null) && (caPair.getSecond().getParentRef() != null)) - { - NodeRef parentRef = caPair.getSecond().getParentRef(); - Long parentNodeId = fNodeDAOService.getNodePair(parentRef).getFirst(); - Long aclId = fNodeDAOService.getNodeAccessControlList(parentNodeId); - return aclId; - } - else - { - return null; - } - } - - public void forceCopy(NodeRef nodeRef) - { - // nothing to do; - } - - public Map patchAcls() - { - throw new UnsupportedOperationException(); - } - - public DbAccessControlList getAccessControlList(StoreRef storeRef) - { - throw new UnsupportedOperationException(); - } - - public void setAccessControlList(StoreRef storeRef, DbAccessControlList acl) - { - throw new UnsupportedOperationException(); - } - - public void setAccessControlList(NodeRef nodeRef, Long aclId) - { - Pair nodePair = getNodePairNotNull(nodeRef); - fNodeDAOService.setNodeAccessControlList(nodePair.getFirst(), aclId); - } -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/NodeAssocImpl.java b/source/java/org/alfresco/repo/domain/hibernate/NodeAssocImpl.java deleted file mode 100644 index ca6e7de45c..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/NodeAssocImpl.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.io.Serializable; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; - -import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.NodeAssoc; -import org.alfresco.repo.domain.qname.QNameDAO; -import org.alfresco.service.cmr.repository.AssociationRef; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.EqualsHelper; - -/** - * Hibernate-specific implementation of the generic node association - * - * @author Derek Hulley - */ -public class NodeAssocImpl implements NodeAssoc, Serializable -{ - private static final long serialVersionUID = 864534636913524867L; - - private Long id; - private Long version; - private Node source; - private Node target; - private Long typeQNameId; - - private transient ReadLock refReadLock; - private transient WriteLock refWriteLock; - private transient AssociationRef nodeAssocRef; - private transient QName typeQName; - - public NodeAssocImpl() - { - ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - refReadLock = lock.readLock(); - refWriteLock = lock.writeLock(); - } - - public void buildAssociation(Node sourceNode, Node targetNode) - { - // add the forward associations - this.setTarget(targetNode); - this.setSource(sourceNode); - } - - public AssociationRef getNodeAssocRef(QNameDAO qnameDAO) - { - boolean trashReference = false; - // first check if it is available - refReadLock.lock(); - try - { - if (nodeAssocRef != null) - { - // double check that the parent and child node references match those of our reference - if (nodeAssocRef.getSourceRef() != source.getNodeRef() || - nodeAssocRef.getTargetRef() != target.getNodeRef()) - { - trashReference = true; - } - else - { - // we are sure that the reference is correct - return nodeAssocRef; - } - } - } - finally - { - refReadLock.unlock(); - } - // get write lock - refWriteLock.lock(); - try - { - if (typeQName == null) - { - typeQName = qnameDAO.getQName(typeQNameId).getSecond(); - } - // double check - if (nodeAssocRef == null || trashReference) - { - nodeAssocRef = new AssociationRef( - this.id, - getSource().getNodeRef(), - this.typeQName, - getTarget().getNodeRef()); - } - return nodeAssocRef; - } - finally - { - refWriteLock.unlock(); - } - } - - public QName getTypeQName(QNameDAO qnameDAO) - { - refReadLock.lock(); - try - { - if (typeQName != null) - { - return typeQName; - } - } - finally - { - refReadLock.unlock(); - } - // get write lock - refWriteLock.lock(); - try - { - typeQName = qnameDAO.getQName(typeQNameId).getSecond(); - return typeQName; - } - finally - { - refWriteLock.unlock(); - } - } - - public void setTypeQName(QNameDAO qnameDAO, QName typeQName) - { - Long typeQNameId = qnameDAO.getOrCreateQName(typeQName).getFirst(); - refWriteLock.lock(); - try - { - setTypeQNameId(typeQNameId); - } - finally - { - refWriteLock.unlock(); - } - } - - public String toString() - { - StringBuffer sb = new StringBuffer(32); - sb.append("NodeAssoc") - .append("[ source=").append(source) - .append(", target=").append(target) - .append(", type=").append(typeQNameId) - .append("]"); - return sb.toString(); - } - - public boolean equals(Object obj) - { - if (obj == null) - { - return false; - } - else if (obj == this) - { - return true; - } - else if (!(obj instanceof NodeAssoc)) - { - return false; - } - NodeAssoc that = (NodeAssoc) obj; - if (EqualsHelper.nullSafeEquals(this.typeQNameId, that.getId())) - { - return true; - } - else - { - return (EqualsHelper.nullSafeEquals(this.typeQNameId, that.getTypeQNameId()) - && EqualsHelper.nullSafeEquals(this.getTarget(), that.getTarget()) - && EqualsHelper.nullSafeEquals(this.getSource(), that.getSource()) - ); - } - } - - public int hashCode() - { - return (typeQNameId == null ? 0 : typeQNameId.hashCode()); - } - - public Long getId() - { - return id; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setId(long id) - { - this.id = id; - } - - public Long getVersion() - { - return version; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setVersion(Long version) - { - this.version = version; - } - - public Node getSource() - { - return source; - } - - /** - * For internal use - */ - private void setSource(Node source) - { - refWriteLock.lock(); - try - { - this.source = source; - this.nodeAssocRef = null; - } - finally - { - refWriteLock.unlock(); - } - } - - public Node getTarget() - { - return target; - } - - /** - * For internal use - */ - private void setTarget(Node target) - { - refWriteLock.lock(); - try - { - this.target = target; - this.nodeAssocRef = null; - } - finally - { - refWriteLock.unlock(); - } - } - - public Long getTypeQNameId() - { - return typeQNameId; - } - - public void setTypeQNameId(Long typeQNameId) - { - refWriteLock.lock(); - try - { - this.typeQNameId = typeQNameId; - this.nodeAssocRef = null; - this.typeQName = null; - } - finally - { - refWriteLock.unlock(); - } - } -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java b/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java index a1cca4e927..251247f6a9 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/NodeImpl.java @@ -20,20 +20,17 @@ package org.alfresco.repo.domain.hibernate; import java.io.Serializable; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import org.alfresco.repo.domain.AuditableProperties; -import org.alfresco.repo.domain.DbAccessControlList; import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.NodePropertyValue; -import org.alfresco.repo.domain.PropertyMapKey; import org.alfresco.repo.domain.Store; -import org.alfresco.repo.domain.Transaction; +import org.alfresco.repo.domain.node.NodePropertyKey; +import org.alfresco.repo.domain.node.NodePropertyValue; +import org.alfresco.repo.domain.node.Transaction; import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; @@ -56,11 +53,10 @@ public class NodeImpl extends LifecycleAdapter implements Node, Serializable private Store store; private String uuid; private Long typeQNameId; + private Long aclId; private Transaction transaction; private boolean deleted; - private DbAccessControlList accessControlList; - private Set aspects; - private Map properties; + private Map properties; private AuditableProperties auditableProperties; private transient ReadLock refReadLock; @@ -74,8 +70,7 @@ public class NodeImpl extends LifecycleAdapter implements Node, Serializable refReadLock = lock.readLock(); refWriteLock = lock.writeLock(); - aspects = new HashSet(5); - properties = new HashMap(5); + properties = new HashMap(5); // Note auditableProperties starts null, as hibernate maps a component containing nulls to null and this would // cause a lot of dirty checks to fail! } @@ -304,32 +299,18 @@ public class NodeImpl extends LifecycleAdapter implements Node, Serializable refWriteLock.unlock(); } } - - public DbAccessControlList getAccessControlList() + + public Long getAclId() { - return accessControlList; - } - - public void setAccessControlList(DbAccessControlList accessControlList) - { - this.accessControlList = accessControlList; - } - - public Set getAspects() - { - return aspects; + return aclId; } - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setAspects(Set aspects) + public void setAclId(Long aclId) { - this.aspects = aspects; + this.aclId = aclId; } - public Map getProperties() + public Map getProperties() { return properties; } @@ -338,7 +319,7 @@ public class NodeImpl extends LifecycleAdapter implements Node, Serializable * For Hibernate use */ @SuppressWarnings("unused") - private void setProperties(Map properties) + private void setProperties(Map properties) { this.properties = properties; } diff --git a/source/java/org/alfresco/repo/domain/hibernate/OldADMPermissionsDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/hibernate/OldADMPermissionsDaoComponentImpl.java deleted file mode 100644 index cfc751ba3c..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/OldADMPermissionsDaoComponentImpl.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import java.util.Collections; - -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.security.permissions.ACLType; -import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties; -import org.alfresco.repo.security.permissions.impl.AclChange; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * 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 OldADMPermissionsDaoComponentImpl extends AbstractPermissionsDaoComponentImpl -{ - private static Log logger = LogFactory.getLog(OldADMPermissionsDaoComponentImpl.class); - - /** - * - */ - public OldADMPermissionsDaoComponentImpl() - { - super(); - } - - /** - * Creates an access control list for the node and removes the entry from the nullPermsionCache. - */ - protected AbstractPermissionsDaoComponentImpl.CreationReport createAccessControlList(NodeRef nodeRef, boolean inherit, DbAccessControlList existing) - { - SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); - properties.setAclType(ACLType.OLD); - properties.setInherits(inherit); - Long id = aclDaoComponent.createAccessControlList(properties); - DbAccessControlList acl = aclDaoComponent.getDbAccessControlList(id); - - // maintain inverse - getACLDAO(nodeRef).setAccessControlList(nodeRef, acl); - - // done - if (logger.isDebugEnabled()) - { - logger.debug("Created Access Control List: \n" + " node: " + nodeRef + "\n" + " list: " + acl); - } - - AbstractPermissionsDaoComponentImpl.CreationReport report = new AbstractPermissionsDaoComponentImpl.CreationReport(acl, Collections - . singletonList(new AclDaoComponentImpl.AclChangeImpl(null, id, null, acl.getAclType()))); - return report; - - } - - public void deletePermissions(NodeRef nodeRef) - { - DbAccessControlList acl = null; - try - { - acl = getAccessControlList(nodeRef); - } - catch (InvalidNodeRefException e) - { - return; - } - if (acl != null) - { - // maintain referencial integrity - getACLDAO(nodeRef).setAccessControlList(nodeRef, (Long) null); - aclDaoComponent.deleteAccessControlList(acl.getId()); - } - } - - public static SimpleAccessControlListProperties getDefaultProperties() - { - SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); - properties.setAclType(ACLType.OLD); - properties.setInherits(true); - properties.setVersioned(false); - return properties; - } -} diff --git a/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml deleted file mode 100644 index 499efa20fb..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml +++ /dev/null @@ -1,439 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - select - permission - from - org.alfresco.repo.domain.hibernate.DbPermissionImpl as permission - where - permission.typeQNameId = :permissionTypeQNameId and - permission.name = :permissionName - - - - select - authority - from - org.alfresco.repo.domain.hibernate.DbAuthorityImpl as authority - where - authority.authority = :authority - - - - select - ace - from - org.alfresco.repo.domain.hibernate.DbAccessControlEntryImpl as ace - where - ace.permission.id = :permissionId and - ace.authority.id = :authorityId and - ace.allowed = :allowed and - ace.applies = :applies and - ace.context is null - - - - select - alias - from - org.alfresco.repo.domain.hibernate.DbAuthorityAliasImpl as alias - join alias.authority as authority - join alias.alias as authorityAlias - where - authority.authority = :authority and - authorityAlias.authority = :alias - - - - select - authorityAlias.authority - from - org.alfresco.repo.domain.hibernate.DbAuthorityAliasImpl as alias - join alias.authority as authority - join alias.alias as authorityAlias - where - authority.authority = :authority - - - - select - aclmem.id, acl.id, ace.id, authority.authority - from - org.alfresco.repo.domain.hibernate.DbAccessControlListMemberImpl as aclmem - join aclmem.accessControlList as acl - join aclmem.accessControlEntry as ace - join ace.authority as authority - where - authority.authority = :authority - - - - select - ace - from - org.alfresco.repo.domain.hibernate.DbAccessControlEntryImpl as ace - join ace.authority as authority - where - authority.authority = :authority - - - - - - select - aclmem - from - org.alfresco.repo.domain.hibernate.DbAccessControlListMemberImpl as aclmem - where - aclmem.accessControlList.id = :id - - - - select - ace.allowed, ace.applies, authority.authority, ace.permission.id, aclmem.position - from - org.alfresco.repo.domain.hibernate.DbAccessControlListMemberImpl as aclmem - join aclmem.accessControlList as acl - join aclmem.accessControlEntry as ace - join ace.authority as authority - where - acl.id = :id - - - - select - acl.id - from - org.alfresco.repo.domain.hibernate.DbAccessControlListImpl as acl - where acl.inheritsFrom = :id and acl.inherits = true - - - - select - acl.id - from - org.alfresco.repo.domain.hibernate.DbAccessControlListImpl as acl - where acl.aclId = :aclId and latest = true - - - - - - - - - - - - :above - ]]> - - - - \ No newline at end of file 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 e02a687697..cabca7af72 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/Transaction.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/Transaction.hbm.xml @@ -8,7 +8,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - select - count(deltaSize), sum(deltaSize) - from - org.alfresco.repo.domain.hibernate.UsageDeltaImpl as usage_delta - where - usage_delta.node.id = :nodeId - - - - - - select - distinct usage_delta.node - from - org.alfresco.repo.domain.hibernate.UsageDeltaImpl as usage_delta - - - - - select - usage_delta - from - org.alfresco.repo.domain.hibernate.UsageDeltaImpl as usage_delta - where - usage_delta.node.id = :nodeId - - - - delete - from - org.alfresco.repo.domain.hibernate.UsageDeltaImpl as usage - where - usage.node.id = :nodeId - - - \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/hibernate/UsageDeltaImpl.java b/source/java/org/alfresco/repo/domain/hibernate/UsageDeltaImpl.java deleted file mode 100644 index a3540e6e08..0000000000 --- a/source/java/org/alfresco/repo/domain/hibernate/UsageDeltaImpl.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; - -import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.UsageDelta; - -/** - * Usage Delta Implementation - * - */ -public class UsageDeltaImpl implements UsageDelta -{ - private Long id; - private Long version; - - private Node node; - private long deltaSize; // +ve or -ve or 0 (in bytes) - - - public Long getId() - { - return id; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setId(Long id) - { - this.id = id; - } - - public Long getVersion() - { - return version; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setVersion(Long version) - { - this.version = version; - } - - - public Node getNode() - { - return node; - } - - public void setNode(Node node) - { - this.node = node; - } - - public long getDeltaSize() - { - return deltaSize; - } - - public void setDeltaSize(long deltaSize) - { - this.deltaSize = deltaSize; - } -} diff --git a/source/java/org/alfresco/repo/domain/locale/AbstractLocaleDAOImpl.java b/source/java/org/alfresco/repo/domain/locale/AbstractLocaleDAOImpl.java new file mode 100644 index 0000000000..e91ee95549 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/locale/AbstractLocaleDAOImpl.java @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.locale; + +import java.util.Locale; + +import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.cache.lookup.EntityLookupCache; +import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAOAdaptor; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.util.Pair; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.extensions.surf.util.I18NUtil; + +/** + * Abstract implementation for Locale DAO. + *

+ * This provides basic services such as caching, but defers to the underlying implementation + * for CRUD operations. + * + * Since locales are system-wide and immutable, we can cache lookups in both directions. + * + * @author janv + * @since 3.4 + */ +public abstract class AbstractLocaleDAOImpl implements LocaleDAO +{ + private static final String CACHE_REGION_LOCALE = "Locale"; + + /** + * Cache for the Locale values:
+ * KEY: ID
+ * VALUE: Locale
+ * VALUE KEY: Locale
+ */ + private EntityLookupCache localeEntityCache; + + /** + * Set the cache that maintains the ID-Locale mappings and vice-versa (bi-directional) + * + * @param localeEntityCache the cache + */ + public void setLocaleEntityCache(SimpleCache localeEntityCache) + { + this.localeEntityCache = new EntityLookupCache( + localeEntityCache, + CACHE_REGION_LOCALE, + new LocaleEntityCallbackDAO()); + } + + /** + * Default constructor. + *

+ * This sets up the DAO accessors to bypass any caching to handle the case where the caches are not + * supplied in the setters. + */ + protected AbstractLocaleDAOImpl() + { + this.localeEntityCache = new EntityLookupCache(new LocaleEntityCallbackDAO()); + } + + public Pair getLocalePair(Locale locale) + { + if (locale == null) + { + throw new IllegalArgumentException("Locale cannot be null"); + } + + return getLocalePairImpl(locale); + } + + public Pair getDefaultLocalePair() + { + return getLocalePairImpl(null); + } + + public Pair getLocalePair(Long id) + { + if (id == null) + { + throw new IllegalArgumentException("Cannot look up entity by null ID."); + } + + Pair entityPair = localeEntityCache.getByKey(id); + if (entityPair == null) + { + throw new DataIntegrityViolationException("No locale exists for ID " + id); + } + + // Convert the locale string to a locale + Locale locale = DefaultTypeConverter.INSTANCE.convert(Locale.class, entityPair.getSecond()); + return new Pair(id, locale); + } + + public Pair getOrCreateLocalePair(Locale locale) + { + if (locale == null) + { + throw new IllegalArgumentException("Locale cannot be null"); + } + + String localeStr = DefaultTypeConverter.INSTANCE.convert(String.class, locale); + Pair entityPair = localeEntityCache.getOrCreateByValue(localeStr); + if (entityPair == null) + { + throw new RuntimeException("Locale should have been created."); + } + return new Pair(entityPair.getFirst(), locale); + } + + public Pair getOrCreateDefaultLocalePair() + { + Pair localePair = getDefaultLocalePair(); + if (localePair != null) + { + return localePair; + } + + LocaleEntity localeEntity = new LocaleEntity(); + localeEntity.setLocale(null); + + return getOrCreateLocalePair(localeEntity.getLocale()); + } + + private Pair getLocalePairImpl(Locale locale) + { + // Null means look for the default + final String localeStr; + if (locale == null) + { + localeStr = LocaleEntity.DEFAULT_LOCALE_SUBSTITUTE; + locale = I18NUtil.getLocale(); + } + else + { + localeStr = DefaultTypeConverter.INSTANCE.convert(String.class, locale); + } + + if (localeStr == null) + { + throw new IllegalArgumentException("Cannot look up entity by null ID."); + } + + Pair entityPair = localeEntityCache.getByValue(localeStr); + if (entityPair == null) + { + return null; + } + else + { + return new Pair(entityPair.getFirst(), locale); + } + } + + /** + * Callback for alf_locale DAO + */ + private class LocaleEntityCallbackDAO extends EntityLookupCallbackDAOAdaptor + { + @Override + public String getValueKey(String value) + { + return value; + } + + public Pair findByKey(Long id) + { + LocaleEntity entity = getLocaleEntity(id); + if (entity == null) + { + return null; + } + else + { + return new Pair(id, entity.getLocaleStr()); + } + } + + @Override + public Pair findByValue(String localeStr) + { + LocaleEntity entity = getLocaleEntity(localeStr); + if (entity == null) + { + return null; + } + else + { + return new Pair(entity.getId(), localeStr); + } + } + + public Pair createValue(String localeStr) + { + LocaleEntity entity = createLocaleEntity(localeStr); + return new Pair(entity.getId(), localeStr); + } + } + + protected abstract LocaleEntity getLocaleEntity(Long id); + protected abstract LocaleEntity getLocaleEntity(String locale); + protected abstract LocaleEntity createLocaleEntity(String locale); +} diff --git a/source/java/org/alfresco/repo/domain/LocaleDAO.java b/source/java/org/alfresco/repo/domain/locale/LocaleDAO.java similarity index 66% rename from source/java/org/alfresco/repo/domain/LocaleDAO.java rename to source/java/org/alfresco/repo/domain/locale/LocaleDAO.java index 7d61643c4e..2f5d2a92af 100644 --- a/source/java/org/alfresco/repo/domain/LocaleDAO.java +++ b/source/java/org/alfresco/repo/domain/locale/LocaleDAO.java @@ -1,34 +1,39 @@ /* * Copyright (C) 2005-2010 Alfresco Software Limited. * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.domain; +package org.alfresco.repo.domain.locale; import java.util.Locale; import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.repo.domain.hibernate.DirtySessionAnnotation; import org.alfresco.util.Pair; /** * Data abstraction layer for Locale entities. * - * @author Derek Hulley - * @since 2.2.1 + * @author Derek Hulley, janv + * @since 3.4 */ public interface LocaleDAO { @@ -37,14 +42,12 @@ public interface LocaleDAO * @return the locale (never null) * @throws AlfrescoRuntimeException if the ID provided is invalid */ - @DirtySessionAnnotation(markDirty=false) Pair getLocalePair(Long id); /** * @param id the locale to fetch or null to get the default locale * @return the locale or null if no such locale exists */ - @DirtySessionAnnotation(markDirty=false) Pair getLocalePair(Locale locale); /** @@ -53,7 +56,6 @@ public interface LocaleDAO * refers to the system's default locale i.e. the value returned can vary * depending on the executing thread's default locale. */ - @DirtySessionAnnotation(markDirty=false) Pair getDefaultLocalePair(); /** @@ -64,7 +66,6 @@ public interface LocaleDAO * locale. * @return the locale - never null */ - @DirtySessionAnnotation(markDirty=true) Pair getOrCreateLocalePair(Locale locale); /** @@ -75,6 +76,5 @@ public interface LocaleDAO * refers to the system's default locale i.e. the value returned can vary * depending on the executing thread's default locale. */ - @DirtySessionAnnotation(markDirty=true) Pair getOrCreateDefaultLocalePair(); } diff --git a/source/java/org/alfresco/repo/domain/LocaleDAOTest.java b/source/java/org/alfresco/repo/domain/locale/LocaleDAOTest.java similarity index 57% rename from source/java/org/alfresco/repo/domain/LocaleDAOTest.java rename to source/java/org/alfresco/repo/domain/locale/LocaleDAOTest.java index b2d4b5324d..15975a238b 100644 --- a/source/java/org/alfresco/repo/domain/LocaleDAOTest.java +++ b/source/java/org/alfresco/repo/domain/locale/LocaleDAOTest.java @@ -1,22 +1,28 @@ /* * Copyright (C) 2005-2010 Alfresco Software Limited. * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.domain; +package org.alfresco.repo.domain.locale; import java.util.ArrayList; import java.util.Collections; @@ -27,44 +33,99 @@ import java.util.concurrent.TimeUnit; import junit.framework.TestCase; -import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.GUID; import org.alfresco.util.Pair; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; +import org.springframework.extensions.surf.util.I18NUtil; /** * @see LocaleDAO * - * - * @author Derek Hulley - * @since 2.2.1 + * @author Derek Hulley, janv + * @since 2.2.1, 3.3 */ public class LocaleDAOTest extends TestCase { private static Log logger = LogFactory.getLog(LocaleDAOTest.class); - private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + private ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); - private RetryingTransactionHelper retryingTransactionHelper; - private LocaleDAO dao; + private TransactionService transactionService; + private RetryingTransactionHelper txnHelper; + private LocaleDAO localeDAO; @Override public void setUp() throws Exception { ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); - retryingTransactionHelper = serviceRegistry.getTransactionService().getRetryingTransactionHelper(); - dao = (LocaleDAO) ctx.getBean("localeDAO"); + transactionService = serviceRegistry.getTransactionService(); + txnHelper = transactionService.getRetryingTransactionHelper(); + + localeDAO = (LocaleDAO) ctx.getBean("localeDAO"); } @Override public void tearDown() throws Exception { - + // NOOP + } + + private Pair getLocale(final Locale locale, boolean expectSuccess) + { + RetryingTransactionCallback> callback = new RetryingTransactionCallback>() + { + public Pair execute() throws Throwable + { + Pair localePair = localeDAO.getOrCreateLocalePair(locale); + return localePair; + } + }; + try + { + return txnHelper.doInTransaction(callback, false); + } + catch (Throwable e) + { + if (expectSuccess) + { + // oops + throw new RuntimeException("Expected to get locale '" + locale + "'.", e); + } + else + { + return null; + } + } + } + + + public void testCreateLocale() throws Exception + { + // Create a locale + Locale locale = new Locale(GUID.generate().substring(0, 20)); + Pair localePair = getLocale(locale, true); + // Check that it can be retrieved + Pair localePairCheck = getLocale(localePair.getSecond(), true); + assertEquals("Locale ID changed", localePair.getFirst(), localePairCheck.getFirst()); + // Check the duplicate checking + getLocale(locale, false); + } + + public void testCreateLocaleEmpty() throws Exception + { + // Create a locale + Locale locale = new Locale(""); + Pair localePair = getLocale(locale, true); + // Check that it can be retrieved + Pair localePairCheck = getLocale(localePair.getSecond(), true); + assertEquals("Locale ID changed", localePair.getFirst(), localePairCheck.getFirst()); } public void testDefaultLocale() throws Exception @@ -76,7 +137,7 @@ public class LocaleDAOTest extends TestCase // What is the thread's default locale? Locale defaultLocale = I18NUtil.getLocale(); // Now make it - Pair localePair = dao.getOrCreateDefaultLocalePair(); + Pair localePair = localeDAO.getOrCreateDefaultLocalePair(); assertNotNull("Default locale should now exist", localePair); assertEquals( "The default locale returned must match the current thread's default locale", @@ -87,12 +148,12 @@ public class LocaleDAOTest extends TestCase }; // Check that the default locale is handled properly - retryingTransactionHelper.doInTransaction(callback); + txnHelper.doInTransaction(callback); // Now change the default locale I18NUtil.setLocale(Locale.CANADA_FRENCH); // Repeat - retryingTransactionHelper.doInTransaction(callback); + txnHelper.doInTransaction(callback); } /** @@ -125,7 +186,7 @@ public class LocaleDAOTest extends TestCase { // This could fail with concurrency, but that's what we're testing logger.debug("Thread " + threadName + " is CREATING " + locale); - localePair = dao.getOrCreateLocalePair(locale); + localePair = localeDAO.getOrCreateLocalePair(locale); } catch (Throwable e) { @@ -145,7 +206,7 @@ public class LocaleDAOTest extends TestCase { try { - retryingTransactionHelper.doInTransaction(callback); + txnHelper.doInTransaction(callback); } catch (Throwable e) { diff --git a/source/java/org/alfresco/repo/domain/hibernate/LocaleEntityImpl.java b/source/java/org/alfresco/repo/domain/locale/LocaleEntity.java similarity index 62% rename from source/java/org/alfresco/repo/domain/hibernate/LocaleEntityImpl.java rename to source/java/org/alfresco/repo/domain/locale/LocaleEntity.java index 705aa87771..72c5898d41 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/LocaleEntityImpl.java +++ b/source/java/org/alfresco/repo/domain/locale/LocaleEntity.java @@ -1,67 +1,144 @@ /* * Copyright (C) 2005-2010 Alfresco Software Limited. * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.domain.hibernate; + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.locale; -import java.io.Serializable; import java.util.Locale; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; -import org.springframework.extensions.surf.util.I18NUtil; -import org.alfresco.repo.domain.LocaleEntity; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.springframework.extensions.surf.util.I18NUtil; + /** - * Hibernate-specific implementation of the domain entity LocaleEntity. + * Entity for alf_locale persistence. * - * @author Derek Hulley - * @since 2.2.1 + * @author janv + * @since 3.4 */ -public class LocaleEntityImpl implements LocaleEntity, Serializable +public class LocaleEntity { - private static final long serialVersionUID = -1436739054926548300L; - public static final String DEFAULT_LOCALE_SUBSTITUTE = ".default"; - + + public static final Long CONST_LONG_ZERO = new Long(0L); + private Long id; private Long version; private String localeStr; - + private transient ReadLock refReadLock; private transient WriteLock refWriteLock; private transient Locale locale; - - public LocaleEntityImpl() + + public LocaleEntity() { ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); refReadLock = lock.readLock(); refWriteLock = lock.writeLock(); } + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("LocaleEntity") + .append("[ id=").append(id) + .append(", localeStr=").append(localeStr) + .append("]"); + return sb.toString(); + } + + public Long getId() + { + return id; + } + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + public void setVersion(Long version) + { + this.version = version; + } + + public String getLocaleStr() + { + return localeStr; + } + public void setLocaleStr(String localeStr) + { + refWriteLock.lock(); + try + { + this.localeStr = localeStr; + this.locale = null; + } + finally + { + refWriteLock.unlock(); + } + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + else if (obj == this) + { + return true; + } + else if (!(obj instanceof LocaleEntity)) + { + return false; + } + LocaleEntity that = (LocaleEntity) obj; + return (this.getLocale().equals(that.getLocale())); + } + + @Override + public int hashCode() + { + return getLocale().hashCode(); + } + /** * Lazily constructs a Locale instance referencing this entity */ public Locale getLocale() { // The default locale cannot be cached as it depends on the running thread's locale - if (localeStr == null || localeStr.equals(LocaleEntityImpl.DEFAULT_LOCALE_SUBSTITUTE)) + if (localeStr == null || localeStr.equals(DEFAULT_LOCALE_SUBSTITUTE)) { return I18NUtil.getLocale(); } @@ -95,6 +172,9 @@ public class LocaleEntityImpl implements LocaleEntity, Serializable } } + /** + * @param locale the locale to set or null to represent the default locale + */ public void setLocale(Locale locale) { refWriteLock.lock(); @@ -102,7 +182,7 @@ public class LocaleEntityImpl implements LocaleEntity, Serializable { if (locale == null) { - this.localeStr = LocaleEntityImpl.DEFAULT_LOCALE_SUBSTITUTE; + this.localeStr = DEFAULT_LOCALE_SUBSTITUTE; this.locale = null; } else @@ -116,92 +196,4 @@ public class LocaleEntityImpl implements LocaleEntity, Serializable refWriteLock.unlock(); } } - - /** - * @see #getStoreRef()() - */ - public String toString() - { - return "" + localeStr; - } - - /** - * @see #getKey() - */ - public boolean equals(Object obj) - { - if (obj == null) - { - return false; - } - else if (obj == this) - { - return true; - } - else if (!(obj instanceof LocaleEntity)) - { - return false; - } - LocaleEntity that = (LocaleEntity) obj; - return (this.getLocale().equals(that.getLocale())); - } - - /** - * @see #getKey() - */ - public int hashCode() - { - return getLocale().hashCode(); - } - - public Long getId() - { - return id; - } - - /** - * For Hibernate use. - */ - @SuppressWarnings("unused") - private void setId(Long id) - { - this.id = id; - } - - public Long getVersion() - { - return version; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setVersion(Long version) - { - this.version = version; - } - - public String getLocaleStr() - { - return localeStr; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setLocaleStr(String localeStr) - { - refWriteLock.lock(); - try - { - this.localeStr = localeStr; - this.locale = null; - } - finally - { - refWriteLock.unlock(); - } - } -} \ No newline at end of file +} diff --git a/source/java/org/alfresco/repo/domain/locale/ibatis/LocaleDAOImpl.java b/source/java/org/alfresco/repo/domain/locale/ibatis/LocaleDAOImpl.java new file mode 100644 index 0000000000..1b16955fee --- /dev/null +++ b/source/java/org/alfresco/repo/domain/locale/ibatis/LocaleDAOImpl.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.locale.ibatis; + +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.repo.domain.locale.AbstractLocaleDAOImpl; +import org.alfresco.repo.domain.locale.LocaleEntity; +import org.springframework.orm.ibatis.SqlMapClientTemplate; + +/** + * iBatis-specific implementation of the Locale DAO. + * + * @author janv + * @since 3.4 + */ +public class LocaleDAOImpl extends AbstractLocaleDAOImpl +{ + private static final String SELECT_LOCALE_BY_ID = "alfresco.locale.select_LocaleById"; + private static final String SELECT_LOCALE_BY_NAME = "alfresco.locale.select_LocaleByName"; + private static final String INSERT_LOCALE = "alfresco.locale.insert_Locale"; + + private SqlMapClientTemplate template; + + public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) + { + this.template = sqlMapClientTemplate; + } + + @Override + protected LocaleEntity getLocaleEntity(Long id) + { + Map params = new HashMap(1); + params.put("id", id); + + return (LocaleEntity) template.queryForObject(SELECT_LOCALE_BY_ID, params); + } + + @Override + protected LocaleEntity getLocaleEntity(String localeStr) + { + Map params = new HashMap(1); + params.put("str", localeStr); + + return (LocaleEntity) template.queryForObject(SELECT_LOCALE_BY_NAME, params); + } + + @Override + protected LocaleEntity createLocaleEntity(String localeStr) + { + LocaleEntity localeEntity = new LocaleEntity(); + localeEntity.setVersion(LocaleEntity.CONST_LONG_ZERO); + localeEntity.setLocaleStr(localeStr); + + Long id = (Long) template.insert(INSERT_LOCALE, localeEntity); + localeEntity.setId(id); + return localeEntity; + } +} diff --git a/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java new file mode 100644 index 0000000000..b7d7fcbb0f --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/AbstractNodeDAOImpl.java @@ -0,0 +1,2940 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.io.Serializable; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.ibatis.BatchingDAO; +import org.alfresco.ibatis.RetryingCallbackHelper; +import org.alfresco.ibatis.RetryingCallbackHelper.RetryingCallback; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.cache.lookup.EntityLookupCache; +import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAOAdaptor; +import org.alfresco.repo.domain.AccessControlListDAO; +import org.alfresco.repo.domain.contentdata.ContentDataDAO; +import org.alfresco.repo.domain.locale.LocaleDAO; +import org.alfresco.repo.domain.permissions.AclDAO; +import org.alfresco.repo.domain.qname.QNameDAO; +import org.alfresco.repo.domain.usage.UsageDAO; +import org.alfresco.repo.policy.BehaviourFilter; +import org.alfresco.repo.security.permissions.AccessControlListProperties; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.repo.transaction.TransactionAwareSingleton; +import org.alfresco.repo.transaction.TransactionListenerAdapter; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState; +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.AssociationExistsException; +import org.alfresco.service.cmr.repository.AssociationRef; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.CyclicChildRelationshipException; +import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; +import org.alfresco.service.cmr.repository.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.InvalidStoreRefException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.Path; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.repository.NodeRef.Status; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.EqualsHelper; +import org.alfresco.util.GUID; +import org.alfresco.util.Pair; +import org.alfresco.util.PropertyCheck; +import org.alfresco.util.ReadWriteLockExecuter; +import org.alfresco.util.EqualsHelper.MapValueComparison; +import org.apache.commons.lang.SerializationUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.util.Assert; + +/** + * Abstract implementation for Node DAO. + *

+ * This provides basic services such as caching, but defers to the underlying implementation + * for CRUD operations. + *

+ * TODO: Timestamp propagation + * TODO: Local retries for certain operations that might benefit + * TODO: Take out joins to parent nodes for selectChildAssoc queries (it's static data) + * TODO: Child nodes' cache invalidation must use a leaner query + * TODO: Bulk loading of caches + * + * @author Derek Hulley + * @since 3.4 + */ +public abstract class AbstractNodeDAOImpl implements NodeDAO, BatchingDAO +{ + private static final String CACHE_REGION_ROOT_NODES = "N.RN"; + private static final String CACHE_REGION_NODES = "N.N"; + private static final String CACHE_REGION_ASPECTS = "N.A"; + private static final String CACHE_REGION_PROPERTIES = "N.P"; + private static final String CACHE_REGION_PARENT_ASSOCS = "N.PA"; + + private Log logger = LogFactory.getLog(getClass()); + private Log loggerPaths = LogFactory.getLog(getClass().getName() + ".paths"); + + private boolean isDebugEnabled = logger.isDebugEnabled(); + private NodePropertyHelper nodePropertyHelper; + private ServerIdCallback serverIdCallback = new ServerIdCallback(); + private UpdateTransactionListener updateTransactionListener = new UpdateTransactionListener(); + private RetryingCallbackHelper childAssocRetryingHelper; + + private DictionaryService dictionaryService; + private BehaviourFilter policyBehaviourFilter; + private AclDAO aclDAO; + private AccessControlListDAO accessControlListDAO; + private QNameDAO qnameDAO; + private ContentDataDAO contentDataDAO; + private LocaleDAO localeDAO; + private UsageDAO usageDAO; + + /** + * Cache for the Store root nodes by StoreRef:
+ * KEY: StoreRef
+ * VALUE: Node representing the root node
+ * VALUE KEY: IGNORED
+ */ + private EntityLookupCache rootNodesCache; + /** + * Bidirectional cache for the Node ID to Node lookups:
+ * KEY: Node ID
+ * VALUE: Node
+ * VALUE KEY: The Node's NodeRef
+ */ + private EntityLookupCache nodesCache; + /** + * Cache for the QName values:
+ * KEY: ID
+ * VALUE: Set<QName>
+ * VALUE KEY: None
+ */ + private EntityLookupCache, Serializable> aspectsCache; + /** + * Cache for the Node properties:
+ * KEY: ID
+ * VALUE: Map<QName, Serializable>
+ * VALUE KEY: None
+ */ + private EntityLookupCache, Serializable> propertiesCache; + /** + * Cache for the Node parent assocs:
+ * KEY: ID
+ * VALUE: ParentAssocs
+ * VALUE KEY: None
+ */ + private EntityLookupCache parentAssocsCache; + + /** + * Constructor. Set up various instance-specific members such as caches and locks. + */ + public AbstractNodeDAOImpl() + { + childAssocRetryingHelper = new RetryingCallbackHelper(); + childAssocRetryingHelper.setRetryWaitMs(10); + childAssocRetryingHelper.setMaxRetries(5); + // Caches + rootNodesCache = new EntityLookupCache(new RootNodesCacheCallbackDAO()); + nodesCache = new EntityLookupCache(new NodesCacheCallbackDAO()); + aspectsCache = new EntityLookupCache, Serializable>(new AspectsCallbackDAO()); + propertiesCache = new EntityLookupCache, Serializable>(new PropertiesCallbackDAO()); + parentAssocsCache = new EntityLookupCache(new ParentAssocsCallbackDAO()); + } + + /** + * @param dictionaryService the service help determine cm:auditable characteristics + */ + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + } + + /** + * @param policyBehaviourFilter the service to determine the behaviour for cm:auditable and + * other inherent capabilities. + */ + public void setPolicyBehaviourFilter(BehaviourFilter policyBehaviourFilter) + { + this.policyBehaviourFilter = policyBehaviourFilter; + } + + /** + * @param aclDAO used to update permissions during certain operations + */ + public void setAclDAO(AclDAO aclDAO) + { + this.aclDAO = aclDAO; + } + + /** + * @param accessControlListDAO used to update ACL inheritance during node moves + */ + public void setAccessControlListDAO(AccessControlListDAO accessControlListDAO) + { + this.accessControlListDAO = accessControlListDAO; + } + + /** + * @param qnameDAO translates QName IDs into QName instances and vice-versa + */ + public void setQnameDAO(QNameDAO qnameDAO) + { + this.qnameDAO = qnameDAO; + } + + /** + * @param contentDataDAO used to create and delete content references + */ + public void setContentDataDAO(ContentDataDAO contentDataDAO) + { + this.contentDataDAO = contentDataDAO; + } + + /** + * @param localeDAO used to handle MLText properties + */ + public void setLocaleDAO(LocaleDAO localeDAO) + { + this.localeDAO = localeDAO; + } + + /** + * @param usageDAO used to keep content usage calculations in line + */ + public void setUsageDAO(UsageDAO usageDAO) + { + this.usageDAO = usageDAO; + } + + /** + * Set the cache that maintains the Store root node data + * + * @param cache the cache + */ + public void setRootNodesCache(SimpleCache cache) + { + this.rootNodesCache = new EntityLookupCache( + cache, + CACHE_REGION_ROOT_NODES, + new RootNodesCacheCallbackDAO()); + } + + /** + * Set the cache that maintains node ID-NodeRef cross referencing data + * + * @param cache the cache + */ + public void setNodesCache(SimpleCache cache) + { + this.nodesCache = new EntityLookupCache( + cache, + CACHE_REGION_NODES, + new NodesCacheCallbackDAO()); + + } + + /** + * Set the cache that maintains the Node QName IDs + * + * @param aspectsCache the cache + */ + public void setAspectsCache(SimpleCache> aspectsCache) + { + this.aspectsCache = new EntityLookupCache, Serializable>( + aspectsCache, + CACHE_REGION_ASPECTS, + new AspectsCallbackDAO()); + } + + /** + * Set the cache that maintains the Node property values + * + * @param propertiesCache the cache + */ + public void setPropertiesCache(SimpleCache> propertiesCache) + { + this.propertiesCache = new EntityLookupCache, Serializable>( + propertiesCache, + CACHE_REGION_PROPERTIES, + new PropertiesCallbackDAO()); + } + + /** + * Set the cache that maintains the Node parent associations + * + * @param parentAssocsCache the cache + */ + public void setParentAssocsCache(SimpleCache parentAssocsCache) + { + this.parentAssocsCache = new EntityLookupCache( + parentAssocsCache, + CACHE_REGION_PARENT_ASSOCS, + new ParentAssocsCallbackDAO()); + } + + /* + * Initialize + */ + + public void init() + { + PropertyCheck.mandatory(this, "dictionaryService", dictionaryService); + PropertyCheck.mandatory(this, "aclDAO", aclDAO); + PropertyCheck.mandatory(this, "accessControlListDAO", accessControlListDAO); + PropertyCheck.mandatory(this, "qnameDAO", qnameDAO); + PropertyCheck.mandatory(this, "contentDataDAO", contentDataDAO); + PropertyCheck.mandatory(this, "localeDAO", localeDAO); + PropertyCheck.mandatory(this, "usageDAO", usageDAO); + + this.nodePropertyHelper = new NodePropertyHelper(dictionaryService, qnameDAO, localeDAO, contentDataDAO); + } + + /* + * Server + */ + + /** + * Wrapper to get the server ID within the context of a lock + */ + private class ServerIdCallback extends ReadWriteLockExecuter + { + private TransactionAwareSingleton serverIdStorage = new TransactionAwareSingleton(); + public Long getWithReadLock() throws Throwable + { + return serverIdStorage.get(); + } + public Long getWithWriteLock() throws Throwable + { + if (serverIdStorage.get() != null) + { + return serverIdStorage.get(); + } + // Server IP address + String ipAddress = null; + try + { + ipAddress = InetAddress.getLocalHost().getHostAddress(); + } + catch (UnknownHostException e) + { + throw new AlfrescoRuntimeException("Failed to get server IP address", e); + } + // Get the server instance + ServerEntity serverEntity = selectServer(ipAddress); + if (serverEntity != null) + { + serverIdStorage.put(serverEntity.getId()); + return serverEntity.getId(); + } + // Doesn't exist, so create it + Long serverId = insertServer(ipAddress); + serverIdStorage.put(serverId); + if (isDebugEnabled) + { + logger.debug("Created server entity: " + serverEntity); + } + return serverId; + } + } + + /** + * Get the ID of the current server + * + * @see ServerIdCallback + */ + private Long getServerId() + { + return serverIdCallback.execute(); + } + + /* + * Cache helpers + */ + + /** + * {@inheritDoc #invalidateCachesByNodeId(Long, Long, List)} + */ + private void invalidateCachesByNodeId( + Long parentNodeId, + Long childNodeId, + EntityLookupCache cache) + { + invalidateCachesByNodeId( + parentNodeId, + childNodeId, + Collections.>singletonList(cache)); + } + + /** + * Invalidate cache entries for given nodes. If the parent node is provided, + * then all children of that parent will be retrieved and their cache entries will + * be removed; this usually applies where the child associations or nodes are + * modified en-masse. + * + * @param parentNodeId the parent node of all child nodes to be invalidated (may be null) + * @param childNodeId the specific child node to invalidate (may be null) + * @param caches caches to invalidate by node id, which must use a Long as the key + */ + private void invalidateCachesByNodeId( + Long parentNodeId, + Long childNodeId, + final List> caches) + { + if (childNodeId != null) + { + for (EntityLookupCache cache : caches) + { + cache.removeByKey(childNodeId); + } + } + if (parentNodeId != null) + { + // Select all children + ChildAssocRefQueryCallback callback = new ChildAssocRefQueryCallback() + { + private int count = 0; + private boolean isClearOn = false; + + public boolean preLoadNodes() + { + return false; + } + + public boolean handle( + Pair childAssocPair, + Pair parentNodePair, + Pair childNodePair) + { + if (isClearOn) + { + // We have already decided to drop ALL cache entries + return false; + } + else if (count >= 1000) + { + // That's enough. Instead of walking thousands of entries + // we just drop the cache at this stage + for (EntityLookupCache cache : caches) + { + cache.clear(); + } + isClearOn = true; + return false; // No more, please + } + count++; + for (EntityLookupCache cache : caches) + { + cache.removeByKey(childNodePair.getFirst()); + } + return true; + } + }; + selectChildAssocs(parentNodeId, null, null, null, null, null, callback); + } + } + + /* + * Transactions + */ + + private static final String KEY_TRANSACTION = "node.transaction.id"; + + /** + * Wrapper to update the current transaction to get the change time correct + * + * @author Derek Hulley + * @since 3.4 + */ + private class UpdateTransactionListener extends TransactionListenerAdapter + { + @Override + public void beforeCommit(boolean readOnly) + { + if (readOnly) + { + return; + } + TransactionEntity txn = AlfrescoTransactionSupport.getResource(KEY_TRANSACTION); + Long txnId = txn.getId(); + // Update it + Long now = System.currentTimeMillis(); + updateTransaction(txnId, now); + } + } + + private TransactionEntity getCurrentTransaction() + { + TransactionEntity txn = AlfrescoTransactionSupport.getResource(KEY_TRANSACTION); + if (txn != null) + { + // We have been busy here before + return txn; + } + // Check that this is a writable txn + if (AlfrescoTransactionSupport.getTransactionReadState() != TxnReadState.TXN_READ_WRITE) + { + throw new IllegalStateException("Transaction entries can only be created for writable transactions"); + } + // Have to create a new transaction entry + Long serverId = getServerId(); + Long now = System.currentTimeMillis(); + String changeTxnId = AlfrescoTransactionSupport.getTransactionId(); + Long txnId = insertTransaction(serverId, changeTxnId, now); + // Store it for later + if (isDebugEnabled) + { + logger.debug("Create txn: " + txnId); + } + txn = new TransactionEntity(); + txn.setId(txnId); + txn.setChangeTxnId(changeTxnId); + txn.setCommitTimeMs(now); + ServerEntity server = new ServerEntity(); + server.setId(serverId); + txn.setServer(server); + + AlfrescoTransactionSupport.bindResource(KEY_TRANSACTION, txn); + // Listen for the end of the transaction + AlfrescoTransactionSupport.bindListener(updateTransactionListener); + // Done + return txn; + } + + public Long getCurrentTransactionId() + { + TransactionEntity txn = getCurrentTransaction(); + return txn.getId(); + } + + /* + * Stores + */ + + public List> getStores() + { + List storeEntities = selectAllStores(); + List> storeRefs = new ArrayList>(storeEntities.size()); + for (StoreEntity storeEntity : storeEntities) + { + storeRefs.add(new Pair(storeEntity.getId(), storeEntity.getStoreRef())); + } + return storeRefs; + } + + /** + * @throws InvalidStoreRefException if the store is invalid + */ + private StoreEntity getStoreNotNull(StoreRef storeRef) + { + Pair rootNodePair = rootNodesCache.getByKey(storeRef); + if (rootNodePair == null) + { + throw new InvalidStoreRefException(storeRef); + } + else + { + return rootNodePair.getSecond().getStore(); + } + } + + public boolean exists(StoreRef storeRef) + { + Pair rootNodePair = rootNodesCache.getByKey(storeRef); + return rootNodePair != null; + } + + public Pair getRootNode(StoreRef storeRef) + { + Pair rootNodePair = rootNodesCache.getByKey(storeRef); + if (rootNodePair == null) + { + throw new InvalidStoreRefException(storeRef); + } + else + { + return rootNodePair.getSecond().getNodePair(); + } + } + + public Pair newStore(StoreRef storeRef) + { + // Create the store + StoreEntity store = new StoreEntity(); + store.setProtocol(storeRef.getProtocol()); + store.setIdentifier(storeRef.getIdentifier()); + + Long storeId = insertStore(store); + store.setId(storeId); + + // Get an ACL for the root node + Long aclId = aclDAO.createAccessControlList(); + + // Create a root node + NodeEntity rootNode = newNodeImpl(store, null, ContentModel.TYPE_STOREROOT, aclId, false, null); + Long rootNodeId = rootNode.getId(); + addNodeAspects(rootNodeId, Collections.singleton(ContentModel.ASPECT_ROOT)); + + // Now update the store with the root node ID + store.setRootNode(rootNode); + updateStoreRoot(store); + + // Push the value into the caches + rootNodesCache.setValue(storeRef, rootNode); + + if (isDebugEnabled) + { + logger.debug("Created store: \n" + " " + store); + } + return new Pair(rootNode.getId(), rootNode.getNodeRef()); + } + + /** + * Callback to cache store root nodes by {@link StoreRef}. + * + * @author Derek Hulley + * @since 3.4 + */ + private class RootNodesCacheCallbackDAO extends EntityLookupCallbackDAOAdaptor + { + /** + * @throws UnsupportedOperationException Stores must be created externally + */ + public Pair createValue(Node value) + { + throw new UnsupportedOperationException("Root node creation is done externally: " + value); + } + + /** + * @param key the store ID + */ + public Pair findByKey(StoreRef storeRef) + { + NodeEntity node = selectStoreRootNode(storeRef); + return node == null ? null : new Pair(storeRef, node); + } + } + + /* + * Nodes + */ + + /** + * Callback to cache nodes by ID and {@link NodeRef}. When looking up objects based on the + * value key, only the referencing properties need be populated. ONLY live nodes are + * cached. + * + * @see NodeEntity + * + * @author Derek Hulley + * @since 3.4 + */ + private class NodesCacheCallbackDAO extends EntityLookupCallbackDAOAdaptor + { + /** + * @throws UnsupportedOperationException Nodes are created externally + */ + public Pair createValue(Node value) + { + throw new UnsupportedOperationException("Node creation is done externally: " + value); + } + + /** + * @param nodeId the key node ID + */ + public Pair findByKey(Long nodeId) + { + NodeEntity node = selectNodeById(nodeId, Boolean.FALSE); + return node == null ? null : new Pair(nodeId, node); + } + + /** + * @return Returns the Node's NodeRef + */ + @Override + public NodeRef getValueKey(Node value) + { + return value.getNodeRef(); + } + + /** + * Looks the node up based on the NodeRef of the given node + */ + @Override + public Pair findByValue(Node node) + { + NodeRef nodeRef = node.getNodeRef(); + node = selectNodeByNodeRef(nodeRef, Boolean.FALSE); + return node == null ? null : new Pair(node.getId(), node); + } + } + + public boolean exists(NodeRef nodeRef) + { + NodeEntity node = new NodeEntity(nodeRef); + Pair pair = nodesCache.getByValue(node); + return pair != null && !pair.getSecond().getDeleted(); + } + + public Status getNodeRefStatus(NodeRef nodeRef) + { + // First check the cache of live nodes + Node node = new NodeEntity(nodeRef); + Pair pair = nodesCache.getByValue(node); + if (pair == null) + { + // It's not there, so select ignoring the 'deleted' flag + node = selectNodeByNodeRef(nodeRef, null); + } + else + { + node = pair.getSecond(); + } + if (node == null) + { + return null; + } + else + { + Transaction txn = node.getTransaction(); + return new NodeRef.Status(txn.getChangeTxnId(), txn.getId(), node.getDeleted()); + } + } + + public Pair getNodePair(NodeRef nodeRef) + { + NodeEntity node = new NodeEntity(nodeRef); + Pair pair = nodesCache.getByValue(node); + return (pair == null || pair.getSecond().getDeleted()) ? null : pair.getSecond().getNodePair(); + } + + public Pair getNodePair(Long nodeId) + { + Pair pair = nodesCache.getByKey(nodeId); + return (pair == null || pair.getSecond().getDeleted()) ? null : pair.getSecond().getNodePair(); + } + + /** + * Find an undeleted node + * + * @param nodeId the node + * @return Returns the fully populated node + * @throws DataIntegrityViolationException if the ID doesn't reference a live node + */ + private Node getNodeNotNull(Long nodeId) + { + Pair pair = nodesCache.getByKey(nodeId); + if (pair == null || pair.getSecond().getDeleted()) + { + throw new DataIntegrityViolationException("No live node exists for ID " + nodeId); + } + else + { + return pair.getSecond(); + } + } + + public QName getNodeType(Long nodeId) + { + Node node = getNodeNotNull(nodeId); + Long nodeTypeQNameId = node.getTypeQNameId(); + return qnameDAO.getQName(nodeTypeQNameId).getSecond(); + } + + public Long getNodeAclId(Long nodeId) + { + Node node = getNodeNotNull(nodeId); + return node.getAclId(); + } + + public ChildAssocEntity newNode( + Long parentNodeId, + QName assocTypeQName, + QName assocQName, + StoreRef storeRef, + String uuid, + QName nodeTypeQName, + String childNodeName, + Map auditableProperties) throws InvalidTypeException + { + Assert.notNull(parentNodeId, "parentNodeId"); + Assert.notNull(assocTypeQName, "assocTypeQName"); + Assert.notNull(assocQName, "assocQName"); + Assert.notNull(storeRef, "storeRef"); + + if (auditableProperties == null) + { + auditableProperties = Collections.emptyMap(); + } + + // Get the parent node + Node parentNode = getNodeNotNull(parentNodeId); + // Find an initial ACL for the node + Long parentAclId = parentNode.getAclId(); + Long childAclId = null; + if (parentAclId != null) + { + AccessControlListProperties inheritedAcl = aclDAO.getAccessControlListProperties( + aclDAO.getInheritedAccessControlList(parentAclId)); + if (inheritedAcl != null) + { + childAclId = inheritedAcl.getId(); + } + } + // Build the cm:auditable properties + AuditablePropertiesEntity auditableProps = new AuditablePropertiesEntity(); + boolean setAuditProps = auditableProps.setAuditValues(null, null, auditableProperties); + if (!setAuditProps) + { + // No cm:auditable properties were supplied + auditableProps = null; + } + + // Get the store + StoreEntity store = getStoreNotNull(storeRef); + // Create the node (it is not a root node) + NodeEntity node = newNodeImpl(store, uuid, nodeTypeQName, childAclId, false, auditableProps); + Long nodeId = node.getId(); + + // Protect the node's cm:auditable if it was explicitly set + if (setAuditProps) + { + NodeRef nodeRef = node.getNodeRef(); + policyBehaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE); + } + + // Now create a primary association for it + if (childNodeName == null) + { + childNodeName = node.getUuid(); + } + ChildAssocEntity assoc = newChildAssocImpl( + parentNodeId, nodeId, true, assocTypeQName, assocQName, childNodeName); + + // There will be no other parent assocs + boolean isRoot = false; + boolean isStoreRoot = nodeTypeQName.equals(ContentModel.TYPE_STOREROOT); + ParentAssocsInfo parentAssocsInfo = new ParentAssocsInfo(isRoot, isStoreRoot, assoc); + parentAssocsCache.setValue(nodeId, parentAssocsInfo); + + if (isDebugEnabled) + { + logger.debug( + "Created new node: \n" + + " Node: " + node + "\n" + + " Assoc: " + assoc); + } + return assoc; + } + + /** + * @param uuid the node UUID, or null to auto-generate + * @param aclId an ACL ID if available + * @param auditableProps null to auto-generate or provide a value to explicitly set + * @param deleted true to create an already-deleted node (used for leaving trails of moved nodes) + */ + private NodeEntity newNodeImpl( + StoreEntity store, + String uuid, + QName nodeTypeQName, + Long aclId, + boolean deleted, + AuditablePropertiesEntity auditableProps) throws InvalidTypeException + { + NodeEntity node = new NodeEntity(); + // Store + node.setStore(store); + // UUID + if (uuid == null) + { + node.setUuid(GUID.generate()); + } + else + { + node.setUuid(uuid); + } + // QName + Long typeQNameId = qnameDAO.getOrCreateQName(nodeTypeQName).getFirst(); + node.setTypeQNameId(typeQNameId); + // ACL (may be null) + node.setAclId(aclId); + // Deleted + node.setDeleted(deleted); + // Transaction + TransactionEntity txn = getCurrentTransaction(); + node.setTransaction(txn); + + Set nodeAspects = null; + + // Audit + if (auditableProps != null) + { + // Client-supplied cm:auditable values + node.setAuditableProperties(auditableProps); + + nodeAspects = Collections.singleton(ContentModel.ASPECT_AUDITABLE); + } + else if (AuditablePropertiesEntity.hasAuditableAspect(nodeTypeQName, dictionaryService)) + { + // Automatically-generated cm:auditable values + auditableProps = new AuditablePropertiesEntity(); + auditableProps.setAuditValues(null, null, true, 0L); + node.setAuditableProperties(auditableProps); + + nodeAspects = Collections.singleton(ContentModel.ASPECT_AUDITABLE); + } + else + { + nodeAspects = Collections.emptySet(); + } + + Long id = null; + try + { + // First try a straight insert and risk the constraint violation if the node exists + id = insertNode(node); + } + catch (Throwable e) + { + // This is probably because there is an existing node. We can handle existing deleted nodes. + NodeRef targetNodeRef = node.getNodeRef(); + NodeEntity deletedNode = selectNodeByNodeRef(targetNodeRef, true); // Only look for deleted nodes + if (deletedNode != null) + { + Long deletedNodeId = deletedNode.getId(); + deleteNodeById(deletedNodeId, true); + // Now repeat, but let any further problems just be thrown out + id = insertNode(node); + } + else + { + throw new AlfrescoRuntimeException("Failed to insert new node: " + node, e); + } + } + node.setId(id); + + // Lock the node and cache + node.lock(); + nodesCache.setValue(id, node); + // Pre-populate some of the other caches so that we don't immediately query + setNodeAspectsCached(id, nodeAspects); + setNodePropertiesCached(id, Collections.emptyMap()); + + if (isDebugEnabled) + { + logger.debug("Created new node: \n" + " " + node); + } + return node; + } + + public Pair moveNode( + final Long childNodeId, + final Long newParentNodeId, + final QName assocTypeQName, + final QName assocQName) + { + final Node newParentNode = getNodeNotNull(newParentNodeId); + final StoreEntity newParentStore = newParentNode.getStore(); + final Node childNode = getNodeNotNull(childNodeId); + final StoreEntity childStore = childNode.getStore(); + ChildAssocEntity primaryParentAssoc = getPrimaryParentAssocImpl(childNodeId); + final Long oldParentNodeId; + if(primaryParentAssoc == null) + { + oldParentNodeId = null; + } + else + { + if(primaryParentAssoc.getParentNode() == null) + { + oldParentNodeId = null; + } + else + { + oldParentNodeId = primaryParentAssoc.getParentNode().getId(); + } + } + + + // Now update the primary parent assoc + RetryingCallback callback = new RetryingCallback() + { + public Integer execute() throws Throwable + { + // We use the child node's UUID if there is no cm:name + String childNodeName = (String) getNodeProperty(childNodeId, ContentModel.PROP_NAME); + if (childNodeName == null) + { + childNodeName = childNode.getUuid(); + } + + try + { + return updatePrimaryParentAssocs( + childNodeId, + newParentNodeId, + assocTypeQName, + assocQName, + childNodeName); + } + catch (Throwable e) + { + // We assume that this is from the child cm:name constraint violation + throw new DuplicateChildNodeNameException( + newParentNode.getNodeRef(), + assocTypeQName, + childNodeName); + } + } + }; + Integer updateCount = childAssocRetryingHelper.doWithRetry(callback); + if (updateCount > 0) + { + NodeUpdateEntity nodeUpdate = new NodeUpdateEntity(); + // ID + nodeUpdate.setId(childNodeId); + // Store + if (!childStore.getId().equals(newParentStore.getId())) + { + nodeUpdate.setStore(newParentNode.getStore()); + nodeUpdate.setUpdateStore(true); + } + + // Update. This takes care of the store move, auditable and transaction + updateNodeImpl(childNode, nodeUpdate); + + // Clear out parent assocs cache + invalidateCachesByNodeId(null, childNodeId, parentAssocsCache); + + // Check that there is not a cyclic relationship + getPaths(nodeUpdate.getNodePair(), false); + + // Update ACLs for moved tree + accessControlListDAO.updateInheritance(childNodeId, oldParentNodeId, newParentNodeId); + } + else + { + // Clear out parent assocs cache + invalidateCachesByNodeId(null, childNodeId, parentAssocsCache); + } + + Pair assocPair = getPrimaryParentAssoc(childNodeId); + + // Done + if (isDebugEnabled) + { + logger.debug("Moved node: " + assocPair); + } + return assocPair; + } + + public void updateNode(Long nodeId, StoreRef storeRef, String uuid, QName nodeTypeQName) + { + // Get the existing node; we need to check for a change in store or UUID + Node oldNode = getNodeNotNull(nodeId); + // Use existing values, where necessary + if (storeRef == null) + { + storeRef = oldNode.getStore().getStoreRef(); + } + if (uuid == null) + { + uuid = oldNode.getUuid(); + } + if (nodeTypeQName == null) + { + Long nodeTypeQNameId = oldNode.getTypeQNameId(); + nodeTypeQName = qnameDAO.getQName(nodeTypeQNameId).getSecond(); + } + + // Wrap all the updates into one + NodeUpdateEntity nodeUpdate = new NodeUpdateEntity(); + nodeUpdate.setId(nodeId); + // Store (if necessary) + if (!storeRef.equals(oldNode.getStore().getStoreRef())) + { + StoreEntity store = getStoreNotNull(storeRef); + nodeUpdate.setStore(store); + nodeUpdate.setUpdateStore(true); + } + else + { + nodeUpdate.setStore(oldNode.getStore()); // Need node reference + } + // UUID (if necessary) + if (!uuid.equals(oldNode.getUuid())) + { + nodeUpdate.setUuid(uuid); + nodeUpdate.setUpdateUuid(true); + } + else + { + nodeUpdate.setUuid(oldNode.getUuid()); // Need node reference + } + // TypeQName (if necessary) + Long nodeTypeQNameId = qnameDAO.getOrCreateQName(nodeTypeQName).getFirst(); + if (!nodeTypeQNameId.equals(oldNode.getTypeQNameId())) + { + nodeUpdate.setTypeQNameId(nodeTypeQNameId); + nodeUpdate.setUpdateTypeQNameId(true); + } + + updateNodeImpl(oldNode, nodeUpdate); + } + + /** + * Updates the node's transaction and cm:auditable properties only. + * + * @see #updateNodeImpl(NodeEntity, NodeUpdateEntity) + */ + private void touchNodeImpl(Long nodeId) + { + Node node = null; + try + { + node = getNodeNotNull(nodeId); + } + catch (DataIntegrityViolationException e) + { + // The ID doesn't reference a live node. + // We do nothing w.r.t. touching + return; + } + NodeUpdateEntity nodeUpdate = new NodeUpdateEntity(); + nodeUpdate.setId(nodeId); + updateNodeImpl(node, nodeUpdate); + } + + /** + * Helper method that updates the node, bringing it into the current transaction with + * the appropriate cm:auditable and transaction behaviour. + *

+ * If the NodeRef of the node is changing (usually a store move) then deleted + * nodes are cleaned out where they might exist. + * + * @param oldNode the existing node, fully populated + * @param nodeUpdate the node update with all update elements populated + */ + private void updateNodeImpl(Node oldNode, NodeUpdateEntity nodeUpdate) + { + Long nodeId = oldNode.getId(); + + // Make sure that the ID has been populated + if (!EqualsHelper.nullSafeEquals(nodeId, nodeUpdate.getId())) + { + throw new IllegalArgumentException("NodeUpdateEntity node ID is not correct: " + nodeUpdate); + } + + // Copy the Store and UUID to the updated node, but leave the update flags. + // The NodeRef may be required when resolving the duplicate NodeRef issues. + if (!nodeUpdate.isUpdateStore()) + { + nodeUpdate.setStore(oldNode.getStore()); + } + if (!nodeUpdate.isUpdateUuid()) + { + nodeUpdate.setUuid(oldNode.getUuid()); + } + // Ensure that other values are set for completeness when caching + if (!nodeUpdate.isUpdateTypeQNameId()) + { + nodeUpdate.setTypeQNameId(oldNode.getTypeQNameId()); + } + if (!nodeUpdate.isUpdateAclId()) + { + nodeUpdate.setAclId(oldNode.getAclId()); + } + if (!nodeUpdate.isUpdateDeleted()) + { + nodeUpdate.setDeleted(oldNode.getDeleted()); + } + + // Check the update values of the reference elements + boolean updateReference = nodeUpdate.isUpdateStore() || nodeUpdate.isUpdateUuid(); + + nodeUpdate.setVersion(oldNode.getVersion()); + // Update the transaction + TransactionEntity txn = getCurrentTransaction(); + nodeUpdate.setTransaction(txn); + if (!txn.getId().equals(oldNode.getTransaction().getId())) + { + // Only update if the txn has changed + nodeUpdate.setUpdateTransaction(true); + } + // Update auditable + Set nodeAspects = getNodeAspects(nodeId); + if (nodeAspects.contains(ContentModel.ASPECT_AUDITABLE)) + { + NodeRef oldNodeRef = oldNode.getNodeRef(); + if (policyBehaviourFilter.isEnabled(oldNodeRef, ContentModel.ASPECT_AUDITABLE)) + { + // Make sure that auditable properties are present + AuditablePropertiesEntity auditableProps = oldNode.getAuditableProperties(); + if (auditableProps == null) + { + auditableProps = new AuditablePropertiesEntity(); + } + boolean updateAuditableProperties = auditableProps.setAuditValues(null, null, false, 1000L); + nodeUpdate.setAuditableProperties(auditableProps); + nodeUpdate.setUpdateAuditableProperties(updateAuditableProperties); + } + else + { + // else: The auditable aspect is manual, so we expect the client code to have done + // the necessary updates on the 'nodeUpdate' + + // cache the explicit setting of auditable properties when creating node (note: auditable aspect is not yet present) + AuditablePropertiesEntity auditableProps = oldNode.getAuditableProperties(); + if (auditableProps != null) + { + nodeUpdate.setAuditableProperties(auditableProps); + } + } + } + else + { + // Make sure that any auditable properties are removed + AuditablePropertiesEntity auditableProps = oldNode.getAuditableProperties(); + if (auditableProps != null) + { + nodeUpdate.setAuditableProperties(null); + nodeUpdate.setUpdateAuditableProperties(true); + } + } + + // Just bug out if nothing has changed + if (!nodeUpdate.isUpdateAnything()) + { + return; + } + + // Do the update + int count = 0; + try + { + count = updateNode(nodeUpdate); + } + catch (Throwable e) + { + NodeRef targetNodeRef = nodeUpdate.getNodeRef(); + // Wipe the node ID from the caches just in case we have stale caches + // The TransactionalCache will propagate removals to the shared cache on rollback + nodesCache.removeByKey(nodeId); + nodesCache.removeByValue(nodeUpdate); + + if (updateReference) + { + // This is the first error. Clean out deleted nodes that might be in the way and + // move away live nodes. + try + { + // Look for live nodes first as they will leave a trail of deleted nodes + // that we will have to deal with subsequently. + NodeEntity liveNode = selectNodeByNodeRef(targetNodeRef, false); // Only look for live nodes + if (liveNode != null) + { + Long liveNodeId = liveNode.getId(); + String liveNodeUuid = GUID.generate(); + updateNode(liveNodeId, null, liveNodeUuid, null); + } + NodeEntity deletedNode = selectNodeByNodeRef(targetNodeRef, true); // Only look for deleted nodes + if (deletedNode != null) + { + Long deletedNodeId = deletedNode.getId(); + deleteNodeById(deletedNodeId, true); + } + if (isDebugEnabled) + { + logger.debug("Cleaned up target references for reference update: " + targetNodeRef); + } + } + catch (Throwable ee) + { + // We don't want to mask the original problem + logger.error("Failed to clean up target nodes for new reference: " + targetNodeRef, ee); + throw new RuntimeException("Failed to update node:" + nodeUpdate, e); + } + // Now repeat + try + { + // The version number will have been incremented. Undo that. + nodeUpdate.setVersion(nodeUpdate.getVersion() - 1L); + count = updateNode(nodeUpdate); + } + catch (Throwable ee) + { + throw new RuntimeException("Failed to update Node: " + nodeUpdate, e); + } + } + else // There is no reference change, so the error must just be propagated + { + throw new RuntimeException("Failed to update Node: " + nodeUpdate, e); + } + } + // Do concurrency check + if (count != 1) + { + // Drop the value from the cache in case the cache is stale + nodesCache.removeByKey(nodeId); + nodesCache.removeByValue(nodeUpdate); + + throw new ConcurrencyFailureException("Failed to update node " + nodeId); + } + + // We need to leave a trail of deleted nodes + if (updateReference) + { + StoreEntity oldStore = oldNode.getStore(); + String oldUuid = oldNode.getUuid(); + newNodeImpl(oldStore, oldUuid, ContentModel.TYPE_CMOBJECT, null, true, null); + } + + // Update the caches + nodeUpdate.lock(); + nodesCache.setValue(nodeId, nodeUpdate); + if (updateReference || nodeUpdate.isUpdateTypeQNameId()) + { + // The association references will all be wrong + invalidateCachesByNodeId(nodeId, nodeId, parentAssocsCache); + } + + // Done + if (isDebugEnabled) + { + logger.debug( + "Updated Node: \n" + + " OLD: " + oldNode + "\n" + + " NEW: " + nodeUpdate); + } + } + + public void setNodeAclId(Long nodeId, Long aclId) + { + Node oldNode = getNodeNotNull(nodeId); + NodeUpdateEntity nodeUpdateEntity = new NodeUpdateEntity(); + nodeUpdateEntity.setId(nodeId); + nodeUpdateEntity.setAclId(aclId); + nodeUpdateEntity.setUpdateAclId(true); + updateNodeImpl(oldNode, nodeUpdateEntity); + } + + public void setPrimaryChildrenSharedAclId( + Long primaryParentNodeId, + Long optionalOldSharedAlcIdInAdditionToNull, + Long newSharedAclId) + { + updatePrimaryChildrenSharedAclId(primaryParentNodeId, optionalOldSharedAlcIdInAdditionToNull, newSharedAclId); + invalidateCachesByNodeId(primaryParentNodeId, null, nodesCache); + } + + public void deleteNode(Long nodeId) + { + Node node = getNodeNotNull(nodeId); + Long aclId = node.getAclId(); // Need this later + + // Clean up content data + Set contentQNames = new HashSet(dictionaryService.getAllProperties(DataTypeDefinition.CONTENT)); + Set contentQNamesToRemoveIds = qnameDAO.convertQNamesToIds(contentQNames, false); + contentDataDAO.deleteContentDataForNode(nodeId, contentQNamesToRemoveIds); + + // Delete content usage deltas + usageDAO.deleteDeltas(nodeId); + + // Finally mark the node as deleted + NodeUpdateEntity nodeUpdate = new NodeUpdateEntity(); + nodeUpdate.setId(nodeId); + // Version + nodeUpdate.setVersion(node.getVersion()); + // Transaction + TransactionEntity txn = getCurrentTransaction(); + nodeUpdate.setTransaction(txn); + nodeUpdate.setUpdateTransaction(true); + // ACL + nodeUpdate.setAclId(null); + nodeUpdate.setUpdateAclId(true); + // Deleted + nodeUpdate.setDeleted(true); + nodeUpdate.setUpdateDeleted(true); + + // Update cm:auditable + Set nodeAspects = getNodeAspects(nodeId); + if (nodeAspects.contains(ContentModel.ASPECT_AUDITABLE)) + { + AuditablePropertiesEntity auditableProps = node.getAuditableProperties(); + if (auditableProps == null) + { + auditableProps = new AuditablePropertiesEntity(); + } + auditableProps.setAuditValues(null, null, false, 1000L); + nodeUpdate.setAuditableProperties(auditableProps); + nodeUpdate.setUpdateAuditableProperties(true); + } + + // Remove value from the cache + nodesCache.removeByKey(nodeId); + + // Remove aspects + deleteNodeAspects(nodeId, null); + aspectsCache.removeByKey(nodeId); + + // Remove properties + deleteNodeProperties(nodeId, (Set) null); + propertiesCache.removeByKey(nodeId); + + // Remove associations + invalidateCachesByNodeId(nodeId, nodeId, parentAssocsCache); + deleteNodeAssocsToAndFrom(nodeId); + deleteChildAssocsToAndFrom(nodeId); + + int count = updateNode(nodeUpdate); + if (count != 1) + { + // Drop cached values in case of stale cache data + nodesCache.removeByValue(node); + + throw new ConcurrencyFailureException("Failed to update node: " + nodeUpdate); + } + + // Remove ACLs + if (aclId != null) + { + aclDAO.deleteAclForNode(aclId, false); + } + } + + public void purgeNode(Long nodeId) + { + int count = deleteNodeById(nodeId, true); + if (count != 1) + { + throw new ConcurrencyFailureException("Failed to purge node: " + nodeId); + } + } + + /* + * Node Properties + */ + + public Map getNodeProperties(Long nodeId) + { + Map props = getNodePropertiesCached(nodeId); + + Node node = getNodeNotNull(nodeId); + // Handle sys:referenceable + ReferenceablePropertiesEntity.addReferenceableProperties(node, props); + // Handle cm:auditable + if (hasNodeAspect(nodeId, ContentModel.ASPECT_AUDITABLE)) + { + AuditablePropertiesEntity auditableProperties = node.getAuditableProperties(); + if (auditableProperties == null) + { + auditableProperties = new AuditablePropertiesEntity(); + } + props.putAll(auditableProperties.getAuditableProperties()); + } + + // Done + if (isDebugEnabled) + { + logger.debug("Fetched properties for Node: \n" + + " Node: " + nodeId + "\n" + + " Props: " + props); + } + return props; + } + + public Serializable getNodeProperty(Long nodeId, QName propertyQName) + { + Serializable value = null; + // We have to load the node for cm:auditable + if (AuditablePropertiesEntity.isAuditableProperty(propertyQName)) + { + Node node = getNodeNotNull(nodeId); + AuditablePropertiesEntity auditableProperties = node.getAuditableProperties(); + if (auditableProperties != null) + { + value = auditableProperties.getAuditableProperty(propertyQName); + } + } + else if (ReferenceablePropertiesEntity.isReferenceableProperty(propertyQName)) // sys:referenceable + { + Node node = getNodeNotNull(nodeId); + value = ReferenceablePropertiesEntity.getReferenceableProperty(node, propertyQName); + } + else + { + Map props = getNodePropertiesCached(nodeId); + value = props.get(propertyQName); + } + // Done + if (isDebugEnabled) + { + logger.debug("Fetched property for Node: \n" + + " Node: " + nodeId + "\n" + + " QName: " + propertyQName + "\n" + + " Value: " + value); + } + return value; + } + + /** + * Does differencing to add and/or remove properties. Internally, the existing properties + * will be retrieved and a difference performed to work out which properties need to be + * created, updated or deleted. It is only necessary to pass in old and new values for + * changes i.e. when setting a single property, it is only necessary to pass that + * property's value in the old and new maps; this improves execution speed + * significantly - although it has no effect on the number of resulting DB operations. + *

+ * Note: The cached properties are not updated + * + * @param nodeId the node ID + * @param newProps the properties to add or update + * @param isAddOnly true if the new properties are just an update or + * false if the properties are a complete set + * @return Returns true if any properties were changed + */ + private boolean setNodePropertiesImpl(Long nodeId, + Map newProps, + boolean isAddOnly) + { + Node node = getNodeNotNull(nodeId); + // Copy inbound values + newProps = new HashMap(newProps); + // Remove cm:auditable + newProps.keySet().removeAll(AuditablePropertiesEntity.getAuditablePropertyQNames()); + // Remove sys:referenceable + ReferenceablePropertiesEntity.removeReferenceableProperties(node, newProps); + + // Determine which properties we are interested in. For addition of properties, we only + // need the old properties for the QNames being added. For complete setting of properties, + // we need the full set of old properties. + Map oldPropsRaw = selectNodeProperties(nodeId); + Set qnameIdsOfInterest = qnameDAO.convertQNamesToIds(newProps.keySet(), true); + + // Get new property raw values + Map newPropsRaw = nodePropertyHelper.convertToPersistentProperties(newProps); + + // Copy for modification + Map propsToDelete = new HashMap(oldPropsRaw); + Map propsToAdd = new HashMap(newPropsRaw); + + // Compare these fine-grained properties + Map persistableDiff = EqualsHelper.getMapComparison( + propsToDelete, + propsToAdd); + // Add or remove properties as we go + for (Map.Entry entry : persistableDiff.entrySet()) + { + NodePropertyKey key = entry.getKey(); + + QName qname = qnameDAO.getQName(key.getQnameId()).getSecond(); + + PropertyDefinition removePropDef = dictionaryService.getProperty(qname); + boolean isContent = (removePropDef != null && + removePropDef.getDataType().getName().equals(DataTypeDefinition.CONTENT)); + + switch (entry.getValue()) + { + case NULL: + case EQUAL: + // The entries are the same + propsToDelete.remove(key); + propsToAdd.remove(key); + continue; + case RIGHT_ONLY: + // Only in new props: add + propsToDelete.remove(key); + // Handle new content + if (isContent) + { + // The new value needs conversion to the ID-based ContentData reference + NodePropertyValue newPropValue = propsToAdd.get(key); + ContentData newContentData = (ContentData) newPropValue.getValue(DataTypeDefinition.CONTENT); + if (newContentData != null) + { + Long newContentDataId = contentDataDAO.createContentData(newContentData).getFirst(); + newPropValue = new NodePropertyValue(DataTypeDefinition.CONTENT, newContentDataId); + propsToAdd.put(key, newPropValue); + } + } + continue; + case LEFT_ONLY: + // Only present in old props: must not be added + propsToAdd.remove(key); + // Handle the fact that this might be a QName we are not interested in + if (isAddOnly && !qnameIdsOfInterest.contains(key.getQnameId())) + { + // We are adding properties and this is not a property type of interest + propsToDelete.remove(key); + continue; + } + // Handle deleted content + if (isContent) + { + // The old values will be an ID-based ContentData reference + NodePropertyValue valueToDelete = propsToDelete.get(key); + Long contentDataId = (Long) valueToDelete.getValue(DataTypeDefinition.CONTENT); + if (contentDataId != null) + { + contentDataDAO.deleteContentData(contentDataId); + } + } + continue; + // Fall through for content dereferencing + case NOT_EQUAL: + // Value has changed: remove and add + // Handle changed content. We may have equal ContentData values here but the ID-ContentData + // mix will always turn up NOT_EQUAL, hence the double-check + if (isContent) + { + // The old values will be an ID-based ContentData reference + NodePropertyValue valueToDelete = propsToDelete.get(key); + Long contentDataIdToDelete = (Long) valueToDelete.getValue(DataTypeDefinition.CONTENT); + ContentData contentDataToDelete = + (contentDataIdToDelete == null) + ? null + : contentDataDAO.getContentData(contentDataIdToDelete).getSecond(); + // The new value will NOT be an ID-based reference + NodePropertyValue newPropValue = propsToAdd.get(key); + ContentData newContentData = (ContentData) newPropValue.getValue(DataTypeDefinition.CONTENT); + // Are they actually different? + if (EqualsHelper.nullSafeEquals(contentDataToDelete, newContentData)) + { + // The are the same, so don't do anything + propsToDelete.remove(key); + propsToAdd.remove(key); + } + else + { + // The ContentData values are different + if (contentDataIdToDelete != null) + { + contentDataDAO.deleteContentData(contentDataIdToDelete); + } + if (newContentData != null) + { + Long newContentDataId = contentDataDAO.createContentData(newContentData).getFirst(); + newPropValue = new NodePropertyValue(DataTypeDefinition.CONTENT, newContentDataId); + propsToAdd.put(key, newPropValue); + } + } + } + continue; + default: + throw new IllegalStateException("Unknown MapValueComparison: " + entry.getValue()); + } + } + + // Shortcut if there are no diffs + if (propsToDelete.isEmpty() && propsToAdd.isEmpty()) + { + return false; + } + + // Remove by key + List propKeysToDeleteList = new ArrayList(propsToDelete.keySet()); + deleteNodeProperties(nodeId, propKeysToDeleteList); + + try + { + // Add by key-value + insertNodeProperties(nodeId, propsToAdd); + } + catch (RuntimeException e) + { + // Don't trust the properties cache for the node + propertiesCache.removeByKey(nodeId); + throw e; + } + + boolean updated = propsToDelete.size() > 0 || propsToAdd.size() > 0; + + // Touch to bring into current txn + if (updated) + { + // Fix properties up w.r.t. types, etc + newProps = nodePropertyHelper.convertToPublicProperties(newPropsRaw); + // Build the properties to cache based on whether this is an append or replace + Map propsToCache = null; + if (isAddOnly) + { + // Combine the old and new properties + propsToCache = nodePropertyHelper.convertToPublicProperties(oldPropsRaw); + propsToCache.putAll(newProps); + } + else + { + // Replace old properties + propsToCache = newProps; + } + // Update cache + setNodePropertiesCached(nodeId, propsToCache); + // Touch to bring into current txn + touchNodeImpl(nodeId); + } + + // Done + if (isDebugEnabled && updated) + { + logger.debug( + "Modified node properties: " + nodeId + "\n" + + " Removed: " + propsToDelete + "\n" + + " Added: " + propsToAdd); + } + return updated; + } + + public boolean setNodeProperties(Long nodeId, Map properties) + { + // Merge with current values + boolean modified = setNodePropertiesImpl(nodeId, properties, false); + + // Done + return modified; + } + + public boolean addNodeProperty(Long nodeId, QName qname, Serializable value) + { + // Copy inbound values + Map newProps = new HashMap(3); + newProps.put(qname, value); + // Merge with current values + boolean modified = setNodePropertiesImpl(nodeId, newProps, true); + + // Done + return modified; + } + + public boolean addNodeProperties(Long nodeId, Map properties) + { + // Merge with current values + boolean modified = setNodePropertiesImpl(nodeId, properties, true); + + // Done + return modified; + } + + public boolean removeNodeProperties(Long nodeId, Set propertyQNames) + { + propertyQNames = new HashSet(propertyQNames); + ReferenceablePropertiesEntity.removeReferenceableProperties(propertyQNames); + if (propertyQNames.size() == 0) + { + return false; // sys:referenceable properties cannot be removed + } + Set qnameIds = qnameDAO.convertQNamesToIds(propertyQNames, false); + int deleteCount = deleteNodeProperties(nodeId, qnameIds); + + if (deleteCount > 0) + { + // Update cache + Map cachedProps = getNodePropertiesCached(nodeId); + cachedProps.keySet().removeAll(propertyQNames); + setNodePropertiesCached(nodeId, cachedProps); + // Touch to bring into current txn + touchNodeImpl(nodeId); + } + // Done + return deleteCount > 0; + } + + /** + * @return Returns a writable copy of the cached property map + */ + private Map getNodePropertiesCached(Long nodeId) + { + Pair> cacheEntry = propertiesCache.getByKey(nodeId); + if (cacheEntry == null) + { + throw new DataIntegrityViolationException("Invalid node ID: " + nodeId); + } + Map cachedProperties = cacheEntry.getSecond(); + Map properties = copyPropertiesAgainstModification(cachedProperties); + // Done + return properties; + } + + /** + * Update the node properties cache. The incoming properties will be wrapped to be + * unmodifiable. + *

+ * NOTE: Incoming properties must exclude the cm:auditable properties + */ + private void setNodePropertiesCached(Long nodeId, Map properties) + { + properties = copyPropertiesAgainstModification(properties); + propertiesCache.setValue(nodeId, Collections.unmodifiableMap(properties)); + } + + /** + * Shallow-copies to a new map except for maps and collections that are binary serialized + */ + private Map copyPropertiesAgainstModification(Map original) + { + // Copy the values, ensuring that any collections are copied as well + Map copy = new HashMap((int)(original.size() * 1.3)); + for (Map.Entry element : original.entrySet()) + { + QName key = element.getKey(); + Serializable value = element.getValue(); + if (value instanceof Collection || value instanceof Map) + { + value = (Serializable) SerializationUtils.deserialize(SerializationUtils.serialize(value)); + } + copy.put(key, value); + } + return copy; + } + + /** + * Callback to cache node properties. The DAO callback only does the simple {@link #findByKey(Long)}. + * + * @author Derek Hulley + * @since 3.4 + */ + private class PropertiesCallbackDAO extends EntityLookupCallbackDAOAdaptor, Serializable> + { + public Pair> createValue(Map value) + { + throw new UnsupportedOperationException("A node always has a 'map' of properties."); + } + + public Pair> findByKey(Long nodeId) + { + Map propsRaw = selectNodeProperties(nodeId); + // Convert to public properties + Map props = nodePropertyHelper.convertToPublicProperties(propsRaw); + // Done + return new Pair>(nodeId, Collections.unmodifiableMap(props)); + } + } + + /* + * Aspects + */ + + public Set getNodeAspects(Long nodeId) + { + Set nodeAspects = getNodeAspectsCached(nodeId); + // Nodes are always referenceable + nodeAspects.add(ContentModel.ASPECT_REFERENCEABLE); + return nodeAspects; + } + + public boolean hasNodeAspect(Long nodeId, QName aspectQName) + { + if (aspectQName.equals(ContentModel.ASPECT_REFERENCEABLE)) + { + // Nodes are always referenceable + return true; + } + Set nodeAspects = getNodeAspectsCached(nodeId); + return nodeAspects.contains(aspectQName); + } + + public boolean addNodeAspects(Long nodeId, Set aspectQNames) + { + // Copy the inbound set + Set aspectQNamesToAdd = new HashSet(aspectQNames); + // Get existing + Set existingAspectQNames = getNodeAspectsCached(nodeId); + // Find out what needs adding + aspectQNamesToAdd.removeAll(existingAspectQNames); + aspectQNamesToAdd.remove(ContentModel.ASPECT_REFERENCEABLE); // Implicit + if (aspectQNamesToAdd.isEmpty()) + { + // Nothing to do + return false; + } + // Add them + Set aspectQNameIds = qnameDAO.convertQNamesToIds(aspectQNamesToAdd, true); + startBatch(); + try + { + for (Long aspectQNameId : aspectQNameIds) + { + insertNodeAspect(nodeId, aspectQNameId); + } + } + catch (RuntimeException e) + { + // This could be because the cache is out of date + aspectsCache.deleteByKey(nodeId); + throw e; + } + finally + { + executeBatch(); + } + // Manually update the cache + Set newAspectQNames = new HashSet(existingAspectQNames); + newAspectQNames.addAll(aspectQNamesToAdd); + setNodeAspectsCached(nodeId, newAspectQNames); + + // If we are adding the sys:aspect_root, then the parent assocs cache is unreliable + if (newAspectQNames.contains(ContentModel.ASPECT_ROOT)) + { + invalidateCachesByNodeId(null, nodeId, parentAssocsCache); + } + + // Touch to bring into current txn + touchNodeImpl(nodeId); + + // Done + return true; + } + + public boolean removeNodeAspects(Long nodeId) + { + // Get existing + Set existingAspectQNames = getNodeAspectsCached(nodeId); + // If we are removing the sys:aspect_root, then the parent assocs cache is unreliable + if (existingAspectQNames.contains(ContentModel.ASPECT_ROOT)) + { + invalidateCachesByNodeId(null, nodeId, parentAssocsCache); + } + + // Just delete all the node's aspects + int deleteCount = deleteNodeAspects(nodeId, null); + // Manually update the cache + aspectsCache.setValue(nodeId, Collections.emptySet()); + + // Touch to bring into current txn + touchNodeImpl(nodeId); + + // Done + return deleteCount > 0; + } + + public boolean removeNodeAspects(Long nodeId, Set aspectQNames) + { + // Get the current aspects + Set existingAspectQNames = getNodeAspects(nodeId); + // Now remove each aspect + Set aspectQNameIdsToRemove = qnameDAO.convertQNamesToIds(aspectQNames, false); + int deleteCount = deleteNodeAspects(nodeId, aspectQNameIdsToRemove); + + // Manually update the cache + Set newAspectQNames = new HashSet(existingAspectQNames); + newAspectQNames.removeAll(aspectQNames); + aspectsCache.setValue(nodeId, newAspectQNames); + + // If we are removing the sys:aspect_root, then the parent assocs cache is unreliable + if (aspectQNames.contains(ContentModel.ASPECT_ROOT)) + { + invalidateCachesByNodeId(null, nodeId, parentAssocsCache); + } + + // Touch to bring into current txn + touchNodeImpl(nodeId); + + // Done + return deleteCount > 0; + } + + public void getNodesWithAspect(QName aspectQName, Long minNodeId, int count, NodeRefQueryCallback resultsCallback) + { + Pair qnamePair = qnameDAO.getQName(aspectQName); + if (qnamePair == null) + { + // No point running a query + return; + } + Long qnameId = qnamePair.getFirst(); + selectNodesWithAspect(qnameId, minNodeId, resultsCallback); + } + + /** + * @return Returns a writable copy of the cached aspects set + */ + private Set getNodeAspectsCached(Long nodeId) + { + Pair> cacheEntry = aspectsCache.getByKey(nodeId); + if (cacheEntry == null) + { + throw new DataIntegrityViolationException("Invalid node ID: " + nodeId); + } + return new HashSet(cacheEntry.getSecond()); + } + + /** + * Update the node aspects cache. The incoming set will be wrapped to be unmodifiable. + */ + private void setNodeAspectsCached(Long nodeId, Set aspects) + { + aspectsCache.setValue(nodeId, Collections.unmodifiableSet(aspects)); + } + + /** + * Callback to cache node aspects. The DAO callback only does the simple {@link #findByKey(Long)}. + * + * @author Derek Hulley + * @since 3.4 + */ + private class AspectsCallbackDAO extends EntityLookupCallbackDAOAdaptor, Serializable> + { + public Pair> createValue(Set value) + { + throw new UnsupportedOperationException("A node always has a 'set' of aspects."); + } + + public Pair> findByKey(Long nodeId) + { + Set nodeAspectQNameIds = selectNodeAspectIds(nodeId); + // Convert to QNames + Set nodeAspectQNames = qnameDAO.convertIdsToQNames(nodeAspectQNameIds); + // Done + return new Pair>(nodeId, Collections.unmodifiableSet(nodeAspectQNames)); + } + } + + /* + * Node assocs + */ + + public Long newNodeAssoc(Long sourceNodeId, Long targetNodeId, QName assocTypeQName) + { + Long assocTypeQNameId = qnameDAO.getOrCreateQName(assocTypeQName).getFirst(); + try + { + // Touch to bring into current txn + touchNodeImpl(sourceNodeId); + + return insertNodeAssoc(sourceNodeId, targetNodeId, assocTypeQNameId); + } + catch (Throwable e) + { + // Probably due to the association already existing. We throw a well-known + // exception and let retrying take itparameterObjects course + throw new AssociationExistsException(sourceNodeId, targetNodeId, assocTypeQName, e); + } + } + + public int removeNodeAssoc(Long sourceNodeId, Long targetNodeId, QName assocTypeQName) + { + Pair assocTypeQNamePair = qnameDAO.getQName(assocTypeQName); + if (assocTypeQNamePair == null) + { + // Never existed + return 0; + } + // Touch to bring into current txn + touchNodeImpl(sourceNodeId); + + Long assocTypeQNameId = assocTypeQNamePair.getFirst(); + return deleteNodeAssoc(sourceNodeId, targetNodeId, assocTypeQNameId); + } + + public int removeNodeAssocsToAndFrom(Long nodeId) + { + // Touch to bring into current txn + touchNodeImpl(nodeId); + + return deleteNodeAssocsToAndFrom(nodeId); + } + + public int removeNodeAssocsToAndFrom(Long nodeId, Set assocTypeQNames) + { + Set assocTypeQNameIds = qnameDAO.convertQNamesToIds(assocTypeQNames, false); + if (assocTypeQNameIds.size() == 0) + { + // Never existed + return 0; + } + // Touch to bring into current txn + touchNodeImpl(nodeId); + + return deleteNodeAssocsToAndFrom(nodeId, assocTypeQNameIds); + } + + public Collection> getSourceNodeAssocs(Long targetNodeId) + { + List nodeAssocEntities = selectNodeAssocsByTarget(targetNodeId); + List> results = new ArrayList>(nodeAssocEntities.size()); + for (NodeAssocEntity nodeAssocEntity : nodeAssocEntities) + { + Long assocId = nodeAssocEntity.getId(); + QName assocTypeQName = qnameDAO.getQName(nodeAssocEntity.getTypeQNameId()).getSecond(); + AssociationRef assocRef = new AssociationRef( + nodeAssocEntity.getId(), + nodeAssocEntity.getSourceNode().getNodeRef(), + assocTypeQName, + nodeAssocEntity.getTargetNode().getNodeRef()); + results.add(new Pair(assocId, assocRef)); + } + return results; + } + + public Collection> getTargetNodeAssocs(Long sourceNodeId) + { + List nodeAssocEntities = selectNodeAssocsBySource(sourceNodeId); + List> results = new ArrayList>(nodeAssocEntities.size()); + for (NodeAssocEntity nodeAssocEntity : nodeAssocEntities) + { + Long assocId = nodeAssocEntity.getId(); + QName assocTypeQName = qnameDAO.getQName(nodeAssocEntity.getTypeQNameId()).getSecond(); + AssociationRef assocRef = new AssociationRef( + nodeAssocEntity.getId(), + nodeAssocEntity.getSourceNode().getNodeRef(), + assocTypeQName, + nodeAssocEntity.getTargetNode().getNodeRef()); + results.add(new Pair(assocId, assocRef)); + } + return results; + } + + /* + * Child assocs + */ + + private ChildAssocEntity newChildAssocImpl( + Long parentNodeId, + Long childNodeId, + boolean isPrimary, + final QName assocTypeQName, + QName assocQName, + final String childNodeName) + { + Assert.notNull(parentNodeId, "parentNodeId"); + Assert.notNull(childNodeId, "childNodeId"); + Assert.notNull(assocTypeQName, "assocTypeQName"); + Assert.notNull(assocQName, "assocQName"); + Assert.notNull(childNodeName, "childNodeName"); + + // Get parent and child nodes. We need them later, so just get them now. + final Node parentNode = getNodeNotNull(parentNodeId); + final Node childNode = getNodeNotNull(childNodeId); + + final ChildAssocEntity assoc = new ChildAssocEntity(); + // Parent node + assoc.setParentNode(new NodeEntity(parentNode)); + // Child node + assoc.setChildNode(new NodeEntity(childNode)); + // Type QName + assoc.setTypeQNameAll(qnameDAO, assocTypeQName, true); + // Child node name + assoc.setChildNodeNameAll(dictionaryService, assocTypeQName, childNodeName); + // QName + assoc.setQNameAll(qnameDAO, assocQName, true); + // Primary + assoc.setPrimary(isPrimary); + // Index + assoc.setAssocIndex(-1); + + RetryingCallback callback = new RetryingCallback() + { + public Long execute() throws Throwable + { + try + { + return insertChildAssoc(assoc); + } + catch (Throwable e) + { + // We assume that this is from the child cm:name constraint violation + throw new DuplicateChildNodeNameException( + parentNode.getNodeRef(), + assocTypeQName, + childNodeName); + } + } + }; + Long assocId = childAssocRetryingHelper.doWithRetry(callback); + // Persist it + assoc.setId(assocId); + + // Primary associations accompany new nodes, so we only have to bring the + // node into the current transaction for secondary associations + if (!isPrimary) + { + updateNode(childNodeId, null, null, null); + } + + // Done + if (isDebugEnabled) + { + logger.debug("Created child association: " + assoc); + } + return assoc; + } + + public Pair newChildAssoc( + Long parentNodeId, + Long childNodeId, + QName assocTypeQName, + QName assocQName, + String childNodeName) + { + ChildAssocEntity assoc = newChildAssocImpl( + parentNodeId, childNodeId, false, assocTypeQName, assocQName, childNodeName); + Long assocId = assoc.getId(); + // update cache + ParentAssocsInfo parentAssocInfo = getParentAssocsCached(childNodeId); + parentAssocInfo = parentAssocInfo.addAssoc(assocId, assoc); + setParentAssocsCached(childNodeId, parentAssocInfo); + // Done + return assoc.getPair(qnameDAO); + } + + public void deleteChildAssoc(Long assocId) + { + ChildAssocEntity assoc = selectChildAssoc(assocId); + if (assoc == null) + { + throw new ConcurrencyFailureException("Child association not found: " + assocId); + } + // Update cache + Long childNodeId = assoc.getChildNode().getId(); + ParentAssocsInfo parentAssocInfo = getParentAssocsCached(childNodeId); + parentAssocInfo = parentAssocInfo.removeAssoc(assocId); + setParentAssocsCached(childNodeId, parentAssocInfo); + // Delete it + int count = deleteChildAssocById(assocId); + if (count != 1) + { + throw new ConcurrencyFailureException("Child association not deleted: " + assocId); + } + } + + public int setChildAssocIndex(Long parentNodeId, Long childNodeId, QName assocTypeQName, QName assocQName, int index) + { + int count = updateChildAssocIndex(parentNodeId, childNodeId, assocTypeQName, assocQName, index); + if (count > 0) + { + invalidateCachesByNodeId(null, childNodeId, parentAssocsCache); + } + return count; + } + + /** + * TODO: See about pulling automatic cm:name update logic into this DAO + */ + public void setChildAssocsUniqueName(final Long childNodeId, final String childName) + { + RetryingCallback callback = new RetryingCallback() + { + public Integer execute() throws Throwable + { + try + { + return updateChildAssocsUniqueName(childNodeId, childName); + } + catch (Throwable e) + { + // We assume that this is from the child cm:name constraint violation + throw new DuplicateChildNodeNameException(null, null, childName); + } + } + }; + Integer count = childAssocRetryingHelper.doWithRetry(callback); + if (count > 0) + { + invalidateCachesByNodeId(null, childNodeId, parentAssocsCache); + } + + if (isDebugEnabled) + { + logger.debug( + "Updated cm:name to parent assocs: \n" + + " Node: " + childNodeId + "\n" + + " Name: " + childName + "\n" + + " Updated: " + count); + } + } + + public Pair getChildAssoc(Long assocId) + { + ChildAssocEntity assoc = selectChildAssoc(assocId); + if (assoc == null) + { + throw new ConcurrencyFailureException("Child association not found: " + assocId); + } + return assoc.getPair(qnameDAO); + } + + public List getPrimaryChildrenAcls(Long nodeId) + { + return selectPrimaryChildAcls(nodeId); + } + + public Pair getChildAssoc( + Long parentNodeId, + Long childNodeId, + QName assocTypeQName, + QName assocQName) + { + List assocs = selectChildAssoc(parentNodeId, childNodeId, assocTypeQName, assocQName); + if (assocs.size() == 0) + { + return null; + } + else if (assocs.size() == 1) + { + return assocs.get(0).getPair(qnameDAO); + } + // Keep the primary association or, if there isn't one, the association with the smallest ID + Map assocsToDeleteById = new HashMap(assocs.size() * 2); + Long minId = null; + Long primaryId = null; + for (ChildAssocEntity assoc : assocs) + { + // First store it + Long assocId = assoc.getId(); + assocsToDeleteById.put(assocId, assoc); + if (minId == null || minId.compareTo(assocId) > 0) + { + minId = assocId; + } + if (assoc.isPrimary()) + { + primaryId = assocId; + } + } + // Remove either the primary or min assoc + Long assocToKeepId = primaryId == null ? minId : primaryId; + ChildAssocEntity assocToKeep = assocsToDeleteById.remove(assocToKeepId); + // If the current transaction allows, remove the other associations + if (AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_WRITE) + { + for (Long assocIdToDelete : assocsToDeleteById.keySet()) + { + deleteChildAssoc(assocIdToDelete); + } + } + // Done + return assocToKeep.getPair(qnameDAO); + } + + public void getChildAssocs( + Long parentNodeId, + Long childNodeId, + QName assocTypeQName, + QName assocQName, + Boolean isPrimary, + Boolean sameStore, + ChildAssocRefQueryCallback resultsCallback) + { + selectChildAssocs( + parentNodeId, childNodeId, + assocTypeQName, assocQName, isPrimary, sameStore, + resultsCallback); + } + + public void getChildAssocs(Long parentNodeId, Set assocTypeQNames, ChildAssocRefQueryCallback resultsCallback) + { + switch (assocTypeQNames.size()) + { + case 0: + return; // No results possible + case 1: + QName assocTypeQName = assocTypeQNames.iterator().next(); + selectChildAssocs(parentNodeId, null, assocTypeQName, (QName) null, null, null, resultsCallback); + break; + default: + selectChildAssocs(parentNodeId, assocTypeQNames, resultsCallback); + } + } + + public Pair getChildAssoc(Long parentNodeId, QName assocTypeQName, String childName) + { + ChildAssocEntity assoc = selectChildAssoc(parentNodeId, assocTypeQName, childName); + return assoc == null ? null : assoc.getPair(qnameDAO); + } + + public void getChildAssocs( + Long parentNodeId, + QName assocTypeQName, + Collection childNames, + ChildAssocRefQueryCallback resultsCallback) + { + selectChildAssocs(parentNodeId, assocTypeQName, childNames, resultsCallback); + } + + public void getChildAssocsByChildTypes( + Long parentNodeId, + Set childNodeTypeQNames, + ChildAssocRefQueryCallback resultsCallback) + { + selectChildAssocsByChildTypes(parentNodeId, childNodeTypeQNames, resultsCallback); + } + + public void getChildAssocsWithoutParentAssocsOfType( + Long parentNodeId, + QName assocTypeQName, + ChildAssocRefQueryCallback resultsCallback) + { + selectChildAssocsWithoutParentAssocsOfType(parentNodeId, assocTypeQName, resultsCallback); + } + + public Pair getPrimaryParentAssoc(Long childNodeId) + { + ChildAssocEntity childAssocEntity = getPrimaryParentAssocImpl(childNodeId); + if(childAssocEntity == null) + { + return null; + } + else + { + return childAssocEntity.getPair(qnameDAO); + } + } + + private ChildAssocEntity getPrimaryParentAssocImpl(Long childNodeId) + { + ParentAssocsInfo parentAssocs = getParentAssocsCached(childNodeId); + return parentAssocs.getPrimaryParentAssoc(); + } + + public void getParentAssocs( + Long childNodeId, + QName assocTypeQName, + QName assocQName, + Boolean isPrimary, + ChildAssocRefQueryCallback resultsCallback) + { + // Do we go for the cache or do we have to query + if (assocTypeQName == null && assocQName == null && isPrimary == null) + { + ParentAssocsInfo parentAssocs = getParentAssocsCached(childNodeId); + for (ChildAssocEntity assoc : parentAssocs.getParentAssocs().values()) + { + resultsCallback.handle( + assoc.getPair(qnameDAO), + assoc.getParentNode().getNodePair(), + assoc.getChildNode().getNodePair()); + } + } + else + { + selectParentAssocs(childNodeId, assocTypeQName, assocQName, isPrimary, resultsCallback); + } + } + + public List getPaths(Pair nodePair, boolean primaryOnly) throws InvalidNodeRefException + { + // 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 assocIdStack = new Stack(); + + // call recursive method to sort it out + prependPaths(nodePair, null, currentPath, paths, assocIdStack, 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: " + nodePair); + } + + // done + if (loggerPaths.isDebugEnabled()) + { + StringBuilder sb = new StringBuilder(256); + if (primaryOnly) + { + sb.append("Primary paths"); + } + else + { + sb.append("Paths"); + } + sb.append(" for node ").append(nodePair); + for (Path path : paths) + { + sb.append("\n").append(" ").append(path); + } + loggerPaths.debug(sb); + } + return paths; + } + + /** + * Build the paths for a node + * + * @param currentNodePair the leave or child node to start with + * @param currentRootNodePair pass in null only + * @param currentPath an empty {@link Path} + * @param completedPaths completed paths i.e. the result + * @param assocIdStack a stack to detected cyclic relationships + * @param primaryOnly true to follow only primary parent associations + * @throws CyclicChildRelationshipException + */ + private void prependPaths( + Pair currentNodePair, + Pair currentRootNodePair, + Path currentPath, + Collection completedPaths, + Stack assocIdStack, + boolean primaryOnly) throws CyclicChildRelationshipException + { + Long currentNodeId = currentNodePair.getFirst(); + NodeRef currentNodeRef = currentNodePair.getSecond(); + + // Check if we have changed root nodes + StoreRef currentStoreRef = currentNodeRef.getStoreRef(); + if (currentRootNodePair == null || !currentStoreRef.equals(currentRootNodePair.getFirst())) + { + // We've changed stores + Pair rootNodePair = getRootNode(currentStoreRef); + currentRootNodePair = new Pair(currentStoreRef, rootNodePair.getSecond()); + } + + // get the parent associations of the given node + ParentAssocsInfo parentAssocInfo = getParentAssocsCached(currentNodeId); + + // does the node have parents + boolean hasParents = parentAssocInfo.getParentAssocs().size() > 0; + // does the current node have a root aspect? + + // look for a root. If we only want the primary root, then ignore all but the top-level root. + if (!(primaryOnly && hasParents) && parentAssocInfo.isRoot()) // exclude primary search with parents present + { + // create a one-sided assoc ref for the root node and prepend to the stack + // this effectively spoofs the fact that the current node is not below the root + // - we put this assoc in as the first assoc in the path must be a one-sided + // reference pointing to the root node + ChildAssociationRef assocRef = new ChildAssociationRef(null, null, null, currentRootNodePair.getSecond()); + // create a path to save and add the 'root' assoc + Path pathToSave = new Path(); + Path.ChildAssocElement first = null; + for (Path.Element element : currentPath) + { + if (first == null) + { + first = (Path.ChildAssocElement) element; + } + else + { + pathToSave.append(element); + } + } + if (first != null) + { + // mimic an association that would appear if the current node was below the root node + // or if first beneath the root node it will make the real thing + ChildAssociationRef updateAssocRef = new ChildAssociationRef( + parentAssocInfo.isStoreRoot() ? ContentModel.ASSOC_CHILDREN : first.getRef().getTypeQName(), + currentRootNodePair.getSecond(), + first.getRef().getQName(), + first.getRef().getChildRef()); + Path.Element newFirst = new Path.ChildAssocElement(updateAssocRef); + pathToSave.prepend(newFirst); + } + + Path.Element element = new Path.ChildAssocElement(assocRef); + pathToSave.prepend(element); + + // store the path just built + completedPaths.add(pathToSave); + } + + if (!hasParents && !parentAssocInfo.isRoot()) + { + throw new RuntimeException("Node without parents does not have root aspect: " + currentNodeRef); + } + // walk up each parent association + for (Map.Entry entry : parentAssocInfo.getParentAssocs().entrySet()) + { + Long assocId = entry.getKey(); + ChildAssocEntity assoc = entry.getValue(); + ChildAssociationRef assocRef = assoc.getRef(qnameDAO); + // do we consider only primary assocs? + if (primaryOnly && !assocRef.isPrimary()) + { + continue; + } + // Ordering is meaningless here as we are constructing a path upwards + // and have no idea where the node comes in the sibling order or even + // if there are like-pathed siblings. + assocRef.setNthSibling(-1); + // build a path element + Path.Element element = new Path.ChildAssocElement(assocRef); + // create a new path that builds on the current path + Path path = new Path(); + path.append(currentPath); + // prepend element + path.prepend(element); + // get parent node pair + Pair parentNodePair = new Pair( + assoc.getParentNode().getId(), + assocRef.getParentRef()); + + // does the association already exist in the stack + if (assocIdStack.contains(assocId)) + { + // the association was present already + logger.error( + "Cyclic parent-child relationship detected: \n" + + " current node: " + currentNodeId + "\n" + + " current path: " + currentPath + "\n" + + " next assoc: " + assocId); + throw new CyclicChildRelationshipException("Node has been pasted into its own tree.", assocRef); + } + + // push the assoc stack, recurse and pop + assocIdStack.push(assocId); + prependPaths(parentNodePair, currentRootNodePair, path, completedPaths, assocIdStack, primaryOnly); + assocIdStack.pop(); + } + // done + } + + /** + * @return Returns a node's parent associations + */ + private ParentAssocsInfo getParentAssocsCached(Long nodeId) + { + Pair cacheEntry = parentAssocsCache.getByKey(nodeId); + if (cacheEntry == null) + { + throw new DataIntegrityViolationException("Invalid node ID: " + nodeId); + } + return cacheEntry.getSecond(); + } + + /** + * Update a node's parent associations. + */ + private void setParentAssocsCached(Long nodeId, ParentAssocsInfo parentAssocs) + { + parentAssocsCache.setValue(nodeId, parentAssocs); + } + + /** + * Callback to cache node parent assocs. + * + * @author Derek Hulley + * @since 3.4 + */ + private class ParentAssocsCallbackDAO extends EntityLookupCallbackDAOAdaptor + { + public Pair createValue(ParentAssocsInfo value) + { + throw new UnsupportedOperationException("Nodes are created independently."); + } + + public Pair findByKey(Long nodeId) + { + // Find out if it is a root or store root + boolean isRoot = hasNodeAspect(nodeId, ContentModel.ASPECT_ROOT); + boolean isStoreRoot = getNodeType(nodeId).equals(ContentModel.TYPE_STOREROOT); + + // Select all the parent associations + List assocs = selectParentAssocs(nodeId); + + // Build the cache object + ParentAssocsInfo value = new ParentAssocsInfo(isRoot, isStoreRoot, assocs); + // Done + return new Pair(nodeId, value); + } + } + + /* + * Bulk caching + */ + + public void cacheNodes(List nodeRefs) + { + + } + + /** + * {@inheritDoc} + *

+ * Simply clears out all the node-related caches. + */ + public void clear() + { + nodesCache.clear(); + aspectsCache.clear(); + propertiesCache.clear(); + parentAssocsCache.clear(); + } + + /* + * Transactions + */ + + public Long getMaxTxnIdByCommitTime(long maxCommitTime) + { + Transaction txn = selectLastTxnBeforeCommitTime(maxCommitTime); + return (txn == null ? null : txn.getId()); + } + + public void getNodesDeletedInOldTxns( + Long minNodeId, + long maxCommitTime, + int count, + NodeRefQueryCallback resultsCallback) + { + selectNodesDeletedInOldTxns(minNodeId, maxCommitTime, count, resultsCallback); + } + + public int getTransactionCount() + { + return selectTransactionCount(); + } + + public Transaction getTxnById(Long txnId) + { + return selectTxnById(txnId); + } + + public List getTxnChanges(Long txnId) + { + return getTxnChangesForStore(null, txnId); + } + + public List getTxnChangesForStore(StoreRef storeRef, Long txnId) + { + Long storeId = (storeRef == null) ? null : getStoreNotNull(storeRef).getId(); + List nodes = selectTxnChanges(txnId, storeId); + // Convert + List nodeRefs = new ArrayList(nodes.size()); + for (NodeEntity node : nodes) + { + nodeRefs.add(node.getNodeRef()); + } + // Done + return nodeRefs; + } + + public int getTxnUpdateCount(Long txnId) + { + return selectTxnNodeChangeCount(txnId, Boolean.TRUE); + } + + public int getTxnDeleteCount(Long txnId) + { + return selectTxnNodeChangeCount(txnId, Boolean.FALSE); + } + + public List getTxnsByCommitTimeAscending( + Long fromTimeInclusive, + Long toTimeExclusive, + int count, + List excludeTxnIds, + boolean remoteOnly) + { + // Pass the current server ID if it is to be excluded + Long serverId = remoteOnly ? serverId = getServerId() : null; + return selectTxns(fromTimeInclusive, toTimeExclusive, count, null, excludeTxnIds, serverId, Boolean.TRUE); + } + + public List getTxnsByCommitTimeDescending( + Long fromTimeInclusive, + Long toTimeExclusive, + int count, + List excludeTxnIds, + boolean remoteOnly) + { + // Pass the current server ID if it is to be excluded + Long serverId = remoteOnly ? serverId = getServerId() : null; + return selectTxns(fromTimeInclusive, toTimeExclusive, count, null, excludeTxnIds, serverId, Boolean.FALSE); + } + + public List getTxnsByCommitTimeAscending(List includeTxnIds) + { + return selectTxns(null, null, null, includeTxnIds, null, null, Boolean.TRUE); + } + + public List getTxnsUnused(Long minTxnId, long maxCommitTime, int count) + { + return selectTxnsUnused(minTxnId, maxCommitTime, count); + } + + public void purgeTxn(Long txnId) + { + deleteTransaction(txnId); + } + + public static final Long LONG_ZERO = 0L; + + public Long getMinTxnCommitTime() + { + Long time = selectMinTxnCommitTime(); + return (time == null ? LONG_ZERO : time); + } + + public Long getMaxTxnCommitTime() + { + Long time = selectMaxTxnCommitTime(); + return (time == null ? LONG_ZERO : time); + } + + /* + * Abstract methods for underlying CRUD + */ + + protected abstract ServerEntity selectServer(String ipAddress); + protected abstract Long insertServer(String ipAddress); + protected abstract Long insertTransaction(Long serverId, String changeTxnId, Long commit_time_ms); + protected abstract int updateTransaction(Long txnId, Long commit_time_ms); + protected abstract int deleteTransaction(Long txnId); + protected abstract List selectAllStores(); + protected abstract NodeEntity selectStoreRootNode(Long storeId); + protected abstract NodeEntity selectStoreRootNode(StoreRef storeRef); + protected abstract Long insertStore(StoreEntity store); + protected abstract int updateStoreRoot(StoreEntity store); + protected abstract Long insertNode(NodeEntity node); + protected abstract int updateNode(NodeUpdateEntity nodeUpdate); + protected abstract void updatePrimaryChildrenSharedAclId( + Long primaryParentNodeId, + Long optionalOldSharedAlcIdInAdditionToNull, + Long newSharedAlcId); + protected abstract int deleteNodeById(Long nodeId, boolean deletedOnly); + protected abstract NodeEntity selectNodeById(Long id, Boolean deleted); + protected abstract NodeEntity selectNodeByNodeRef(NodeRef nodeRef, Boolean deleted); + protected abstract Map selectNodeProperties(Long nodeId); + protected abstract Map selectNodeProperties(Long nodeId, Set qnameIds); + protected abstract int deleteNodeProperties(Long nodeId, Set qnameIds); + protected abstract void deleteNodeProperties(Long nodeId, List propKeys); + protected abstract void insertNodeProperties(Long nodeId, Map persistableProps); + protected abstract Set selectNodeAspectIds(Long nodeId); + protected abstract void insertNodeAspect(Long nodeId, Long qnameId); + protected abstract int deleteNodeAspects(Long nodeId, Set qnameIds); + protected abstract void selectNodesWithAspect(Long qnameId, Long minNodeId, NodeRefQueryCallback resultsCallback); + protected abstract Long insertNodeAssoc(Long sourceNodeId, Long targetNodeId, Long assocTypeQNameId); + protected abstract int deleteNodeAssoc(Long sourceNodeId, Long targetNodeId, Long assocTypeQNameId); + protected abstract int deleteNodeAssocsToAndFrom(Long nodeId); + protected abstract int deleteNodeAssocsToAndFrom(Long nodeId, Set assocTypeQNameIds); + protected abstract List selectNodeAssocsBySource(Long sourceNodeId); + protected abstract List selectNodeAssocsByTarget(Long targetNodeId); + protected abstract Long insertChildAssoc(ChildAssocEntity assoc); + protected abstract int deleteChildAssocById(Long assocId); + protected abstract int updateChildAssocIndex( + Long parentNodeId, + Long childNodeId, + QName assocTypeQName, + QName assocQName, + int index); + protected abstract int updateChildAssocsUniqueName(Long childNodeId, String name); + protected abstract int deleteChildAssocsToAndFrom(Long nodeId); + protected abstract ChildAssocEntity selectChildAssoc(Long assocId); + protected abstract List selectPrimaryChildAcls(Long nodeId); + protected abstract List selectChildAssoc( + Long parentNodeId, + Long childNodeId, + QName assocTypeQName, + QName assocQName); + /** + * Parameters are all optional except the parent node ID and the callback + */ + protected abstract void selectChildAssocs( + Long parentNodeId, + Long childNodeId, + QName assocTypeQName, + QName assocQName, + Boolean isPrimary, + Boolean sameStore, + ChildAssocRefQueryCallback resultsCallback); + protected abstract void selectChildAssocs( + Long parentNodeId, + Set assocTypeQNames, + ChildAssocRefQueryCallback resultsCallback); + protected abstract ChildAssocEntity selectChildAssoc( + Long parentNodeId, + QName assocTypeQName, + String childName); + protected abstract void selectChildAssocs( + Long parentNodeId, + QName assocTypeQName, + Collection childNames, + ChildAssocRefQueryCallback resultsCallback); + protected abstract void selectChildAssocsByChildTypes( + Long parentNodeId, + Set childNodeTypeQNames, + ChildAssocRefQueryCallback resultsCallback); + protected abstract void selectChildAssocsWithoutParentAssocsOfType( + Long parentNodeId, + QName assocTypeQName, + ChildAssocRefQueryCallback resultsCallback); + /** + * Parameters are all optional except the parent node ID and the callback + */ + protected abstract void selectParentAssocs( + Long childNodeId, + QName assocTypeQName, + QName assocQName, + Boolean isPrimary, + ChildAssocRefQueryCallback resultsCallback); + protected abstract List selectParentAssocs(Long childNodeId); + /** + * No DB constraint, so multiple returned + */ + protected abstract List selectPrimaryParentAssocs(Long childNodeId); + protected abstract int updatePrimaryParentAssocs( + Long childNodeId, + Long parentNodeId, + QName assocTypeQName, + QName assocQName, + String childNodeName); + + protected abstract Transaction selectLastTxnBeforeCommitTime(Long maxCommitTime); + protected abstract void selectNodesDeletedInOldTxns( + Long minNodeId, + Long maxCommitTime, + Integer count, + NodeRefQueryCallback resultsCallback); + protected abstract int selectTransactionCount(); + protected abstract Transaction selectTxnById(Long txnId); + protected abstract List selectTxnChanges(Long txnId, Long storeId); + /** + * @param txnId the transaction ID (never null) + * @param updates TRUE to select node updates, FALSE to select + * node deletions or null to select all changes. + * @return Returns the number of nodes affected by the transaction + */ + protected abstract int selectTxnNodeChangeCount(Long txnId, Boolean updates); + protected abstract List selectTxns( + Long fromTimeInclusive, + Long toTimeExclusive, + Integer count, + List includeTxnIds, + List excludeTxnIds, + Long excludeServerId, + Boolean ascending); + protected abstract List selectTxnsUnused(Long minTxnId, Long maxCommitTime, Integer count); + protected abstract Long selectMinTxnCommitTime(); + protected abstract Long selectMaxTxnCommitTime(); +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/node/AuditablePropertiesEntity.java b/source/java/org/alfresco/repo/domain/node/AuditablePropertiesEntity.java new file mode 100644 index 0000000000..dbb29b90e0 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/AuditablePropertiesEntity.java @@ -0,0 +1,481 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.TypeDefinition; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.namespace.QName; + +/** + * Class holding properties associated with the cm:auditable aspect. + * This aspect is common enough to warrant direct inclusion on the Node entity. + * + * @author Derek Hulley + * @since 3.4 + */ +public class AuditablePropertiesEntity +{ + private static Set auditablePropertyQNames; + static + { + auditablePropertyQNames = new HashSet(13); + auditablePropertyQNames.add(ContentModel.PROP_CREATOR); + auditablePropertyQNames.add(ContentModel.PROP_CREATED); + auditablePropertyQNames.add(ContentModel.PROP_MODIFIER); + auditablePropertyQNames.add(ContentModel.PROP_MODIFIED); + auditablePropertyQNames.add(ContentModel.PROP_ACCESSED); + } + + /** + * @return Returns the QNames of the cm:auditable properties + */ + public static Set getAuditablePropertyQNames() + { + return auditablePropertyQNames; + } + + /** + * @return Returns true if the property belongs to the cm:auditable aspect + */ + public static boolean isAuditableProperty(QName qname) + { + return auditablePropertyQNames.contains(qname); + } + + /** + * @param typeQName a node type + * @return true if the type given has the cm:auditable aspect by default + */ + public static boolean hasAuditableAspect(QName typeQName, DictionaryService dictionaryService) + { + TypeDefinition typeDef = dictionaryService.getType(typeQName); + if (typeDef == null) + { + return false; + } + return typeDef.getDefaultAspectNames().contains(ContentModel.ASPECT_AUDITABLE); + } + + private String auditCreator; + private String auditCreated; + private String auditModifier; + private String auditModified; + private String auditAccessed; + + // Cached value for faster comparisons when updating modification time + private long auditModifiedTime = -1L; + + /** + * Default constructor with all null values. + */ + public AuditablePropertiesEntity() + { + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("AuditablePropertiesEntity") + .append("[ auditCreator=").append(auditCreator) + .append(", auditCreated=").append(auditCreated) + .append(", auditModifier=").append(auditModifier) + .append(", auditModified=").append(auditModified) + .append("]"); + return sb.toString(); + } + + /** + * @param qname the property name + * @return Returns the value of the cm:auditable property or null + */ + public Serializable getAuditableProperty(QName qname) + { + if (qname.equals(ContentModel.PROP_CREATOR)) + { + return auditCreator; + } + else if (qname.equals(ContentModel.PROP_CREATED)) + { + return DefaultTypeConverter.INSTANCE.convert(Date.class, auditCreated); + } + else if (qname.equals(ContentModel.PROP_MODIFIER)) + { + return auditModifier == null ? auditCreator : auditModifier; + } + else if (qname.equals(ContentModel.PROP_MODIFIED)) + { + String dateStr = auditModified == null ? auditCreated : auditModified; + return DefaultTypeConverter.INSTANCE.convert(Date.class, dateStr); + } + else if (qname.equals(ContentModel.PROP_ACCESSED)) + { + return DefaultTypeConverter.INSTANCE.convert(Date.class, auditAccessed); + } + else + { + return null; + } + } + + /** + * @param qname the property name + * @param value the property value + * @return Returns true if the property was used + * @deprecated Deprecated from the start, but possibly useful code + */ + @SuppressWarnings("unused") + private boolean setAuditableProperty(QName qname, Serializable value) + { + if (qname.equals(ContentModel.PROP_CREATOR)) + { + auditCreator = DefaultTypeConverter.INSTANCE.convert(String.class, value); + return true; + } + if (qname.equals(ContentModel.PROP_MODIFIER)) + { + auditModifier = DefaultTypeConverter.INSTANCE.convert(String.class, value); + return true; + } + if (qname.equals(ContentModel.PROP_CREATED)) + { + auditCreated = DefaultTypeConverter.INSTANCE.convert(String.class, value); + return true; + } + if (qname.equals(ContentModel.PROP_MODIFIED)) + { + auditModified = DefaultTypeConverter.INSTANCE.convert(String.class, value); + return true; + } + if (qname.equals(ContentModel.PROP_ACCESSED)) + { + auditAccessed = DefaultTypeConverter.INSTANCE.convert(String.class, value); + return true; + } + else + { + return false; + } + } + + /** + * @return Returns a Map of auditable properties + */ + public Map getAuditableProperties() + { + Map properties = new HashMap(7); + properties.put(ContentModel.PROP_CREATOR, auditCreator); + properties.put(ContentModel.PROP_CREATED, DefaultTypeConverter.INSTANCE.convert(Date.class, auditCreated)); + // cm:modifier - use cm:creator if not set + if (auditModifier != null) + { + properties.put(ContentModel.PROP_MODIFIER, auditModifier); + } + else + { + properties.put(ContentModel.PROP_MODIFIER, auditCreator); + } + // cm:modified - use cm:created if not set + if (auditModified != null) + { + properties.put(ContentModel.PROP_MODIFIED, DefaultTypeConverter.INSTANCE.convert(Date.class, auditModified)); + } + else + { + properties.put(ContentModel.PROP_MODIFIED, DefaultTypeConverter.INSTANCE.convert(Date.class, auditCreated)); + } + // Usually null + if (auditAccessed != null) + { + properties.put(ContentModel.PROP_ACCESSED, DefaultTypeConverter.INSTANCE.convert(Date.class, auditAccessed)); + } + return properties; + } + + /** + * Set all cm:auditable parameters as required. Where possible, the creation and modification data + * will be shared so as to reduce data duplication. + * + * @param user the username; null to use the + * {@link AuthenticationUtil#getFullyAuthenticatedUser() fully-authenticated user} + * @param date the creation or modification date; null to use the current system time + * @param force true to force the values to overwrite any pre-existing values + * @param modifiedDateToleranceMs the number of milliseconds' to tolerate before updating the + * modification date. + * Setting this to 1000L (say) will mean that the modification time will not be + * changed if the existing value is withing 1000 ms of the new time. + * @return Returns true if there were any changes made, otherwise false + */ + public boolean setAuditValues(String user, Date date, boolean force, long modifiedDateToleranceMs) + { + // Get a user if we need + if (user == null) + { + user = AuthenticationUtil.getFullyAuthenticatedUser(); + if (user == null) + { + user = "unknown"; + } + } + // Get a date if we need + if (date == null) + { + date = new Date(); + } + + String dateStr = DefaultTypeConverter.INSTANCE.convert(String.class, date); + long dateTime = date.getTime(); + + // Need to know if anything changed + boolean changed = false; + + // Always set cm:creator and cm:created + if (force || auditCreator == null) + { + auditCreator = user; + changed = true; + } + if (force || auditCreated == null) + { + auditCreated = dateStr; + changed = true; + } + if (auditModifier == null || !auditModifier.equals(user)) + { + auditModifier = user; + changed = true; + } + long lastModTime = getAuditModifiedTime(); + if (lastModTime < 0 || (lastModTime + modifiedDateToleranceMs) < dateTime) + { + // The time has moved on enough + auditModifiedTime = dateTime; + auditModified = dateStr; + changed = true; + } + // Done + return changed; + } + + /** + * Set all cm:auditable parameters as required, giving precedence to the supplied + * property map. + * + * @param user the username + * @param date the creation or modification date + * @param properties the properties to override the user and date + * @return Returns true if there were any changes made, otherwise false + */ + public boolean setAuditValues(String user, Date date, Map properties) + { + // Need to know if anything changed + boolean changed = false; + + if (properties.containsKey(ContentModel.PROP_CREATOR)) + { + auditCreator = DefaultTypeConverter.INSTANCE.convert( + String.class, + properties.get(ContentModel.PROP_CREATOR)); + changed = true; + } + if (properties.containsKey(ContentModel.PROP_MODIFIER)) + { + auditModifier = DefaultTypeConverter.INSTANCE.convert( + String.class, + properties.get(ContentModel.PROP_MODIFIER)); + changed = true; + } + if (properties.containsKey(ContentModel.PROP_CREATED)) + { + auditCreated = DefaultTypeConverter.INSTANCE.convert( + String.class, + properties.get(ContentModel.PROP_CREATED)); + changed = true; + } + if (properties.containsKey(ContentModel.PROP_MODIFIED)) + { + Date auditModifiedDate = DefaultTypeConverter.INSTANCE.convert( + Date.class, + properties.get(ContentModel.PROP_MODIFIED)); + auditModifiedTime = auditModifiedDate.getTime(); + auditModified = DefaultTypeConverter.INSTANCE.convert( + String.class, + auditModifiedDate); + changed = true; + } + if (properties.containsKey(ContentModel.PROP_ACCESSED)) + { + auditAccessed = DefaultTypeConverter.INSTANCE.convert( + String.class, + properties.get(ContentModel.PROP_ACCESSED)); + changed = true; + } + + if (changed) + { + // Make sure populate any missing values + // Get a user if we need + if (user == null) + { + user = AuthenticationUtil.getFullyAuthenticatedUser(); + if (user == null) + { + user = "unknown"; + } + } + // Get a date if we need + if (date == null) + { + date = new Date(); + } + + String dateStr = DefaultTypeConverter.INSTANCE.convert(String.class, date); + long dateTime = date.getTime(); + + if (auditCreator == null) + { + auditCreator = user; + } + if (auditModifier == null) + { + auditModifier = user; + } + if (auditCreated == null) + { + auditCreated = dateStr; + } + if (auditModified == null) + { + auditModifiedTime = dateTime; + auditModified = dateStr; + } + } + // Done + return changed; + } + + /** + * For persistance use + */ + public String getAuditCreator() + { + return auditCreator; + } + + /** + * For persistance use + */ + public void setAuditCreator(String auditCreator) + { + this.auditCreator = auditCreator; + } + + /** + * For persistance use + */ + public String getAuditCreated() + { + return auditCreated; + } + + /** + * For persistance use + */ + public void setAuditCreated(String auditCreated) + { + this.auditCreated = auditCreated; + } + + /** + * For persistance use + */ + public String getAuditModifier() + { + return auditModifier; + } + + /** + * For persistance use + */ + public void setAuditModifier(String auditModifier) + { + this.auditModifier = auditModifier; + } + + /** + * For persistance use + */ + public String getAuditModified() + { + return auditModified; + } + + /** + * For internal use. Provides access to the time (long) for the + * {@link #getAuditModified() auditModified} property. + */ + private long getAuditModifiedTime() + { + if (auditModifiedTime < 0 && auditModified != null) + { + auditModifiedTime = DefaultTypeConverter.INSTANCE.convert(Date.class, auditModified).getTime(); + } + return auditModifiedTime; + } + + /** + * For persistance use + */ + public void setAuditModified(String auditModified) + { + this.auditModified = auditModified; + } + + /** + * For persistance use + */ + public String getAuditAccessed() + { + return auditAccessed; + } + + /** + * For persistance use + */ + public void setAuditAccessed(String auditAccessed) + { + this.auditAccessed = auditAccessed; + } +} diff --git a/source/java/org/alfresco/repo/domain/node/ChildAssocEntity.java b/source/java/org/alfresco/repo/domain/node/ChildAssocEntity.java new file mode 100644 index 0000000000..f6765a42e1 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/ChildAssocEntity.java @@ -0,0 +1,528 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.io.UnsupportedEncodingException; +import java.util.List; +import java.util.zip.CRC32; + +import org.alfresco.repo.domain.qname.QNameDAO; +import org.alfresco.service.cmr.dictionary.AssociationDefinition; +import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.GUID; +import org.alfresco.util.Pair; +import org.alfresco.util.ParameterCheck; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Bean for alf_child_assoc table. + * + * @author Derek Hulley + * @since 3.4 + */ +public class ChildAssocEntity +{ + private static final Log logger = LogFactory.getLog(ChildAssocEntity.class); + + private Long id; + private Long version; + private NodeEntity parentNode; + private NodeEntity childNode; + private Long typeQNameId; + private Long childNodeNameCrc; + private String childNodeName; + private Long qnameNamespaceId; + private String qnameLocalName; + private Long qnameCrc; + private Boolean isPrimary; + private int assocIndex; + + // Suplemental query-related parameters + private List typeQNameIds; + private List childNodeNameCrcs; + private List childNodeTypeQNameIds; + private Boolean sameStore; + private boolean ordered; + + /** + * Find a CRC value for the full QName using UTF-8 conversion. + * + * @param qname the association qname + * @return Returns the CRC value (UTF-8 compatible) + */ + public static Long getQNameCrc(QName qname) + { + CRC32 crc = new CRC32(); + try + { + crc.update(qname.getNamespaceURI().getBytes("UTF-8")); + crc.update(qname.getLocalName().getBytes("UTF-8")); + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException("UTF-8 encoding is not supported"); + } + return crc.getValue(); + + } + + /** + * Find a CRC value for the association's child node name using UTF-8 conversion. + * + * @param childNodeName the child node name + * @return Returns the CRC value (UTF-8 compatible) + */ + public static Long getChildNodeNameCrc(String childNodeName) + { + CRC32 crc = new CRC32(); + try + { + // https://issues.alfresco.com/jira/browse/ALFCOM-1335 + crc.update(childNodeName.getBytes("UTF-8")); + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException("UTF-8 encoding is not supported"); + } + return crc.getValue(); + } + + private static final String TRUNCATED_NAME_INDICATOR = "~~~"; + + /** + * Truncates the association's child node name to 50 characters. + * + * @param childNodeName the child node name + * @return Returns the potentially truncated value + */ + public static String getChildNodeNameShort(String childNodeName) + { + int length = childNodeName.length(); + if (length <= 50) + { + return childNodeName; + } + else + { + StringBuilder ret = new StringBuilder(50); + ret.append(childNodeName.substring(0, 47)).append(TRUNCATED_NAME_INDICATOR); + return ret.toString(); + } + } + + /** + * Apply the cm:name to the child association. If the child name is null then a GUID is generated as + * a substitute. + *

+ * Unknown associations or associations that do not require unique name checking will use a GUID for the child + * name and the CRC value used will be negative. + * + * @param childName the cm:name applying to the association. + */ + public static Pair getChildNameUnique( + DictionaryService dictionaryService, + QName assocTypeQName, + String childName) + { + if (childName == null) + { + throw new IllegalArgumentException("Child name may not be null. Use the Node ID ..."); + } + + String childNameNewShort; // + long childNameNewCrc = -1L; // By default, they don't compete + + AssociationDefinition assocDef = dictionaryService.getAssociation(assocTypeQName); + if (assocDef == null || !assocDef.isChild()) + { + if (logger.isWarnEnabled()) + { + logger.warn("No child association of this type could be found: " + assocTypeQName); + } + childNameNewShort = GUID.generate(); + childNameNewCrc = -1L * getChildNodeNameCrc(childNameNewShort); + } + else + { + ChildAssociationDefinition childAssocDef = (ChildAssociationDefinition) assocDef; + if (childAssocDef.getDuplicateChildNamesAllowed()) + { + childNameNewShort = GUID.generate(); + childNameNewCrc = -1L * getChildNodeNameCrc(childNameNewShort); + } + else + { + String childNameNewLower = childName.toLowerCase(); + childNameNewShort = getChildNodeNameShort(childNameNewLower); + childNameNewCrc = getChildNodeNameCrc(childNameNewLower); + } + } + return new Pair(childNameNewShort, childNameNewCrc); + } + + /** + * Required default constructor + */ + public ChildAssocEntity() + { + ordered = true; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("ChildAssocEntity") + .append("[ ID=").append(id) + .append(", parentNode=").append(parentNode) + .append(", childNode=").append(childNode) + .append(", typeQNameId=").append(typeQNameId) + .append(", childNodeNameCrc=").append(childNodeNameCrc) + .append(", childNodeName=").append(childNodeName) + .append(", qnameNamespaceId=").append(qnameNamespaceId) + .append(", qnameLocalName=").append(qnameLocalName) + .append(", qnameCrc=").append(qnameCrc) + .append("]"); + return sb.toString(); + } + + public ChildAssociationRef getRef(QNameDAO qnameDAO) + { + QName typeQName = qnameDAO.getQName(typeQNameId).getSecond(); + QName qname = QName.createQName(qnameDAO.getNamespace(qnameNamespaceId).getSecond(), qnameLocalName); + return new ChildAssociationRef( + typeQName, + parentNode.getNodeRef(), + qname, + childNode.getNodeRef(), + isPrimary, + assocIndex); + } + + public Pair getPair(QNameDAO qnameDAO) + { + return new Pair(id, getRef(qnameDAO)); + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + public NodeEntity getParentNode() + { + return parentNode; + } + + public void setParentNode(NodeEntity parentNode) + { + this.parentNode = parentNode; + } + + public NodeEntity getChildNode() + { + return childNode; + } + + public void setChildNode(NodeEntity childNode) + { + this.childNode = childNode; + } + + /** + * Helper method to set the {@link #setTypeQNameId(Long)}. + * + * @param qnameDAO the DAO to resolve the QName ID + * @param typeQName the association type + * @param forUpdate true if the QName must exist i.e. this + * entity will be used for updates and the type + * QName must exist. + * @return true if the set worked otherwise false + */ + public boolean setTypeQNameAll(QNameDAO qnameDAO, QName typeQName, boolean forUpdate) + { + if (forUpdate) + { + typeQNameId = qnameDAO.getOrCreateQName(typeQName).getFirst(); + return true; + } + else + { + Pair qnamePair = qnameDAO.getQName(typeQName); + if (qnamePair == null) + { + return false; + } + else + { + typeQNameId = qnamePair.getFirst(); + return true; + } + } + } + + public Long getTypeQNameId() + { + return typeQNameId; + } + + /** + * @deprecated For persistence use only + */ + public void setTypeQNameId(Long typeQNameId) + { + this.typeQNameId = typeQNameId; + } + + /** + * Helper method to set all values associated with the + * {@link #setChildNodeName(String) child node name}. + * + * @param dictionaryService the service that determines how the CRC values are generated. + * If this is null then the CRC values are generated + * assuming that positive enforcement of the name constraint is + * required. + * @param childNodeName the child node name + */ + public void setChildNodeNameAll( + DictionaryService dictionaryService, + QName typeQName, + String childNodeName) + { + ParameterCheck.mandatory("childNodeName", childNodeName); + + if (dictionaryService != null) + { + ParameterCheck.mandatory("typeQName", typeQName); + + Pair childNameUnique = ChildAssocEntity.getChildNameUnique( + dictionaryService, + typeQName, + childNodeName); + this.childNodeName = childNameUnique.getFirst(); + this.childNodeNameCrc = childNameUnique.getSecond(); + } + else + { + String childNameNewLower = childNodeName.toLowerCase(); + this.childNodeName = ChildAssocEntity.getChildNodeNameShort(childNameNewLower); + this.childNodeNameCrc = ChildAssocEntity.getChildNodeNameCrc(childNameNewLower); + } + } + + public Long getChildNodeNameCrc() + { + return childNodeNameCrc; + } + + /** + * @deprecated For persistence use + */ + public void setChildNodeNameCrc(Long childNodeNameCrc) + { + this.childNodeNameCrc = childNodeNameCrc; + } + + public String getChildNodeName() + { + return childNodeName; + } + + /** + * @deprecated For persistence use + */ + public void setChildNodeName(String childNodeName) + { + this.childNodeName = childNodeName; + } + + /** + * Set all required fields associated with the patch QName. + * + * @param forUpdate true if the entity is going to be used for a + * data update i.e. the QName must exist. + * @return Returns true if the QName namespace + * exists. + */ + public boolean setQNameAll(QNameDAO qnameDAO, QName qname, boolean forUpdate) + { + String assocQNameNamespace = qname.getNamespaceURI(); + String assocQNameLocalName = qname.getLocalName(); + Long assocQNameNamespaceId = null; + if (forUpdate) + { + assocQNameNamespaceId = qnameDAO.getOrCreateNamespace(assocQNameNamespace).getFirst(); + } + else + { + Pair nsPair = qnameDAO.getOrCreateNamespace(assocQNameNamespace); + if (nsPair == null) + { + // We can't set anything + return false; + } + else + { + assocQNameNamespaceId = nsPair.getFirst(); + } + } + Long assocQNameCrc = getQNameCrc(qname); + + this.qnameNamespaceId = assocQNameNamespaceId; + this.qnameLocalName = assocQNameLocalName; + this.qnameCrc = assocQNameCrc; + + // All set correctly + return true; + } + + public Long getQnameNamespaceId() + { + return qnameNamespaceId; + } + + /** + * @deprecated For persistence use + */ + public void setQnameNamespaceId(Long qnameNamespaceId) + { + this.qnameNamespaceId = qnameNamespaceId; + } + + public String getQnameLocalName() + { + return qnameLocalName; + } + + /** + * @deprecated For persistence use + */ + public void setQnameLocalName(String qnameLocalName) + { + this.qnameLocalName = qnameLocalName; + } + + public Long getQnameCrc() + { + return qnameCrc; + } + + /** + * @deprecated For persistence use + */ + public void setQnameCrc(Long qnameCrc) + { + this.qnameCrc = qnameCrc; + } + + public Boolean isPrimary() + { + return isPrimary; + } + + public void setPrimary(Boolean isPrimary) + { + this.isPrimary = isPrimary; + } + + public int getAssocIndex() + { + return assocIndex; + } + + public void setAssocIndex(int assocIndex) + { + this.assocIndex = assocIndex; + } + + public List getTypeQNameIds() + { + return typeQNameIds; + } + + public void setTypeQNameIds(List typeQNameIds) + { + this.typeQNameIds = typeQNameIds; + } + + public List getChildNodeNameCrcs() + { + return childNodeNameCrcs; + } + + public void setChildNodeNameCrcs(List childNodeNameCrcs) + { + this.childNodeNameCrcs = childNodeNameCrcs; + } + + public List getChildNodeTypeQNameIds() + { + return childNodeTypeQNameIds; + } + + public void setChildNodeTypeQNameIds(List childNodeTypeQNameIds) + { + this.childNodeTypeQNameIds = childNodeTypeQNameIds; + } + + public Boolean getSameStore() + { + return sameStore; + } + + public void setSameStore(Boolean sameStore) + { + this.sameStore = sameStore; + } + + public boolean isOrdered() + { + return ordered; + } + + public void setOrdered(boolean ordered) + { + this.ordered = ordered; + } +} diff --git a/source/java/org/alfresco/repo/domain/node/Node.java b/source/java/org/alfresco/repo/domain/node/Node.java new file mode 100644 index 0000000000..1b9fc454aa --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/Node.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.Pair; + +/** + * Interface for beans carrying general information for alf_node data. + * + * @author andyh + */ +public interface Node extends NodeIdAndAclId +{ + public abstract NodeRef getNodeRef(); + + public abstract Pair getNodePair(); + + public abstract Long getVersion(); + + public abstract StoreEntity getStore(); + + public abstract String getUuid(); + + public abstract Long getTypeQNameId(); + + public abstract Boolean getDeleted(); + + public abstract TransactionEntity getTransaction(); + + public abstract AuditablePropertiesEntity getAuditableProperties(); + +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/node/NodeAspectsEntity.java b/source/java/org/alfresco/repo/domain/node/NodeAspectsEntity.java new file mode 100644 index 0000000000..91a8ec388c --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/NodeAspectsEntity.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.util.List; + +/** + * Bean to convey alf_node_aspects data. + * + * @author Derek Hulley + * @since 3.4 + */ +public class NodeAspectsEntity +{ + private Long id; + private List aspectQNameIds; + + /** + * Required default constructor + */ + public NodeAspectsEntity() + { + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("NodeAspectsEntity") + .append(", id=").append(id) + .append(", aspects=").append(aspectQNameIds) + .append("]"); + return sb.toString(); + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public List getAspectQNameIds() + { + return aspectQNameIds; + } + + public void setAspectQNameIds(List aspectQNameIds) + { + this.aspectQNameIds = aspectQNameIds; + } +} diff --git a/source/java/org/alfresco/repo/domain/node/NodeAssocEntity.java b/source/java/org/alfresco/repo/domain/node/NodeAssocEntity.java new file mode 100644 index 0000000000..fed79ad05d --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/NodeAssocEntity.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.util.List; + +/** + * Bean for alf_node_assoc table. + * + * @author Derek Hulley + * @since 3.4 + */ +public class NodeAssocEntity +{ + private Long id; + private Long version; + private NodeEntity sourceNode; + private NodeEntity targetNode; + private Long typeQNameId; + private List typeQNameIds; + + /** + * Required default constructor + */ + public NodeAssocEntity() + { + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("NodeAssocEntity") + .append("[ ID=").append(id) + .append(", sourceNode=").append(sourceNode) + .append(", targetNode=").append(targetNode) + .append(", typeQNameId=").append(typeQNameId) + .append(", typeQNameIds=").append(typeQNameIds) + .append("]"); + return sb.toString(); + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + public NodeEntity getSourceNode() + { + return sourceNode; + } + + public void setSourceNode(NodeEntity sourceNode) + { + this.sourceNode = sourceNode; + } + + public NodeEntity getTargetNode() + { + return targetNode; + } + + public void setTargetNode(NodeEntity targetNode) + { + this.targetNode = targetNode; + } + + public Long getTypeQNameId() + { + return typeQNameId; + } + + public void setTypeQNameId(Long typeQNameId) + { + this.typeQNameId = typeQNameId; + } + + public List getTypeQNameIds() + { + return typeQNameIds; + } + + public void setTypeQNameIds(List typeQNameIds) + { + this.typeQNameIds = typeQNameIds; + } +} diff --git a/source/java/org/alfresco/repo/domain/node/NodeDAO.java b/source/java/org/alfresco/repo/domain/node/NodeDAO.java new file mode 100644 index 0000000000..71d64b796c --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/NodeDAO.java @@ -0,0 +1,607 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.node.NodeBulkLoader; +import org.alfresco.service.cmr.dictionary.InvalidTypeException; +import org.alfresco.service.cmr.repository.AssociationRef; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.Path; +import org.alfresco.service.cmr.repository.StoreExistsException; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; + +/** + * DAO services for alf_node and related tables + * + * @author Derek Hulley + * @since 3.4 + */ +public interface NodeDAO extends NodeBulkLoader +{ + /** + * Interface used to iterate over pure node results + * + * @author Derek Hulley + * @since 3.4 + */ + public interface NodeRefQueryCallback + { + /** + * @param nodePair the node result + * @return Returns true if more results are required + */ + boolean handle(Pair nodePair); + } + + /* + * Transaction + */ + + /** + * + * @return Returns the ID of the current transaction entry + */ + public Long getCurrentTransactionId(); + + /* + * Store + */ + + /** + * Fetch a list of all stores in the repository + * + * @return Returns a list of stores + */ + public List> getStores(); + + /** + * Find out if a store exists or not + * + * @param storeRef the store + * @return Returns true if the store exists otherwise false + */ + public boolean exists(StoreRef storeRef); + + /** + * Creates a unique store for the given protocol and identifier combination. + * The root node is created with the "root" aspect. + * + * @return Returns the root node, which is added automatically. + * @throws StoreExistsException if the store already exists + */ + public Pair newStore(StoreRef storeRef); + + public Pair getRootNode(StoreRef storeRef); + + /* + * Node + */ + + /** + * Find out if a node exists. Unpurged deleted nodes do not count as they are the DAO's concern only. + * + * @param nodeRef the potentially valid node reference + * @return Returns true if the node is present and undeleted + */ + public boolean exists(NodeRef nodeRef); + + /** + * Get the current status of the node, including deleted nodes. + * + * @param nodeRef the node reference + * @return Returns the current status of the reference. + * This will only be null if the node never existed or has been + * purged following deletion. + */ + public NodeRef.Status getNodeRefStatus(NodeRef nodeRef); + + public Pair getNodePair(NodeRef nodeRef); + + public Pair getNodePair(Long nodeId); + + public QName getNodeType(Long nodeId); + + public Long getNodeAclId(Long nodeId); + + /** + * Create a new node. Note that allowing the uuid to be assigned by passing in a null + * is more efficient. + * + * @param parentNodeId the ID of the parent node (may not be null) + * @param assocTypeQName the primary association (may not be null) + * @param assocQName the association path (may not be null) + * @param storeRef the store to which the node must belong + * @param uuid the node store-unique identifier, or null to assign a GUID + * @param nodeTypeQName the type of the node + * @param childNodeName the cm:name of the child node or null to use the node's UUID + * @param auditableProperties a map containing any cm:auditable properties for the node + * @return Returns the details of the child association created + * @throws InvalidTypeException if the node type is invalid or if the node type + * is not a valid real node + */ + public ChildAssocEntity newNode( + Long parentNodeId, + QName assocTypeQName, + QName assocQName, + StoreRef storeRef, + String uuid, + QName nodeTypeQName, + String childNodeName, + Map auditableProperties) throws InvalidTypeException; + + /** + * Update a node's primary association, giving it a new parent and new association parameters. + *

+ * **NEW**: If the parent node's store differs from the child node's store, then the + * child node's store is updated. Store move conflicts are automatically handled by assigning + * new UUIDs to the existing target node. + * + * @param childNodeId the child node that is moving + * @param newParentNodeId the new parent node (may not be null) + * @param assocTypeQName the new association type or null to keep the existing type + * @param assocQName the new association qname or null to keep the existing name + * @return Returns the new association reference + */ + public Pair moveNode( + Long childNodeId, + Long newParentNodeId, + QName assocTypeQName, + QName assocQName); + + /** + * @param storeRef the new store or null to keep the existing one + * @param uuid the new UUID for the node or null to keep it the same + * @param nodeTypeQName the new type QName for the node or null to keep the existing one + */ + public void updateNode(Long nodeId, StoreRef storeRef, String uuid, QName nodeTypeQName); + + public void setNodeAclId(Long nodeId, Long aclId); + + public void setPrimaryChildrenSharedAclId( + Long primaryParentNodeId, + Long optionalOldSharedAlcIdInAdditionToNull, + Long newSharedAclId); + + /** + * Deletes the node and all entities. Note that the node entry will still exist and be + * associated with a live transaction. + */ + public void deleteNode(Long nodeId); + + /** + * Remove all traces of the node. This assumes that the node has been marked + * for deletion using {@link #deleteNode(Long)}. + * + * @deprecated This will be replaced with a purgeNodes(long maxTxnCommitTimeMs) + */ + public void purgeNode(Long nodeId); + + /* + * Properties + */ + + public Serializable getNodeProperty(Long nodeId, QName propertyQName); + + public Map getNodeProperties(Long nodeId); + + public boolean setNodeProperties(Long nodeId, Map properties); + + public boolean addNodeProperty(Long nodeId, QName qname, Serializable value); + + public boolean addNodeProperties(Long nodeId, Map properties); + + public boolean removeNodeProperties(Long nodeId, Set propertyQNames); + + /* + * Aspects + */ + + public Set getNodeAspects(Long nodeId); + + public boolean hasNodeAspect(Long nodeId, QName aspectQName); + + public boolean addNodeAspects(Long nodeId, Set aspectQNames); + + public boolean removeNodeAspects(Long nodeId); + + public boolean removeNodeAspects(Long nodeId, Set aspectQNames); + + public void getNodesWithAspect(QName aspectQName, Long minNodeId, int count, NodeRefQueryCallback resultsCallback); + + /* + * Node Assocs + */ + + public Long newNodeAssoc( + Long sourceNodeId, + Long targetNodeId, + QName assocTypeQName); + + /** + * Remove a specific node association + * + * @param assocId the node association ID to remove + * @return Returns the number of associations removed + */ + public int removeNodeAssoc(Long sourceNodeId, Long targetNodeId, QName assocTypeQName); + + /** + * Remove all node associations that share the given node. + * + * @param nodeId the source or target of the associations + * @return Returns the number of associations removed + */ + public int removeNodeAssocsToAndFrom(Long nodeId); + + /** + * Remove all node associations of given types that share the given node. + * + * @param nodeId the source or target of the associations + * @param assocTypeQNames the types that should be deleted + * @return Returns the number of associations removed + */ + public int removeNodeAssocsToAndFrom(Long nodeId, Set assocTypeQNames); + + /** + * @return Returns all the node associations where the node is the target + */ + public Collection> getSourceNodeAssocs(Long targetNodeId); + + /** + * @return Returns all the node associations where the node is the source + */ + public Collection> getTargetNodeAssocs(Long sourceNodeId); + + /* + * Child Assocs + */ + + /** + * Interface used to iterate over results from child association queries + * + * @author Derek Hulley + * @since 3.4 + */ + public interface ChildAssocRefQueryCallback + { + /** + * @return Return false to terminate the query + * i.e. stop receiving results + */ + boolean handle( + Pair childAssocPair, + Pair parentNodePair, + Pair childNodePair + ); + + /** + * @return Return true if caching of the results is required + */ + boolean preLoadNodes(); + } + + /** + * Create a new child association. The unique enforcement for cm:name will be done + * as part of the association creation i.e. there is no need to update it after the fact. + * + * @param childNodeName the cm:name to apply to the association + * @return Returns the persisted and filled association's ID + */ + public Pair newChildAssoc( + Long parentNodeId, + Long childNodeId, + QName assocTypeQName, + QName assocQName, + String childNodeName); + + /** + * @param assocId the ID of the child association to delete + */ + public void deleteChildAssoc(Long assocId); + + /** + * Sets the association index ordering. + * + * @param parentNodeId the parent node ID + * @param childNodeId the child node ID + * @param assocTypeQName the association type + * @param assocQName the association path qualified name + * @param newIndex the new index + * @return Returns the number of associations modified + */ + public int setChildAssocIndex( + Long parentNodeId, + Long childNodeId, + QName assocTypeQName, + QName assocQName, + int index); + + /** + * Bulk-update all unique name (cm:name) index for parent associations of a given node. + * + * @param childNodeId the child node who's name is changing + * @param childName the new cm:name value + */ + public void setChildAssocsUniqueName(Long childNodeId, String childName); + + /** + * Get a specific association + * + * @param assocId the ID of the association + * @return Returns the association reference or null if it doesn't exist + */ + public Pair getChildAssoc(Long assocId); + + /** + * Get a specific child association given all the determining data. + *

+ * The implementation may find multiple entries (there is no constraint to prevent it) + * although the cm:name constraint will normally prevent the association from + * being created twice. The lowest ID association will always be returned and the + * others will be cleaned up if the transaction is read-write. + * + * @return Returns a matching association or null if one was not found. + */ + public Pair getChildAssoc( + Long parentNodeId, + Long childNodeId, + QName assocTypeQName, + QName assocQName); + + /** + * Get the child associations of a given parent node, optionally filtering on association QName + * and association type QName. + *

+ * This is an efficient query for node paths. + * + * @param parentNodeId the parent node ID + * @param childNodeId the child node ID to filter on; null for no filtering + * @param assocTypeQName the association type qname to filter on; null for no filtering + * @param assocQName the association qname to filter on; null for no filtering + * @param isPrimary filter for primary (true) or secondary associations; + * null for no filtering. + * @param sameStore null to ignore, true to only get children that are in the + * same store as the parent, or false to only get children that are in + * a different store from the parent. + * @param resultsCallback the callback that will be called with the results + */ + public void getChildAssocs( + Long parentNodeId, + Long childNodeId, + QName assocTypeQName, + QName assocQName, + Boolean isPrimary, + Boolean sameStore, + ChildAssocRefQueryCallback resultsCallback); + + /** + * Get the child associations of a given parent node, optionally filtering on type QName. + * + * @param parentNodeId the parent node ID + * @param assocTypeQNames the association type qnames to filter on; null for no filtering + * @param resultsCallback the callback that will be called with the results + */ + public void getChildAssocs( + Long parentNodeId, + Set assocTypeQNames, + ChildAssocRefQueryCallback resultsCallback); + + /** + * Get a child association for given parent node, association type and child node name (cm:name). + * + * @param parentNodeId the parent Node ID + * @param assocTypeQName the association type to filter on + * @param childName the cm:name value to filter on + * @return Returns an association matching the given parent, type and child name + * (cm:name) - or null if not found + */ + public Pair getChildAssoc(Long parentNodeId, QName assocTypeQName, String childName); + + /** + * Get the child associations of a given parent node, filtering on type QName and + * the cm:name of the child nodes. + *

+ * NOTE: This method only works if the association type fundamentally supports unique-name enforcement. + * + * @param parentNodeId the parent node + * @param assocTypeQName the type of the association to check; or null for no filtering. + * If the association type is not specified, then the same child node may be + * included several times. + * @param childNames the names of the child nodes (cm:name). These will be matched exactly. + * @param resultsCallback the callback that will be called with the results + */ + public void getChildAssocs( + Long parentNodeId, + QName assocTypeQName, + Collection childNames, + ChildAssocRefQueryCallback resultsCallback); + + public void getChildAssocsByChildTypes( + Long parentNodeId, + Set childNodeTypeQNames, + ChildAssocRefQueryCallback resultsCallback); + + /** + * Gets the set of child associations of a certain parent node without parent associations of a certain type to + * other nodes with the same parent! In effect the 'orphans' with respect to a certain association type. + * + * @param parentNodeId the parent node ID + * @param assocTypeQName the association type QName + * @param resultsCallback the callback that will be called with the results + */ + public void getChildAssocsWithoutParentAssocsOfType( + final Long parentNodeId, + final QName assocTypeQName, + ChildAssocRefQueryCallback resultsCallback); + + /** + * Finds the association between the node's primary parent and the node itself + * + * @return Returns the primary (defining) association or null + * if it is a root node + */ + public Pair getPrimaryParentAssoc(Long childNodeId); + + /** + * Get the parent association of a given parent node, optionally filtering on association QName + * and association type QName. + *

+ * This is an efficient query for node paths. + * + * @param childNodeId the child node ID + * @param assocTypeQName the association type qname to filter on; null for no filtering + * @param assocQName the association qname to filter on; null for no filtering + * @param isPrimary filter for primary (true) or secondary associations; + * null for no filtering. + * @param resultsCallback the callback that will be called with the results + */ + public void getParentAssocs( + Long childNodeId, + QName assocTypeQName, + QName assocQName, + Boolean isPrimary, + ChildAssocRefQueryCallback resultsCallback); + + /** + * Fetch all primary child node IDs and corresponding ACL IDs. + * + * @param nodeId the parent node ID + * @return Returns a list of Node ID - ACL ID pairs + */ + public List getPrimaryChildrenAcls(Long nodeId); + + /** + * Build the paths for a node. + * + * When searching for primaryOnly == true, checks that there is exactly + * one path. + * + * @param currentNodePair the leave or child node to start with + * @param primaryOnly true to follow only primary parent associations + */ + public List getPaths(Pair nodePair, boolean primaryOnly) throws InvalidNodeRefException; + + /* + * Transactions + */ + + /** + * Gets a batch of deleted nodes in old transactions. + * + * @param minNodeId the minimum node ID + * @param maxCommitTime the maximum commit time (to set a minimum transaction age) + * @param count the maximum number of results (for batching) + * @param resultsCallback the callback to pass results back + * + * @deprecated {@link #purgeNode(Long)} + */ + public void getNodesDeletedInOldTxns( + Long minNodeId, + long maxCommitTime, + int count, + NodeRefQueryCallback resultsCallback); + + /** + * Retrieves the maximum transaction ID for which the commit time is less than the given time. + * + * @param maxCommitTime the max commit time (ms) + * @return the last transaction on or before the given time + */ + public Long getMaxTxnIdByCommitTime(long maxCommitTime); + /** + * Retrieves a specific transaction. + * + * @param txnId the unique transaction ID. + * @return the requested transaction or null + */ + public Transaction getTxnById(Long txnId); + /** + * Get all transactions in a given time range. Since time-based retrieval doesn't guarantee uniqueness + * for any given millisecond, a list of optional exclusions may be provided. + * + * @param excludeTxnIds a list of txn IDs to ignore. null is allowed. + * @param remoteOnly true if locally-written transactions must be ignored + */ + public List getTxnsByCommitTimeAscending( + Long fromTimeInclusive, + Long toTimeExclusive, + int count, + List excludeTxnIds, + boolean remoteOnly); + /** + * Get all transactions in a given time range. Since time-based retrieval doesn't guarantee uniqueness + * for any given millisecond, a list of optional exclusions may be provided. + * + * @param excludeTxnIds a list of txn IDs to ignore. null is allowed. + * @param remoteOnly true if locally-written transactions must be ignored + */ + public List getTxnsByCommitTimeDescending( + Long fromTimeInclusive, + Long toTimeExclusive, + int count, + List excludeTxnIds, + boolean remoteOnly); + /** + * Get a specific list of transactions ordered by commit time. + * + * @param includeTxnIds a list of transaction IDs to search for + * @return Returns the transactions by commit time for the given IDs + */ + public List getTxnsByCommitTimeAscending(List includeTxnIds); + + public int getTxnUpdateCount(Long txnId); + + public int getTxnDeleteCount(Long txnId); + + public int getTransactionCount(); + + /** + * @deprecated Replace with query returning a Node object + */ + public List getTxnChangesForStore(StoreRef storeRef, Long txnId); + + /** + * @deprecated Replace with query returning a Node object + */ + public List getTxnChanges(Long txnId); + + public List getTxnsUnused(Long minTxnId, long maxCommitTime, int count); + + public void purgeTxn(Long txnId); + + public Long getMinTxnCommitTime(); + + public Long getMaxTxnCommitTime(); +} diff --git a/source/java/org/alfresco/repo/domain/node/NodeDAOTest.java b/source/java/org/alfresco/repo/domain/node/NodeDAOTest.java new file mode 100644 index 0000000000..54eb106f9f --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/NodeDAOTest.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.util.List; + +import junit.framework.TestCase; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.node.NodeDAO.NodeRefQueryCallback; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.GUID; +import org.alfresco.util.Pair; +import org.springframework.context.ApplicationContext; + +/** + * Additional tests for the Node DAO. + * + * @see NodeDAO + * + * @author Derek Hulley + * @since 3.4 + */ +public class NodeDAOTest extends TestCase +{ + private ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + + private TransactionService transactionService; + private RetryingTransactionHelper txnHelper; + private NodeDAO nodeDAO; + + @Override + public void setUp() + { + ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); + transactionService = serviceRegistry.getTransactionService(); + txnHelper = transactionService.getRetryingTransactionHelper(); + txnHelper.setMinRetryWaitMs(10); + txnHelper.setRetryWaitIncrementMs(10); + txnHelper.setMaxRetryWaitMs(50); + + nodeDAO = (NodeDAO) ctx.getBean("nodeDAO"); + } + + public void testTransaction() throws Throwable + { + RetryingTransactionCallback getTxnIdCallback = new RetryingTransactionCallback() + { + public Long execute() throws Throwable + { + return nodeDAO.getCurrentTransactionId(); + } + }; + // No txn + try + { + getTxnIdCallback.execute(); + fail("Should have failed when running outside of a transaction"); + } + catch (Throwable e) + { + // Expected + } + // Read-only + try + { + txnHelper.doInTransaction(getTxnIdCallback, true); + fail("Should have failed when running in read-only transaction"); + } + catch (Throwable e) + { + // Expected + } + // First success + Long txnId1 = txnHelper.doInTransaction(getTxnIdCallback); + assertNotNull("No txn ID 1", txnId1); + Long txnId2 = txnHelper.doInTransaction(getTxnIdCallback); + assertNotNull("No txn ID 2", txnId2); + assertTrue("2nd ID should be larger than first", txnId2.compareTo(txnId1) > 0); + } + + /** + * TODO: Clean up after test or force indexing on the stores + */ + public void xtestNewStore() throws Exception + { + final StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_TEST, getName() + "-" + GUID.generate()); + RetryingTransactionCallback> callback = new RetryingTransactionCallback>() + { + public Pair execute() throws Throwable + { + return nodeDAO.newStore(storeRef); + } + }; + Pair rootNodePair = txnHelper.doInTransaction(callback); + assertNotNull(rootNodePair); + assertEquals("Root node has incorrect store", storeRef, rootNodePair.getSecond().getStoreRef()); + // Should fail second time + try + { + txnHelper.doInTransaction(callback); + fail("Should not be able to create same store."); + } + catch (Throwable e) + { + // Expected + } + } + + public void testGetNodesWithAspects() throws Throwable + { + NodeRefQueryCallback callback = new NodeRefQueryCallback() + { + public boolean handle(Pair nodePair) + { + // Don't need more + return false; + } + }; + nodeDAO.getNodesWithAspect(ContentModel.ASPECT_AUDITABLE, 1L, 5, callback); + } + + public void testGetPrimaryChildAcls() throws Throwable + { + List acls = nodeDAO.getPrimaryChildrenAcls(1L); + assertNotNull("Null list", acls); + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/node/NodeEntity.java b/source/java/org/alfresco/repo/domain/node/NodeEntity.java new file mode 100644 index 0000000000..938359cb2c --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/NodeEntity.java @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.Pair; + +/** + * Bean to convey alf_node data. + * + * @author Derek Hulley + * @since 3.4 + */ +public class NodeEntity implements Node +{ + private boolean locked; + + private Long id; + private Long version; + private StoreEntity store; + private String uuid; + private Long typeQNameId; + private Long aclId; + private Boolean deleted; + private TransactionEntity transaction; + private AuditablePropertiesEntity auditableProperties; + + /** + * Required default constructor + */ + public NodeEntity() + { + locked = false; + } + + /** + * Helper constructor to build the necessary elements to fulfill the {@link #getNodeRef()} query + */ + /* package */ NodeEntity(NodeRef nodeRef) + { + this(); + this.store = new StoreEntity(); + this.store.setProtocol(nodeRef.getStoreRef().getProtocol()); + this.store.setIdentifier(nodeRef.getStoreRef().getIdentifier()); + this.uuid = nodeRef.getId(); + } + + /** + * Helper copy constructor + */ + /* package */ NodeEntity(Node node) + { + this.id = node.getId(); + this.version = node.getVersion(); + this.store = node.getStore(); + this.uuid = node.getUuid(); + this.typeQNameId = node.getTypeQNameId(); + this.aclId = node.getAclId(); + this.deleted = node.getDeleted(); + this.transaction = node.getTransaction(); + this.auditableProperties = node.getAuditableProperties(); + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("NodeEntity") + .append("[ ID=").append(id); + if (store != null) + { + sb.append(", store=").append(store.getProtocol()).append("://").append(store.getIdentifier()); + } + else + { + sb.append(", store=").append("null"); + } + sb.append(", uuid=").append(uuid) + .append(", typeQNameId=").append(typeQNameId) + .append(", aclId=").append(aclId) + .append(", deleted=").append(deleted) + .append(", transaction=").append(transaction) + .append(", auditProps=").append(auditableProperties) + .append("]"); + return sb.toString(); + } + + /** + * Lock the entity against further updates to prevent accidental modification + */ + public void lock() + { + locked = true; + } + + private final void checkLock() + { + if (locked) + { + throw new IllegalStateException("The entity is locked against updates: " + this); + } + } + + public void incrementVersion() + { + if (version >= Short.MAX_VALUE) + { + this.version = 0L; + } + else + { + this.version++; + } + } + + public NodeRef getNodeRef() + { + return new NodeRef(store.getStoreRef(), uuid); + } + + public Pair getNodePair() + { + return new Pair(id, getNodeRef()); + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + checkLock(); + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + checkLock(); + this.version = version; + } + + public StoreEntity getStore() + { + return store; + } + + public void setStore(StoreEntity store) + { + checkLock(); + this.store = store; + } + + public String getUuid() + { + return uuid; + } + + public void setUuid(String uuid) + { + checkLock(); + this.uuid = uuid; + } + + public Long getTypeQNameId() + { + return typeQNameId; + } + + public void setTypeQNameId(Long typeQNameId) + { + checkLock(); + this.typeQNameId = typeQNameId; + } + + public Long getAclId() + { + return aclId; + } + + public void setAclId(Long aclId) + { + checkLock(); + this.aclId = aclId; + } + + public Boolean getDeleted() + { + return deleted; + } + + public void setDeleted(Boolean deleted) + { + checkLock(); + this.deleted = deleted; + } + + public TransactionEntity getTransaction() + { + return transaction; + } + + public void setTransaction(TransactionEntity transaction) + { + checkLock(); + this.transaction = transaction; + } + + public AuditablePropertiesEntity getAuditableProperties() + { + return auditableProperties; + } + + public void setAuditableProperties(AuditablePropertiesEntity auditableProperties) + { + checkLock(); + this.auditableProperties = auditableProperties; + } +} diff --git a/source/java/org/alfresco/repo/domain/node/NodeIdAndAclId.java b/source/java/org/alfresco/repo/domain/node/NodeIdAndAclId.java new file mode 100644 index 0000000000..867c9295ba --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/NodeIdAndAclId.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +/** + * Simple interface for beans carrying basic Node ID and related ACL ID data + * + * @author andyh + */ +public interface NodeIdAndAclId +{ + public abstract Long getId(); + + public abstract Long getAclId(); +} diff --git a/source/java/org/alfresco/repo/domain/node/NodePropertyEntity.java b/source/java/org/alfresco/repo/domain/node/NodePropertyEntity.java new file mode 100644 index 0000000000..fadbc43fc8 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/NodePropertyEntity.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.util.List; + +/** + * Bean to convey alf_node_properties data. + * + * @author Derek Hulley + * @since 3.4 + */ +public class NodePropertyEntity +{ + private Long nodeId; + private NodePropertyKey key; + private NodePropertyValue value; + /** Carries data for queries and updates */ + private List qnameIds; + + /** + * Required default constructor + */ + public NodePropertyEntity() + { + } + + @Override + public String toString() + { + return "NodePropertyEntity [node=" + nodeId + ", key=" + key + ", value=" + value + "]"; + } + + public Long getNodeId() + { + return nodeId; + } + + public void setNodeId(Long nodeId) + { + this.nodeId = nodeId; + } + + public NodePropertyKey getKey() + { + return key; + } + + public void setKey(NodePropertyKey key) + { + this.key = key; + } + + public NodePropertyValue getValue() + { + return value; + } + + public void setValue(NodePropertyValue value) + { + this.value = value; + } + + public List getQnameIds() + { + return qnameIds; + } + + public void setQnameIds(List qnameIds) + { + this.qnameIds = qnameIds; + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/node/NodePropertyHelper.java b/source/java/org/alfresco/repo/domain/node/NodePropertyHelper.java new file mode 100644 index 0000000000..0e6c2c3262 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/NodePropertyHelper.java @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.domain.ContentDataId; +import org.alfresco.repo.domain.contentdata.ContentDataDAO; +import org.alfresco.repo.domain.locale.LocaleDAO; +import org.alfresco.repo.domain.qname.QNameDAO; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; +import org.alfresco.service.cmr.dictionary.DictionaryException; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.dictionary.PropertyDefinition; +import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.MLText; +import org.alfresco.service.cmr.repository.datatype.TypeConversionException; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * This class provides services for translating exploded properties + * (as persisted in alf_node_properties) in the public form, which is a + * Map of values keyed by their QName. + * + * @author Derek Hulley + * @since 3.4 + */ +public class NodePropertyHelper +{ + private static final Log logger = LogFactory.getLog(NodePropertyHelper.class); + + private final DictionaryService dictionaryService; + private final QNameDAO qnameDAO; + private final LocaleDAO localeDAO; + private final ContentDataDAO contentDataDAO; + + /** + * Construct the helper with the appropriate DAOs and services + */ + public NodePropertyHelper( + DictionaryService dictionaryService, + QNameDAO qnameDAO, + LocaleDAO localeDAO, + ContentDataDAO contentDataDAO) + { + this.dictionaryService = dictionaryService; + this.qnameDAO = qnameDAO; + this.localeDAO = localeDAO; + this.contentDataDAO = contentDataDAO; + } + + public Map convertToPersistentProperties(Map in) + { + Map propertyMap = new HashMap( + in.size() + 5); + for (Map.Entry entry : in.entrySet()) + { + Serializable value = entry.getValue(); + // Get the qname ID + QName propertyQName = entry.getKey(); + Long propertyQNameId = qnameDAO.getOrCreateQName(propertyQName).getFirst(); + // Get the locale ID + Long propertylocaleId = localeDAO.getOrCreateDefaultLocalePair().getFirst(); + // Get the property definition, if available + PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); + // Add it to the map + addValueToPersistedProperties( + propertyMap, + propertyDef, + NodePropertyHelper.IDX_NO_COLLECTION, + propertyQNameId, + propertylocaleId, + value); + } + // Done + return propertyMap; + } + + /** + * The collection index used to indicate that the value is not part of a collection. All values from zero up are + * used for real collection indexes. + */ + private static final int IDX_NO_COLLECTION = -1; + + /** + * A method that adds properties to the given map. It copes with collections. + * + * @param propertyDef the property definition (null is allowed) + * @param collectionIndex the index of the property in the collection or -1 if we are not yet processing a + * collection + */ + private void addValueToPersistedProperties( + Map propertyMap, + PropertyDefinition propertyDef, + int collectionIndex, + Long propertyQNameId, + Long propertyLocaleId, + Serializable value) + { + if (value == null) + { + // The property is null. Null is null and cannot be massaged any other way. + NodePropertyValue npValue = makeNodePropertyValue(propertyDef, null); + NodePropertyKey npKey = new NodePropertyKey(); + npKey.setListIndex(collectionIndex); + npKey.setQnameId(propertyQNameId); + npKey.setLocaleId(propertyLocaleId); + // Add it to the map + propertyMap.put(npKey, npValue); + // Done + return; + } + + // Get or spoof the property datatype + QName propertyTypeQName; + if (propertyDef == null) // property not recognised + { + // allow it for now - persisting excess properties can be useful sometimes + propertyTypeQName = DataTypeDefinition.ANY; + } + else + { + propertyTypeQName = propertyDef.getDataType().getName(); + } + + // A property may appear to be multi-valued if the model definition is loose and + // an unexploded collection is passed in. Otherwise, use the model-defined behaviour + // strictly. + boolean isMultiValued; + if (propertyTypeQName.equals(DataTypeDefinition.ANY)) + { + // It is multi-valued if required (we are not in a collection and the property is a new collection) + isMultiValued = (value != null) && (value instanceof Collection) + && (collectionIndex == IDX_NO_COLLECTION); + } + else + { + isMultiValued = propertyDef.isMultiValued(); + } + + // Handle different scenarios. + // - Do we need to explode a collection? + // - Does the property allow collections? + if (collectionIndex == IDX_NO_COLLECTION && isMultiValued && !(value instanceof Collection)) + { + // We are not (yet) processing a collection but the property should be part of a collection + addValueToPersistedProperties( + propertyMap, + propertyDef, + 0, + propertyQNameId, + propertyLocaleId, + value); + } + else if (collectionIndex == IDX_NO_COLLECTION && value instanceof Collection) + { + // We are not (yet) processing a collection and the property is a collection i.e. needs exploding + // Check that multi-valued properties are supported if the property is a collection + if (!isMultiValued) + { + throw new DictionaryException("A single-valued property of this type may not be a collection: \n" + + " Property: " + propertyDef + "\n" + " Type: " + propertyTypeQName + "\n" + " Value: " + + value); + } + // We have an allowable collection. + @SuppressWarnings("unchecked") + Collection collectionValues = (Collection) value; + // Persist empty collections directly. This is handled by the NodePropertyValue. + if (collectionValues.size() == 0) + { + NodePropertyValue npValue = makeNodePropertyValue(null, + (Serializable) collectionValues); + NodePropertyKey npKey = new NodePropertyKey(); + npKey.setListIndex(NodePropertyHelper.IDX_NO_COLLECTION); + npKey.setQnameId(propertyQNameId); + npKey.setLocaleId(propertyLocaleId); + // Add it to the map + propertyMap.put(npKey, npValue); + } + // Break it up and recurse to persist the values. + collectionIndex = -1; + for (Object collectionValueObj : collectionValues) + { + collectionIndex++; + if (collectionValueObj != null && !(collectionValueObj instanceof Serializable)) + { + throw new IllegalArgumentException("Node properties must be fully serializable, " + + "including values contained in collections. \n" + " Property: " + propertyDef + "\n" + + " Index: " + collectionIndex + "\n" + " Value: " + collectionValueObj); + } + Serializable collectionValue = (Serializable) collectionValueObj; + try + { + addValueToPersistedProperties( + propertyMap, + propertyDef, + collectionIndex, + propertyQNameId, + propertyLocaleId, + collectionValue); + } + catch (Throwable e) + { + throw new AlfrescoRuntimeException("Failed to persist collection entry: \n" + " Property: " + + propertyDef + "\n" + " Index: " + collectionIndex + "\n" + " Value: " + + collectionValue, e); + } + } + } + else + { + // We are either processing collection elements OR the property is not a collection + // Collections of collections are only supported by type d:any + if (value instanceof Collection && !propertyTypeQName.equals(DataTypeDefinition.ANY)) + { + throw new DictionaryException( + "Collections of collections (Serializable) are only supported by type 'd:any': \n" + + " Property: " + propertyDef + "\n" + " Type: " + propertyTypeQName + "\n" + + " Value: " + value); + } + // Handle ContentData + // We used to check the property type, but we now handle d:any ContentData as well + if (value instanceof ContentData) + { + // We keep the ContentData i.e. we treat it as a low-level property that will be handled externally. + // This will be converted to a String and persisted as such unless the value is ultimately + // replaced by and ID-based ContentData reference +// // Needs converting to an ID +// ContentData contentData = (ContentData) value; +// Long contentDataId = contentDataDAO.createContentData(contentData).getFirst(); +// value = new ContentDataId(contentDataId); + } + // Handle MLText + if (value instanceof MLText) + { + // This needs to be split up into individual strings + MLText mlTextValue = (MLText) value; + for (Map.Entry mlTextEntry : mlTextValue.entrySet()) + { + Locale mlTextLocale = mlTextEntry.getKey(); + String mlTextStr = mlTextEntry.getValue(); + // Get the Locale ID for the text + Long mlTextLocaleId = localeDAO.getOrCreateLocalePair(mlTextLocale).getFirst(); + // This is persisted against the current locale, but as a d:text instance + NodePropertyValue npValue = new NodePropertyValue(DataTypeDefinition.TEXT, mlTextStr); + NodePropertyKey npKey = new NodePropertyKey(); + npKey.setListIndex(collectionIndex); + npKey.setQnameId(propertyQNameId); + npKey.setLocaleId(mlTextLocaleId); + // Add it to the map + propertyMap.put(npKey, npValue); + } + } + else + { + NodePropertyValue npValue = makeNodePropertyValue(propertyDef, value); + NodePropertyKey npKey = new NodePropertyKey(); + npKey.setListIndex(collectionIndex); + npKey.setQnameId(propertyQNameId); + npKey.setLocaleId(propertyLocaleId); + // Add it to the map + propertyMap.put(npKey, npValue); + } + } + } + + /** + * Helper method to convert the Serializable value into a full, persistable {@link NodePropertyValue}. + *

+ * Where the property definition is null, the value will take on the {@link DataTypeDefinition#ANY generic ANY} + * value. + *

+ * Collections are NOT supported. These must be split up by the calling code before calling this method. Map + * instances are supported as plain serializable instances. + * + * @param propertyDef the property dictionary definition, may be null + * @param value the value, which will be converted according to the definition - may be null + * @return Returns the persistable property value + */ + private NodePropertyValue makeNodePropertyValue(PropertyDefinition propertyDef, Serializable value) + { + // get property attributes + final QName propertyTypeQName; + if (propertyDef == null) // property not recognised + { + // allow it for now - persisting excess properties can be useful sometimes + propertyTypeQName = DataTypeDefinition.ANY; + } + else + { + propertyTypeQName = propertyDef.getDataType().getName(); + } + try + { + NodePropertyValue propertyValue = new NodePropertyValue(propertyTypeQName, value); + // done + return propertyValue; + } + catch (TypeConversionException e) + { + throw new TypeConversionException( + "The property value is not compatible with the type defined for the property: \n" + " property: " + + (propertyDef == null ? "unknown" : propertyDef) + "\n" + " value: " + value + "\n" + + " value type: " + value.getClass(), e); + } + } + + public Serializable getPublicProperty( + Map propertyValues, + QName propertyQName) + { + // Get the qname ID + Pair qnamePair = qnameDAO.getQName(propertyQName); + if (qnamePair == null) + { + // There is no persisted property with that QName, so we can't match anything + return null; + } + Long qnameId = qnamePair.getFirst(); + // Now loop over the properties and extract those with the given qname ID + SortedMap scratch = new TreeMap(); + for (Map.Entry entry : propertyValues.entrySet()) + { + NodePropertyKey propertyKey = entry.getKey(); + if (propertyKey.getQnameId().equals(qnameId)) + { + scratch.put(propertyKey, entry.getValue()); + } + } + // If we found anything, then collapse the properties to a Serializable + if (scratch.size() > 0) + { + PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); + Serializable collapsedValue = collapsePropertiesWithSameQName(propertyDef, scratch); + return collapsedValue; + } + else + { + return null; + } + } + + public Map convertToPublicProperties(Map propertyValues) + { + Map propertyMap = new HashMap(propertyValues.size(), 1.0F); + // Shortcut + if (propertyValues.size() == 0) + { + return propertyMap; + } + // We need to process the properties in order + SortedMap sortedPropertyValues = new TreeMap( + propertyValues); + // A working map. Ordering is important. + SortedMap scratch = new TreeMap(); + // Iterate (sorted) over the map entries and extract values with the same qname + Long currentQNameId = Long.MIN_VALUE; + Iterator> iterator = sortedPropertyValues.entrySet().iterator(); + while (true) + { + Long nextQNameId = null; + NodePropertyKey nextPropertyKey = null; + NodePropertyValue nextPropertyValue = null; + // Record the next entry's values + if (iterator.hasNext()) + { + Map.Entry entry = iterator.next(); + nextPropertyKey = entry.getKey(); + nextPropertyValue = entry.getValue(); + nextQNameId = nextPropertyKey.getQnameId(); + } + // If the QName is going to change, and we have some entries to process, then process them. + if (scratch.size() > 0 && (nextQNameId == null || !nextQNameId.equals(currentQNameId))) + { + QName currentQName = qnameDAO.getQName(currentQNameId).getSecond(); + PropertyDefinition currentPropertyDef = dictionaryService.getProperty(currentQName); + // We have added something to the scratch properties but the qname has just changed + Serializable collapsedValue = null; + // We can shortcut if there is only one value + if (scratch.size() == 1) + { + // There is no need to collapse list indexes + collapsedValue = collapsePropertiesWithSameQNameAndListIndex(currentPropertyDef, scratch); + } + else + { + // There is more than one value so the list indexes need to be collapsed + collapsedValue = collapsePropertiesWithSameQName(currentPropertyDef, scratch); + } + // If the property is multi-valued then the output property must be a collection + if (currentPropertyDef != null && currentPropertyDef.isMultiValued()) + { + if (collapsedValue != null && !(collapsedValue instanceof Collection)) + { + // Can't use Collections.singletonList: ETHREEOH-1172 + ArrayList collection = new ArrayList(1); + collection.add(collapsedValue); + collapsedValue = collection; + } + } + // Store the value + propertyMap.put(currentQName, collapsedValue); + // Reset + scratch.clear(); + } + if (nextQNameId != null) + { + // Add to the current entries + scratch.put(nextPropertyKey, nextPropertyValue); + currentQNameId = nextQNameId; + } + else + { + // There is no next value to process + break; + } + } + // Done + return propertyMap; + } + + private Serializable collapsePropertiesWithSameQName( + PropertyDefinition propertyDef, + SortedMap sortedPropertyValues) + { + Serializable result = null; + Collection collectionResult = null; + // A working map. Ordering is not important for this map. + Map scratch = new HashMap(3); + // Iterate (sorted) over the map entries and extract values with the same list index + Integer currentListIndex = Integer.MIN_VALUE; + Iterator> iterator = sortedPropertyValues.entrySet().iterator(); + while (true) + { + Integer nextListIndex = null; + NodePropertyKey nextPropertyKey = null; + NodePropertyValue nextPropertyValue = null; + // Record the next entry's values + if (iterator.hasNext()) + { + Map.Entry entry = iterator.next(); + nextPropertyKey = entry.getKey(); + nextPropertyValue = entry.getValue(); + nextListIndex = nextPropertyKey.getListIndex(); + } + // If the list index is going to change, and we have some entries to process, then process them. + if (scratch.size() > 0 && (nextListIndex == null || !nextListIndex.equals(currentListIndex))) + { + // We have added something to the scratch properties but the index has just changed + Serializable collapsedValue = collapsePropertiesWithSameQNameAndListIndex(propertyDef, scratch); + // Store. If there is a value already, then we must build a collection. + if (result == null) + { + result = collapsedValue; + } + else if (collectionResult != null) + { + // We have started a collection, so just add the value to it. + collectionResult.add(collapsedValue); + } + else + { + // We already had a result, and now have another. A collection has not been + // started. We start a collection and explicitly keep track of it so that + // we don't get mixed up with collections of collections (ETHREEOH-2064). + collectionResult = new ArrayList(20); + collectionResult.add(result); // Add the first result + collectionResult.add(collapsedValue); // Add the new value + result = (Serializable) collectionResult; + } + // Reset + scratch.clear(); + } + if (nextListIndex != null) + { + // Add to the current entries + scratch.put(nextPropertyKey, nextPropertyValue); + currentListIndex = nextListIndex; + } + else + { + // There is no next value to process + break; + } + } + // Make sure that multi-valued properties are returned as a collection + if (propertyDef != null && propertyDef.isMultiValued() && result != null && !(result instanceof Collection)) + { + // Can't use Collections.singletonList: ETHREEOH-1172 + ArrayList collection = new ArrayList(1); + collection.add(result); + result = collection; + } + // Done + return result; + } + + /** + * At this level, the properties have the same qname and list index. They can only be separated by locale. + * Typically, MLText will fall into this category as only. + *

+ * If there are multiple values then they can only be separated by locale. If they are separated by locale, then + * they have to be text-based. This means that the only way to store them is via MLText. Any other multi-locale + * properties cannot be deserialized. + */ + private Serializable collapsePropertiesWithSameQNameAndListIndex( + PropertyDefinition propertyDef, + Map propertyValues) + { + int propertyValuesSize = propertyValues.size(); + Serializable value = null; + if (propertyValuesSize == 0) + { + // Nothing to do + } + for (Map.Entry entry : propertyValues.entrySet()) + { + NodePropertyKey propertyKey = entry.getKey(); + NodePropertyValue propertyValue = entry.getValue(); + + if (propertyValuesSize == 1 + && (propertyDef == null || !propertyDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT))) + { + // This is the only value and it is NOT to be converted to MLText + value = makeSerializableValue(propertyDef, propertyValue); + } + else + { + // There are multiple values, so add them to MLText + MLText mltext = (value == null) ? new MLText() : (MLText) value; + try + { + String mlString = (String) propertyValue.getValue(DataTypeDefinition.TEXT); + // Get the locale + Long localeId = propertyKey.getLocaleId(); + Locale locale = localeDAO.getLocalePair(localeId).getSecond(); + // Add to the MLText object + mltext.addValue(locale, mlString); + } + catch (TypeConversionException e) + { + // Ignore + logger.warn("Unable to add property value to MLText instance: " + propertyValue); + } + value = mltext; + } + } + // Done + return value; + } + + /** + * Extracts the externally-visible property from the persistable value. + * + * @param propertyDef the model property definition - may be null + * @param propertyValue the persisted property + * @return Returns the value of the property in the format dictated by the property definition, + * or null if the property value is null + */ + public Serializable makeSerializableValue(PropertyDefinition propertyDef, NodePropertyValue propertyValue) + { + if (propertyValue == null) + { + return null; + } + // get property attributes + final QName propertyTypeQName; + if (propertyDef == null) + { + // allow this for now + propertyTypeQName = DataTypeDefinition.ANY; + } + else + { + propertyTypeQName = propertyDef.getDataType().getName(); + } + try + { + Serializable value = propertyValue.getValue(propertyTypeQName); + // Handle conversions to and from ContentData + if (value instanceof ContentDataId) + { + // ContentData used to be persisted as a String and then as a Long. + // Now it has a special type to denote the ID + Long contentDataId = ((ContentDataId) value).getId(); + Pair contentDataPair = contentDataDAO.getContentData(contentDataId); + if (contentDataPair == null) + { + // It is invalid + value = null; + } + else + { + value = contentDataPair.getSecond(); + } + } + else if (propertyTypeQName.equals(DataTypeDefinition.CONTENT) && (value instanceof Long)) + { + // ContentData used to be persisted + Pair contentDataPair = contentDataDAO.getContentData((Long) value); + if (contentDataPair == null) + { + // It is invalid + value = null; + } + else + { + value = contentDataPair.getSecond(); + } + } + // done + return value; + } + catch (TypeConversionException e) + { + throw new TypeConversionException( + "The property value is not compatible with the type defined for the property: \n" + + " property: " + (propertyDef == null ? "unknown" : propertyDef) + "\n" + + " property value: " + propertyValue, e); + } + } +} diff --git a/source/java/org/alfresco/repo/domain/node/NodePropertyKey.java b/source/java/org/alfresco/repo/domain/node/NodePropertyKey.java new file mode 100644 index 0000000000..aa2abbedc6 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/NodePropertyKey.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.io.Serializable; + +import org.alfresco.util.EqualsHelper; + +/** + * Compound key for persistence of {@link org.alfresco.repo.domain.Node} + * + * @author Derek Hulley + * @since 3.4 + */ +public class NodePropertyKey implements Serializable, Comparable +{ + private static final long serialVersionUID = 3258695403221300023L; + + private Long qnameId; + private Long localeId; + private Integer listIndex; + + public NodePropertyKey() + { + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append("NodePropertyKey ") + .append(" [listIndex=").append(listIndex) + .append(", localeId=").append(localeId) + .append(", qnameId=").append(qnameId) + .append("]"); + return sb.toString(); + } + + public int hashCode() + { + return + (qnameId == null ? 0 : qnameId.hashCode()) + + (listIndex == null ? 0 : listIndex.hashCode()); + } + + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + else if (!(obj instanceof NodePropertyKey)) + { + return false; + } + // Compare in order of selectivity + NodePropertyKey that = (NodePropertyKey) obj; + return (EqualsHelper.nullSafeEquals(this.qnameId, that.qnameId) && + EqualsHelper.nullSafeEquals(this.listIndex, that.listIndex) && + EqualsHelper.nullSafeEquals(this.localeId, that.localeId) + ); + } + + /** + * throws ClassCastException if the object is not of the correct type + */ + public int compareTo(NodePropertyKey that) + { + // Comparision by priority: qnameId, listIndex, localeId, nodeId + int compare = this.qnameId.compareTo(that.qnameId); + if (compare != 0) + { + return compare; + } + compare = this.listIndex.compareTo(that.listIndex); + if (compare != 0) + { + return compare; + } + return this.localeId.compareTo(that.localeId); + } + + public Long getQnameId() + { + return qnameId; + } + + public void setQnameId(Long qnameId) + { + this.qnameId = qnameId; + } + + public Long getLocaleId() + { + return localeId; + } + + public void setLocaleId(Long localeId) + { + this.localeId = localeId; + } + + public Integer getListIndex() + { + return listIndex; + } + + public void setListIndex(Integer listIndex) + { + this.listIndex = listIndex; + } +} diff --git a/source/java/org/alfresco/repo/domain/NodePropertyValue.java b/source/java/org/alfresco/repo/domain/node/NodePropertyValue.java similarity index 93% rename from source/java/org/alfresco/repo/domain/NodePropertyValue.java rename to source/java/org/alfresco/repo/domain/node/NodePropertyValue.java index bd8be643f3..fef3daf6c2 100644 --- a/source/java/org/alfresco/repo/domain/NodePropertyValue.java +++ b/source/java/org/alfresco/repo/domain/node/NodePropertyValue.java @@ -1,22 +1,28 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2008 Alfresco Software Limited. * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.domain; +package org.alfresco.repo.domain.node; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -31,6 +37,7 @@ import java.util.Locale; import java.util.Map; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.domain.ContentDataId; import org.alfresco.repo.domain.schema.SchemaBootstrap; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.AssociationRef; @@ -52,6 +59,7 @@ import org.apache.commons.logging.LogFactory; * Immutable property value storage class. * * @author Derek Hulley + * @since 3.4 */ public class NodePropertyValue implements Cloneable, Serializable { @@ -767,13 +775,7 @@ public class NodePropertyValue implements Cloneable, Serializable { NodePropertyValue that = (NodePropertyValue) obj; return (this.actualType.equals(that.actualType) && - EqualsHelper.nullSafeEquals(this.booleanValue, that.booleanValue) && - EqualsHelper.nullSafeEquals(this.longValue, that.longValue) && - EqualsHelper.nullSafeEquals(this.floatValue, that.floatValue) && - EqualsHelper.nullSafeEquals(this.doubleValue, that.doubleValue) && - EqualsHelper.nullSafeEquals(this.stringValue, that.stringValue) && - EqualsHelper.nullSafeEquals(this.serializableValue, that.serializableValue) - ); + EqualsHelper.nullSafeEquals(this.getPersistedValue(), that.getPersistedValue())); } else @@ -1019,7 +1021,7 @@ public class NodePropertyValue implements Cloneable, Serializable // convert the type // In order to cope with historical data, where collections were serialized // regardless of type. - if (persistedValue instanceof Collection) + if (persistedValue instanceof Collection) { // We assume that the collection contained the correct type values. They would // have been converted on the way in. diff --git a/source/java/org/alfresco/repo/domain/node/NodeUpdateEntity.java b/source/java/org/alfresco/repo/domain/node/NodeUpdateEntity.java new file mode 100644 index 0000000000..cdcbb2aa3f --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/NodeUpdateEntity.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +/** + * Bean to convey alf_node update data. It uses the basic node data, but adds + * information to identify the properties that need updating. + * + * @author Derek Hulley + * @since 3.4 + */ +public class NodeUpdateEntity extends NodeEntity +{ + private boolean updateStore; + private boolean updateUuid; + private boolean updateTypeQNameId; + private boolean updateAclId; + private boolean updateDeleted; + private boolean updateTransaction; + private boolean updateAuditableProperties; + + /** + * Required default constructor + */ + public NodeUpdateEntity() + { + } + + /** + * Determine if this update represents anything new at all + */ + public boolean isUpdateAnything() + { + return updateAuditableProperties || updateTransaction || updateDeleted + || updateAclId || updateStore || updateUuid || updateTypeQNameId; + } + + public boolean isUpdateStore() + { + return updateStore; + } + + public void setUpdateStore(boolean updateStore) + { + this.updateStore = updateStore; + } + + public boolean isUpdateUuid() + { + return updateUuid; + } + + public void setUpdateUuid(boolean updateUuid) + { + this.updateUuid = updateUuid; + } + + public boolean isUpdateTypeQNameId() + { + return updateTypeQNameId; + } + + public void setUpdateTypeQNameId(boolean updateTypeQNameId) + { + this.updateTypeQNameId = updateTypeQNameId; + } + + public boolean isUpdateAclId() + { + return updateAclId; + } + + public void setUpdateAclId(boolean updateAclId) + { + this.updateAclId = updateAclId; + } + + public boolean isUpdateDeleted() + { + return updateDeleted; + } + + public void setUpdateDeleted(boolean updateDeleted) + { + this.updateDeleted = updateDeleted; + } + + public boolean isUpdateTransaction() + { + return updateTransaction; + } + + public void setUpdateTransaction(boolean updateTransaction) + { + this.updateTransaction = updateTransaction; + } + + public boolean isUpdateAuditableProperties() + { + return updateAuditableProperties; + } + + public void setUpdateAuditableProperties(boolean updateAuditableProperties) + { + this.updateAuditableProperties = updateAuditableProperties; + } +} diff --git a/source/java/org/alfresco/repo/domain/node/ParentAssocsInfo.java b/source/java/org/alfresco/repo/domain/node/ParentAssocsInfo.java new file mode 100644 index 0000000000..a334dde6ee --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/ParentAssocsInfo.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Object to keep hold of a node and it's parent associations. + * + * @author David Ward + * @author Derek Hulley + * @since 3.4 + */ +/* package */ class ParentAssocsInfo implements Serializable +{ + private static final long serialVersionUID = -2167221525380802365L; + + private static final Log logger = LogFactory.getLog(ParentAssocsInfo.class); + + private static Set warnedDuplicateParents = new HashSet(3); + + private final boolean isRoot; + private final boolean isStoreRoot; + private final Long primaryAssocId; + private final Map parentAssocsById; + + /** + * Constructor to provide clean initial version of a Node's parent association + */ + ParentAssocsInfo(boolean isRoot, boolean isStoreRoot, ChildAssocEntity parent) + { + this(isRoot, isStoreRoot, Collections.singletonList(parent)); + } + /** + * Constructor to provide clean initial version of a Node's parent associations + */ + ParentAssocsInfo(boolean isRoot, boolean isStoreRoot, List parents) + { + this.isRoot = isRoot; + this.isStoreRoot = isStoreRoot; + Long primaryAssocId = null; + // Build map of child associations + Map parentAssocsById = new HashMap(5); + for (ChildAssocEntity parentAssoc : parents) + { + Long parentAssocId = parentAssoc.getId(); + // Populate the results + parentAssocsById.put(parentAssocId, parentAssoc); + // Primary + if (parentAssoc.isPrimary()) + { + if (primaryAssocId == null) + { + primaryAssocId = parentAssocId; + } + else + { + // Warn about the duplicates + synchronized (warnedDuplicateParents) + { + Long childNodeId = parentAssoc.getChildNode().getId(); + boolean added = warnedDuplicateParents.add(childNodeId); + if (added) + { + logger.warn( + "Multiple primary associations: \n" + + " Node: " + childNodeId + "\n" + + " Associations: " + parents); + } + } + } + } + } + this.primaryAssocId = primaryAssocId; + // Protect the map from accidental modification + this.parentAssocsById = Collections.unmodifiableMap(parentAssocsById); + } + + /** + * Private constructor used to copy existing values. + */ + private ParentAssocsInfo( + boolean isRoot, + boolean isStoreRoot, + Map parentAssocsById, + Long primaryAssocId) + { + this.isRoot = isRoot; + this.isStoreRoot = isStoreRoot; + this.parentAssocsById = Collections.unmodifiableMap(parentAssocsById); + this.primaryAssocId = primaryAssocId; + } + + @Override + public String toString() + { + StringBuilder builder = new StringBuilder(); + builder.append("ParentAssocsInfo ") + .append("[isRoot=").append(isRoot) + .append(", isStoreRoot=").append(isStoreRoot) + .append(", parentAssocsById=").append(parentAssocsById) + .append(", primaryAssocId=").append(primaryAssocId) + .append("]"); + return builder.toString(); + } + + public boolean isRoot() + { + return isRoot; + } + + public boolean isStoreRoot() + { + return isStoreRoot; + } + + public Map getParentAssocs() + { + return parentAssocsById; + } + + public ChildAssocEntity getPrimaryParentAssoc() + { + return (primaryAssocId != null) ? parentAssocsById.get(primaryAssocId) : null; + } + + public ParentAssocsInfo changeIsRoot(boolean isRoot) + { + return new ParentAssocsInfo(isRoot, this.isRoot, parentAssocsById, primaryAssocId); + } + + public ParentAssocsInfo changeIsStoreRoot(boolean isStoreRoot) + { + return new ParentAssocsInfo(this.isRoot, isStoreRoot, parentAssocsById, primaryAssocId); + } + + public ParentAssocsInfo addAssoc(Long assocId, ChildAssocEntity parentAssoc) + { + Map parentAssocs = new HashMap(parentAssocsById); + parentAssocs.put(parentAssoc.getId(), parentAssoc); + return new ParentAssocsInfo(isRoot, isStoreRoot, parentAssocs, primaryAssocId); + } + + public ParentAssocsInfo removeAssoc(Long assocId) + { + Map parentAssocs = new HashMap(parentAssocsById); + parentAssocs.remove(assocId); + return new ParentAssocsInfo(isRoot, isStoreRoot, parentAssocs, primaryAssocId); + } +} diff --git a/source/java/org/alfresco/repo/domain/node/PrimaryChildrenAclUpdateEntity.java b/source/java/org/alfresco/repo/domain/node/PrimaryChildrenAclUpdateEntity.java new file mode 100644 index 0000000000..75103f863d --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/PrimaryChildrenAclUpdateEntity.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +/** + * Carry bulk acl update info. + * + * @author andyh + * @since 3.4 + * + */ +public class PrimaryChildrenAclUpdateEntity +{ + Long primaryParentNodeId; + Long optionalOldSharedAclIdInAdditionToNull; + Long newSharedAclId; + + public PrimaryChildrenAclUpdateEntity() + { + } + + public Long getPrimaryParentNodeId() + { + return primaryParentNodeId; + } + + public void setPrimaryParentNodeId(Long primaryParentNodeId) + { + this.primaryParentNodeId = primaryParentNodeId; + } + + public Long getOptionalOldSharedAclIdInAdditionToNull() + { + return optionalOldSharedAclIdInAdditionToNull; + } + + public void setOptionalOldSharedAclIdInAdditionToNull(Long optionalOldSharedAclIdInAdditionToNull) + { + this.optionalOldSharedAclIdInAdditionToNull = optionalOldSharedAclIdInAdditionToNull; + } + + public Long getNewSharedAclId() + { + return newSharedAclId; + } + + public void setNewSharedAclId(Long newSharedAclId) + { + this.newSharedAclId = newSharedAclId; + } + + public boolean getIsPrimary() + { + return true; + } + +} diff --git a/source/java/org/alfresco/repo/domain/node/ReferenceablePropertiesEntity.java b/source/java/org/alfresco/repo/domain/node/ReferenceablePropertiesEntity.java new file mode 100644 index 0000000000..07f94b9e17 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/ReferenceablePropertiesEntity.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; +import org.alfresco.service.namespace.QName; + +/** + * Class holding properties associated with the sys:referenceable aspect. + * This aspect is common enough to warrant direct inclusion on the Node entity. + * + * @author Derek Hulley + * @since 3.4 + */ +public class ReferenceablePropertiesEntity +{ + private static final Set REFERENCEABLE_PROP_QNAMES; + static + { + REFERENCEABLE_PROP_QNAMES = new HashSet(8); + REFERENCEABLE_PROP_QNAMES.add(ContentModel.PROP_STORE_PROTOCOL); + REFERENCEABLE_PROP_QNAMES.add(ContentModel.PROP_STORE_IDENTIFIER); + REFERENCEABLE_PROP_QNAMES.add(ContentModel.PROP_NODE_UUID); + REFERENCEABLE_PROP_QNAMES.add(ContentModel.PROP_NODE_DBID); + } + + /** + * @return Returns true if the property belongs to the sys:referenceable aspect + */ + public static boolean isReferenceableProperty(QName qname) + { + return REFERENCEABLE_PROP_QNAMES.contains(qname); + } + + /** + * Remove all {@link ContentModel#ASPECT_REFERENCEABLE referencable} properties + */ + public static void removeReferenceableProperties(Node node, Map properties) + { + properties.keySet().removeAll(REFERENCEABLE_PROP_QNAMES); + String name = DefaultTypeConverter.INSTANCE.convert(String.class, properties.get(ContentModel.PROP_NAME)); + if (name != null && name.equals(node.getUuid())) + { + // The cm:name matches the UUID, so drop it + properties.remove(ContentModel.PROP_NAME); + } + } + + /** + * Remove all {@link ContentModel#ASPECT_REFERENCEABLE referencable} properties + */ + public static void removeReferenceableProperties(Set propertyQNames) + { + propertyQNames.removeAll(REFERENCEABLE_PROP_QNAMES); + } + + /** + * Adds all {@link ContentModel#ASPECT_REFERENCEABLE referencable} properties. + */ + public static void addReferenceableProperties(Node node, Map properties) + { + Long nodeId = node.getId(); + NodeRef nodeRef = node.getNodeRef(); + properties.put(ContentModel.PROP_STORE_PROTOCOL, nodeRef.getStoreRef().getProtocol()); + properties.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier()); + properties.put(ContentModel.PROP_NODE_UUID, nodeRef.getId()); + properties.put(ContentModel.PROP_NODE_DBID, nodeId); + // add the ID as the name, if required + String name = DefaultTypeConverter.INSTANCE.convert(String.class, properties.get(ContentModel.PROP_NAME)); + if (name == null) + { + properties.put(ContentModel.PROP_NAME, nodeRef.getId()); + } + } + + public static Serializable getReferenceableProperty(Node node, QName qname) + { + Long nodeId = node.getId(); + NodeRef nodeRef = node.getNodeRef(); + 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(); + } + else if (qname.equals(ContentModel.PROP_NODE_DBID)) + { + return nodeId; + } + throw new IllegalArgumentException("Not sys:referenceable property: " + qname); + } +} diff --git a/source/java/org/alfresco/repo/domain/node/ServerEntity.java b/source/java/org/alfresco/repo/domain/node/ServerEntity.java new file mode 100644 index 0000000000..db87e8eca4 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/ServerEntity.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +/** + * Bean to represent alf_server data. + * + * @author Derek Hulley + * @since 3.4 + */ +public class ServerEntity +{ + private Long id; + private Long version; + private String ipAddress; + + /** + * Required default constructor + */ + public ServerEntity() + { + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("ServerEntity") + .append("[ ID=").append(id) + .append(", ipAddress=").append(ipAddress) + .append("]"); + return sb.toString(); + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + public String getIpAddress() + { + return ipAddress; + } + + public void setIpAddress(String ipAddress) + { + this.ipAddress = ipAddress; + } +} diff --git a/source/java/org/alfresco/repo/domain/node/StoreEntity.java b/source/java/org/alfresco/repo/domain/node/StoreEntity.java new file mode 100644 index 0000000000..294a9b1023 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/StoreEntity.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import org.alfresco.service.cmr.repository.StoreRef; + +/** + * Bean to capture StoreRef results. + * + * @author Derek Hulley + * @since 3.4 + */ +public class StoreEntity +{ + private Long id; + private Long version; + private String protocol; + private String identifier; + private NodeEntity rootNode; + + /** + * Required default constructor + */ + public StoreEntity() + { + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("StoreEntity") + .append("[ ID=").append(id) + .append(", protocol=").append(protocol) + .append(", identifier=").append(identifier) + .append(", rootNode=").append(rootNode) + .append("]"); + return sb.toString(); + } + + public StoreRef getStoreRef() + { + return new StoreRef(protocol, identifier); + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + public String getProtocol() + { + return protocol; + } + + public void setProtocol(String protocol) + { + this.protocol = protocol; + } + + public String getIdentifier() + { + return identifier; + } + + public void setIdentifier(String identifier) + { + this.identifier = identifier; + } + + public NodeEntity getRootNode() + { + return rootNode; + } + + public void setRootNode(NodeEntity rootNode) + { + this.rootNode = rootNode; + } +} diff --git a/source/java/org/alfresco/repo/domain/node/Transaction.java b/source/java/org/alfresco/repo/domain/node/Transaction.java new file mode 100644 index 0000000000..20c6176f87 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/Transaction.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +/** + * Interface for alf_transaction objects. + * + * @author Derek Hulley + * @since 3.4 + */ +public interface Transaction +{ + public Long getId(); + + public String getChangeTxnId(); + + public Long getCommitTimeMs(); +} diff --git a/source/java/org/alfresco/repo/domain/node/TransactionEntity.java b/source/java/org/alfresco/repo/domain/node/TransactionEntity.java new file mode 100644 index 0000000000..7da70c69e9 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/TransactionEntity.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +/** + * Bean to represent alf_transaction data. + * + * @author Derek Hulley + * @since 3.4 + */ +public class TransactionEntity implements Transaction +{ + private Long id; + private Long version; + private ServerEntity server; + private String changeTxnId; + private Long commitTimeMs; + + /** + * Required default constructor + */ + public TransactionEntity() + { + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("TransactionEntity") + .append("[ ID=").append(id) + .append(", server=").append(server) + .append(", changeTxnId=").append(changeTxnId) + .append(", commitTimeMs=").append(commitTimeMs) + .append("]"); + return sb.toString(); + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + public ServerEntity getServer() + { + return server; + } + + public void setServer(ServerEntity server) + { + this.server = server; + } + + public String getChangeTxnId() + { + return changeTxnId; + } + + public void setChangeTxnId(String changeTxnId) + { + this.changeTxnId = changeTxnId; + } + + public Long getCommitTimeMs() + { + return commitTimeMs; + } + + public void setCommitTimeMs(Long commitTimeMs) + { + this.commitTimeMs = commitTimeMs; + } +} diff --git a/source/java/org/alfresco/repo/domain/node/TransactionQueryEntity.java b/source/java/org/alfresco/repo/domain/node/TransactionQueryEntity.java new file mode 100644 index 0000000000..a2d93abe13 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/TransactionQueryEntity.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node; + +import java.util.List; + +/** + * Bean to represent carry query parameters for alf_transaction. + * + * @author Derek Hulley + * @since 3.4 + */ +public class TransactionQueryEntity +{ + private Long id; + private Long minId; + private Long maxId; + private Long minCommitTime; + private Long maxCommitTime; + private List includeTxnIds; + private List excludeTxnIds; + private Long excludeServerId; + private Boolean ascending; + private Long storeId; + + /** + * Required default constructor + */ + public TransactionQueryEntity() + { + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("TransactionQueryEntity") + .append("[ id=").append(id) + .append(", minId=").append(minId) + .append(", maxId=").append(maxId) + .append(", minCommitTime=").append(minCommitTime) + .append(", maxCommitTime=").append(maxCommitTime) + .append(", includeTxnIds=").append(includeTxnIds) + .append(", excludeTxnIds=").append(excludeTxnIds) + .append(", excludeServerId=").append(excludeServerId) + .append(", ascending=").append(ascending) + .append(", storeId=").append(storeId) + .append("]"); + return sb.toString(); + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getMinId() + { + return minId; + } + + public void setMinId(Long minId) + { + this.minId = minId; + } + + public Long getMaxId() + { + return maxId; + } + + public void setMaxId(Long maxId) + { + this.maxId = maxId; + } + + public Long getMinCommitTime() + { + return minCommitTime; + } + + public void setMinCommitTime(Long minCommitTime) + { + this.minCommitTime = minCommitTime; + } + + public Long getMaxCommitTime() + { + return maxCommitTime; + } + + public void setMaxCommitTime(Long maxCommitTime) + { + this.maxCommitTime = maxCommitTime; + } + + public List getIncludeTxnIds() + { + return includeTxnIds; + } + + public void setIncludeTxnIds(List includeTxnIds) + { + this.includeTxnIds = includeTxnIds; + } + + public List getExcludeTxnIds() + { + return excludeTxnIds; + } + + public void setExcludeTxnIds(List excludeTxnIds) + { + this.excludeTxnIds = excludeTxnIds; + } + + public Long getExcludeServerId() + { + return excludeServerId; + } + + public void setExcludeServerId(Long excludeServerId) + { + this.excludeServerId = excludeServerId; + } + + public Boolean getAscending() + { + return ascending; + } + + public void setAscending(Boolean ascending) + { + this.ascending = ascending; + } + + public Long getStoreId() + { + return storeId; + } + + public void setStoreId(Long storeId) + { + this.storeId = storeId; + } +} diff --git a/source/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java b/source/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java new file mode 100644 index 0000000000..aef526d5be --- /dev/null +++ b/source/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java @@ -0,0 +1,1244 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.node.ibatis; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.domain.node.AbstractNodeDAOImpl; +import org.alfresco.repo.domain.node.ChildAssocEntity; +import org.alfresco.repo.domain.node.NodeAspectsEntity; +import org.alfresco.repo.domain.node.NodeAssocEntity; +import org.alfresco.repo.domain.node.NodeEntity; +import org.alfresco.repo.domain.node.NodeIdAndAclId; +import org.alfresco.repo.domain.node.NodePropertyEntity; +import org.alfresco.repo.domain.node.NodePropertyKey; +import org.alfresco.repo.domain.node.NodePropertyValue; +import org.alfresco.repo.domain.node.NodeUpdateEntity; +import org.alfresco.repo.domain.node.PrimaryChildrenAclUpdateEntity; +import org.alfresco.repo.domain.node.ServerEntity; +import org.alfresco.repo.domain.node.StoreEntity; +import org.alfresco.repo.domain.node.Transaction; +import org.alfresco.repo.domain.node.TransactionEntity; +import org.alfresco.repo.domain.node.TransactionQueryEntity; +import org.alfresco.repo.domain.qname.QNameDAO; +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.StoreRef; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; +import org.springframework.orm.ibatis.SqlMapClientTemplate; +import org.springframework.util.Assert; + +import com.ibatis.sqlmap.client.event.RowHandler; +import com.sun.star.uno.RuntimeException; + +/** + * iBatis-specific extension of the Node abstract DAO + * + * @author Derek Hulley + * @since 3.4 + */ +public class NodeDAOImpl extends AbstractNodeDAOImpl +{ + private static final String SELECT_SERVER_BY_IPADDRESS = "alfresco.node.select_ServerByIpAddress"; + private static final String INSERT_SERVER = "alfresco.node.insert_Server"; + private static final String INSERT_TRANSACTION = "alfresco.node.insert_Transaction"; + private static final String UPDATE_TRANSACTION_COMMIT_TIME = "alfresco.node.update_TransactionCommitTime"; + private static final String DELETE_TRANSACTION_BY_ID = "alfresco.node.delete_TransactionById"; + private static final String INSERT_STORE = "alfresco.node.insert_Store"; + private static final String UPDATE_STORE_ROOT = "alfresco.node.update_StoreRoot"; + private static final String SELECT_STORE_ALL = "alfresco.node.select_StoreAll"; + private static final String SELECT_STORE_ROOT_NODE_BY_ID = "alfresco.node.select_StoreRootNodeById"; + private static final String SELECT_STORE_ROOT_NODE_BY_REF = "alfresco.node.select_StoreRootNodeByRef"; + private static final String INSERT_NODE = "alfresco.node.insert_Node"; + private static final String UPDATE_NODE = "alfresco.node.update_Node"; + private static final String DELETE_NODE_BY_ID = "alfresco.node.delete_NodeById"; + private static final String SELECT_NODE_BY_ID = "alfresco.node.select_NodeById"; + private static final String SELECT_NODE_BY_NODEREF = "alfresco.node.select_NodeByNodeRef"; + private static final String SELECT_NODE_PROPERTIES = "alfresco.node.select_NodeProperties"; + private static final String INSERT_NODE_PROPERTY = "alfresco.node.insert_NodeProperty"; + private static final String UPDATE_PRIMARY_CHILDREN_SHARED_ACL = "alfresco.node.update_PrimaryChildrenSharedAcl"; + private static final String SELECT_NODE_ASPECT_IDS = "alfresco.node.select_NodeAspectIds"; + private static final String INSERT_NODE_ASPECT = "alfresco.node.insert_NodeAspect"; + private static final String DELETE_NODE_ASPECTS = "alfresco.node.delete_NodeAspects"; + private static final String DELETE_NODE_PROPERTIES = "alfresco.node.delete_NodeProperties"; + private static final String SELECT_NODES_WITH_ASPECT_ID = "alfresco.node.select_NodesWithAspectId"; + private static final String INSERT_NODE_ASSOC = "alfresco.node.insert_NodeAssoc"; + private static final String DELETE_NODE_ASSOC = "alfresco.node.delete_NodeAssoc"; + private static final String DELETE_NODE_ASSOCS_TO_AND_FROM = "alfresco.node.delete_NodeAssocsToAndFrom"; + private static final String SELECT_NODE_ASSOCS_BY_SOURCE = "alfresco.node.select_NodeAssocsBySource"; + private static final String SELECT_NODE_ASSOCS_BY_TARGET = "alfresco.node.select_NodeAssocsByTarget"; + private static final String SELECT_NODE_PRIMARY_CHILD_ACLS = "alfresco.node.select_NodePrimaryChildAcls"; + private static final String INSERT_CHILD_ASSOC = "alfresco.node.insert_ChildAssoc"; + private static final String DELETE_CHILD_ASSOC_BY_ID = "alfresco.node.delete_ChildAssocById"; + private static final String UPDATE_CHILD_ASSOCS_INDEX = "alfresco.node.update_ChildAssocsIndex"; + private static final String UPDATE_CHILD_ASSOCS_UNIQUE_NAME = "alfresco.node.update_ChildAssocsUniqueName"; + private static final String DELETE_CHILD_ASSOCS_TO_AND_FROM = "alfresco.node.delete_ChildAssocsToAndFrom"; + private static final String SELECT_CHILD_ASSOC_BY_ID = "alfresco.node.select_ChildAssocById"; + private static final String SELECT_CHILD_ASSOCS_OF_PARENT = "alfresco.node.select_ChildAssocsOfParent"; + private static final String SELECT_CHILD_ASSOCS_OF_PARENT_WITHOUT_PARENT_ASSOCS_OF_TYPE = + "alfresco.node.select_ChildAssocsOfParentWithoutParentAssocsOfType"; + private static final String SELECT_PARENT_ASSOCS_OF_CHILD = "alfresco.node.select_ParentAssocsOfChild"; + private static final String UPDATE_PARENT_ASSOCS_OF_CHILD = "alfresco.node.update_ParentAssocsOfChild"; + private static final String SELECT_TXN_LAST = "alfresco.node.select_TxnLast"; + private static final String SELECT_TXN_NODES = "alfresco.node.select_TxnNodes"; + private static final String SELECT_TXNS = "alfresco.node.select_Txns"; + private static final String SELECT_TXN_COUNT = "alfresco.node.select_TxnCount"; + private static final String SELECT_TXN_NODE_COUNT = "alfresco.node.select_TxnNodeCount"; + private static final String SELECT_TXNS_UNUSED = "alfresco.node.select_TxnsUnused"; + private static final String SELECT_TXN_MIN_COMMIT_TIME = "alfresco.node.select_TxnMinCommitTime"; + private static final String SELECT_TXN_MAX_COMMIT_TIME = "alfresco.node.select_TxnMaxCommitTime"; + + private SqlMapClientTemplate template; + private QNameDAO qnameDAO; + private DictionaryService dictionaryService; + + public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) + { + this.template = sqlMapClientTemplate; + } + + @Override + public void setQnameDAO(QNameDAO qnameDAO) + { + this.qnameDAO = qnameDAO; + super.setQnameDAO(qnameDAO); + } + + @Override + public void setDictionaryService(DictionaryService dictionaryService) + { + this.dictionaryService = dictionaryService; + super.setDictionaryService(dictionaryService); + } + + public void startBatch() + { + try + { + template.getSqlMapClient().startBatch(); + } + catch (SQLException e) + { + throw new RuntimeException("Failed to start DAO batch.", e); + } + } + + public void executeBatch() + { + try + { + template.getSqlMapClient().executeBatch(); + } + catch (SQLException e) + { + throw new RuntimeException("Failed to start DAO batch.", e); + } + } + + @SuppressWarnings("unchecked") + @Override + protected ServerEntity selectServer(String ipAddress) + { + ServerEntity entity = new ServerEntity(); + entity.setIpAddress(ipAddress); + // Potentially more results if there is a case issue (unlikely) + List results = template.queryForList(SELECT_SERVER_BY_IPADDRESS, entity); + for (ServerEntity serverEntity : results) + { + // Take the first one that matches regardless of case + if (serverEntity.getIpAddress().equalsIgnoreCase(ipAddress)) + { + return serverEntity; + } + } + // There was no match + return null; + } + + @Override + protected Long insertServer(String ipAddress) + { + ServerEntity entity = new ServerEntity(); + entity.setVersion(1L); + entity.setIpAddress(ipAddress); + return (Long) template.insert(INSERT_SERVER, entity); + } + + @Override + protected Long insertTransaction(Long serverId, String changeTxnId, Long commitTimeMs) + { + ServerEntity server = new ServerEntity(); + server.setId(serverId); + TransactionEntity transaction = new TransactionEntity(); + transaction.setServer(server); + transaction.setVersion(1L); + transaction.setChangeTxnId(changeTxnId); + transaction.setCommitTimeMs(commitTimeMs); + return (Long) template.insert(INSERT_TRANSACTION, transaction); + } + + @Override + protected int updateTransaction(Long txnId, Long commitTimeMs) + { + TransactionEntity transaction = new TransactionEntity(); + transaction.setId(txnId); + transaction.setCommitTimeMs(commitTimeMs); + return template.update(UPDATE_TRANSACTION_COMMIT_TIME, transaction); + } + + @Override + protected int deleteTransaction(Long txnId) + { + TransactionEntity transaction = new TransactionEntity(); + transaction.setId(txnId); + return template.delete(DELETE_TRANSACTION_BY_ID, transaction); + } + + @SuppressWarnings("unchecked") + @Override + protected List selectAllStores() + { + return template.queryForList(SELECT_STORE_ALL); + } + + @Override + protected NodeEntity selectStoreRootNode(Long storeId) + { + StoreEntity store = new StoreEntity(); + store.setId(storeId); + return (NodeEntity) template.queryForObject(SELECT_STORE_ROOT_NODE_BY_ID, store); + } + + @Override + protected NodeEntity selectStoreRootNode(StoreRef storeRef) + { + StoreEntity store = new StoreEntity(); + store.setProtocol(storeRef.getProtocol()); + store.setIdentifier(storeRef.getIdentifier()); + return (NodeEntity) template.queryForObject(SELECT_STORE_ROOT_NODE_BY_REF, store); + } + + @Override + protected Long insertStore(StoreEntity store) + { + store.setVersion(1L); + return (Long) template.insert(INSERT_STORE, store); + } + + @Override + protected int updateStoreRoot(StoreEntity store) + { + return template.update(UPDATE_STORE_ROOT, store); + } + + @Override + protected Long insertNode(NodeEntity node) + { + node.setVersion(1L); + return (Long) template.insert(INSERT_NODE, node); + } + + @Override + protected int updateNode(NodeUpdateEntity nodeUpdate) + { + // Increment the version + nodeUpdate.incrementVersion(); + return template.update(UPDATE_NODE, nodeUpdate); + } + + @Override + protected void updatePrimaryChildrenSharedAclId( + Long primaryParentNodeId, + Long optionalOldSharedAlcIdInAdditionToNull, + Long newSharedAlcId) + { + PrimaryChildrenAclUpdateEntity primaryChildrenAclUpdateEntity = new PrimaryChildrenAclUpdateEntity(); + primaryChildrenAclUpdateEntity.setPrimaryParentNodeId(primaryParentNodeId); + primaryChildrenAclUpdateEntity.setOptionalOldSharedAclIdInAdditionToNull(optionalOldSharedAlcIdInAdditionToNull); + primaryChildrenAclUpdateEntity.setNewSharedAclId(newSharedAlcId); + + template.update(UPDATE_PRIMARY_CHILDREN_SHARED_ACL, primaryChildrenAclUpdateEntity); + } + + @Override + protected int deleteNodeById(Long nodeId, boolean deletedOnly) + { + NodeEntity node = new NodeEntity(); + node.setId(nodeId); + // Do we delete everything (false) or just nodes already marked as deleted (true) + node.setDeleted(deletedOnly); + return template.delete(DELETE_NODE_BY_ID, node); + } + + @Override + protected NodeEntity selectNodeById(Long id, Boolean deleted) + { + NodeEntity node = new NodeEntity(); + node.setId(id); + // Deleted + if (deleted != null) + { + node.setDeleted(deleted); + } + + return (NodeEntity) template.queryForObject(SELECT_NODE_BY_ID, node); + } + + @Override + protected NodeEntity selectNodeByNodeRef(NodeRef nodeRef, Boolean deleted) + { + StoreEntity store = new StoreEntity(); + StoreRef storeRef = nodeRef.getStoreRef(); + store.setProtocol(storeRef.getProtocol()); + store.setIdentifier(storeRef.getIdentifier()); + + NodeEntity node = new NodeEntity(); + // Store + node.setStore(store); + // UUID + node.setUuid(nodeRef.getId()); + // Deleted + if (deleted != null) + { + node.setDeleted(deleted); + } + + return (NodeEntity) template.queryForObject(SELECT_NODE_BY_NODEREF, node); + } + + /** + * Pull out the key-value pairs from the rows + */ + private Map makePersistentPropertiesMap(List rows) + { + Long nodeId = null; + Map props = new HashMap(27); + for (NodePropertyEntity row : rows) + { + if (row.getNodeId() == null) + { + throw new RuntimeException("Expect results with a Node ID: " + row); + } + if (nodeId == null) + { + nodeId = row.getNodeId(); + } + else if (!nodeId.equals(row.getNodeId())) + { + throw new RuntimeException("Results can only be interpreted for a single node."); + } + props.put(row.getKey(), row.getValue()); + } + // Done + return props; + } + + /** + * Convert key-value pairs into rows + */ + private List makePersistentRows(Long nodeId, Map map) + { + List rows = new ArrayList(map.size()); + for (Map.Entry entry : map.entrySet()) + { + NodePropertyEntity row = new NodePropertyEntity(); + row.setNodeId(nodeId); + row.setKey(entry.getKey()); + row.setValue(entry.getValue()); + rows.add(row); + } + // Done + return rows; + } + + protected Map selectNodeProperties(Long nodeId) + { + return selectNodeProperties(nodeId, Collections.emptySet()); + } + @SuppressWarnings("unchecked") + @Override + protected Map selectNodeProperties(Long nodeId, Set qnameIds) + { + NodePropertyEntity prop = new NodePropertyEntity(); + // Node + prop.setNodeId(nodeId); + // QName(s) + switch(qnameIds.size()) + { + case 0: + // Ignore + break; + case 1: + prop.setKey(new NodePropertyKey()); + prop.getKey().setQnameId(qnameIds.iterator().next()); + break; + default: + prop.setQnameIds(new ArrayList(qnameIds)); + } + + List rows = template.queryForList(SELECT_NODE_PROPERTIES, prop); + return makePersistentPropertiesMap(rows); + } + + @Override + protected int deleteNodeProperties(Long nodeId, Set qnameIds) + { + NodePropertyEntity prop = new NodePropertyEntity(); + // Node + prop.setNodeId(nodeId); + // QNames + if (qnameIds != null) + { + if (qnameIds.isEmpty()) + { + return 0; // Nothing to do + } + prop.setQnameIds(new ArrayList(qnameIds)); + } + + return template.delete(DELETE_NODE_PROPERTIES, prop); + } + + @Override + protected void deleteNodeProperties(Long nodeId, List propKeys) + { + Assert.notNull(nodeId, "Must have 'nodeId'"); + Assert.notNull(nodeId, "Must have 'propKeys'"); + + if (propKeys.size() == 0) + { + return; + } + + NodePropertyEntity prop = new NodePropertyEntity(); + // Node + prop.setNodeId(nodeId); + + startBatch(); + try + { + for (NodePropertyKey propKey : propKeys) + { + prop.setKey(propKey); + template.delete(DELETE_NODE_PROPERTIES, prop); + } + } + finally + { + executeBatch(); + } + } + + @Override + protected void insertNodeProperties(Long nodeId, Map persistableProps) + { + List rows = makePersistentRows(nodeId, persistableProps); + + startBatch(); + try + { + for (NodePropertyEntity row : rows) + { + template.insert(INSERT_NODE_PROPERTY, row); + } + } + finally + { + executeBatch(); + } + } + + @SuppressWarnings("unchecked") + @Override + protected Set selectNodeAspectIds(Long nodeId) + { + List aspectQNameIdList = template.queryForList(SELECT_NODE_ASPECT_IDS, nodeId); + return new HashSet(aspectQNameIdList); + } + + @Override + protected void insertNodeAspect(Long nodeId, Long qnameId) + { + Map aspectParameters = new HashMap(5); + aspectParameters.put("nodeId", nodeId); + aspectParameters.put("qnameId", qnameId); + template.insert(INSERT_NODE_ASPECT, aspectParameters); + } + + @Override + protected int deleteNodeAspects(Long nodeId, Set qnameIds) + { + NodeAspectsEntity nodeAspects = new NodeAspectsEntity(); + nodeAspects.setId(nodeId); + if (qnameIds != null && !qnameIds.isEmpty()) + { + nodeAspects.setAspectQNameIds(new ArrayList(qnameIds)); // Null means all + } + return template.delete(DELETE_NODE_ASPECTS, nodeAspects); + } + + @Override + protected void selectNodesWithAspect(Long qnameId, Long minNodeId, final NodeRefQueryCallback resultsCallback) + { + RowHandler rowHandler = new RowHandler() + { + public void handleRow(Object valueObject) + { + NodeEntity entity = (NodeEntity) valueObject; + Pair nodePair = new Pair(entity.getId(), entity.getNodeRef()); + resultsCallback.handle(nodePair); + } + }; + + Map parameters = new HashMap(5); + parameters.put("minNodeId", minNodeId); + parameters.put("qnameId", qnameId); + template.queryWithRowHandler(SELECT_NODES_WITH_ASPECT_ID, parameters,rowHandler); + } + + @Override + protected Long insertNodeAssoc(Long sourceNodeId, Long targetNodeId, Long assocTypeQNameId) + { + NodeAssocEntity assoc = new NodeAssocEntity(); + assoc.setVersion(1L); + assoc.setTypeQNameId(assocTypeQNameId); + // Source + NodeEntity sourceNode = new NodeEntity(); + sourceNode.setId(sourceNodeId); + assoc.setSourceNode(sourceNode); + // Target + NodeEntity targetNode = new NodeEntity(); + targetNode.setId(targetNodeId); + assoc.setTargetNode(targetNode); + + return (Long) template.insert(INSERT_NODE_ASSOC, assoc); + } + + @Override + protected int deleteNodeAssoc(Long sourceNodeId, Long targetNodeId, Long assocTypeQNameId) + { + NodeAssocEntity assoc = new NodeAssocEntity(); + assoc.setTypeQNameId(assocTypeQNameId); + // Source + NodeEntity sourceNode = new NodeEntity(); + sourceNode.setId(sourceNodeId); + assoc.setSourceNode(sourceNode); + // Target + NodeEntity targetNode = new NodeEntity(); + targetNode.setId(targetNodeId); + assoc.setTargetNode(targetNode); + + return template.delete(DELETE_NODE_ASSOC, assoc); + } + + @Override + protected int deleteNodeAssocsToAndFrom(Long nodeId) + { + NodeAssocEntity assoc = new NodeAssocEntity(); + // Source + NodeEntity sourceNode = new NodeEntity(); + sourceNode.setId(nodeId); + assoc.setSourceNode(sourceNode); + // Target + NodeEntity targetNode = new NodeEntity(); + targetNode.setId(nodeId); + assoc.setTargetNode(targetNode); + + return template.delete(DELETE_NODE_ASSOCS_TO_AND_FROM, assoc); + } + + @Override + protected int deleteNodeAssocsToAndFrom(Long nodeId, Set assocTypeQNameIds) + { + NodeAssocEntity assoc = new NodeAssocEntity(); + assoc.setTypeQNameIds(new ArrayList(assocTypeQNameIds)); + // Source + NodeEntity sourceNode = new NodeEntity(); + sourceNode.setId(nodeId); + assoc.setSourceNode(sourceNode); + // Target + NodeEntity targetNode = new NodeEntity(); + targetNode.setId(nodeId); + assoc.setTargetNode(targetNode); + + return template.delete(DELETE_NODE_ASSOCS_TO_AND_FROM, assoc); + } + + @SuppressWarnings("unchecked") + @Override + protected List selectNodeAssocsBySource(Long sourceNodeId) + { + NodeAssocEntity assoc = new NodeAssocEntity(); + // Source + NodeEntity sourceNode = new NodeEntity(); + sourceNode.setId(sourceNodeId); + assoc.setSourceNode(sourceNode); + + return (List) template.queryForList(SELECT_NODE_ASSOCS_BY_SOURCE, assoc); + } + + @SuppressWarnings("unchecked") + @Override + protected List selectNodeAssocsByTarget(Long targetNodeId) + { + NodeAssocEntity assoc = new NodeAssocEntity(); + // Target + NodeEntity targetNode = new NodeEntity(); + targetNode.setId(targetNodeId); + assoc.setTargetNode(targetNode); + + return (List) template.queryForList(SELECT_NODE_ASSOCS_BY_TARGET, assoc); + } + + @Override + protected Long insertChildAssoc(ChildAssocEntity assoc) + { + assoc.setVersion(1L); + return (Long) template.insert(INSERT_CHILD_ASSOC, assoc); + } + + @Override + protected int deleteChildAssocById(Long assocId) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // ID + assoc.setId(assocId); + + return template.delete(DELETE_CHILD_ASSOC_BY_ID, assoc); + } + + @Override + protected int updateChildAssocIndex( + Long parentNodeId, + Long childNodeId, + QName assocTypeQName, + QName assocQName, + int index) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Parent + NodeEntity parentNode = new NodeEntity(); + parentNode.setId(parentNodeId); + assoc.setParentNode(parentNode); + // Child + NodeEntity childNode = new NodeEntity(); + childNode.setId(childNodeId); + assoc.setChildNode(childNode); + // Type QName + assoc.setTypeQNameAll(qnameDAO, assocTypeQName, true); + // QName + assoc.setQNameAll(qnameDAO, assocQName, true); + // Index + assoc.setAssocIndex(index); + + return template.update(UPDATE_CHILD_ASSOCS_INDEX, assoc); + } + + @Override + protected int updateChildAssocsUniqueName(Long childNodeId, String name) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Child + NodeEntity childNode = new NodeEntity(); + childNode.setId(childNodeId); + assoc.setChildNode(childNode); + // Name + assoc.setChildNodeNameAll(null, null, name); + + return template.update(UPDATE_CHILD_ASSOCS_UNIQUE_NAME, assoc); + } + + @Override + protected int deleteChildAssocsToAndFrom(Long nodeId) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Parent + NodeEntity parentNode = new NodeEntity(); + parentNode.setId(nodeId); + assoc.setParentNode(parentNode); + // Child + NodeEntity childNode = new NodeEntity(); + childNode.setId(nodeId); + assoc.setChildNode(childNode); + + return template.delete(DELETE_CHILD_ASSOCS_TO_AND_FROM, assoc); + } + + @Override + protected ChildAssocEntity selectChildAssoc(Long assocId) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + assoc.setId(assocId); + + return (ChildAssocEntity) template.queryForObject(SELECT_CHILD_ASSOC_BY_ID, assoc); + } + + @SuppressWarnings("unchecked") + @Override + public List selectPrimaryChildAcls(Long nodeId) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Parent + NodeEntity parentNode = new NodeEntity(); + parentNode.setId(nodeId); + assoc.setParentNode(parentNode); + // Primary + assoc.setPrimary(true); + + return template.queryForList(SELECT_NODE_PRIMARY_CHILD_ACLS, assoc); + } + + @SuppressWarnings("unchecked") + @Override + protected List selectChildAssoc( + Long parentNodeId, + Long childNodeId, + QName assocTypeQName, + QName assocQName) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Parent + NodeEntity parentNode = new NodeEntity(); + parentNode.setId(parentNodeId); + assoc.setParentNode(parentNode); + // Child + NodeEntity childNode = new NodeEntity(); + childNode.setId(childNodeId); + assoc.setChildNode(childNode); + // Type QName + if (!assoc.setTypeQNameAll(qnameDAO, assocTypeQName, false)) + { + return Collections.emptyList(); // Shortcut + } + // QName + if (!assoc.setQNameAll(qnameDAO, assocQName, false)) + { + return Collections.emptyList(); // Shortcut + } + + return template.queryForList(SELECT_CHILD_ASSOCS_OF_PARENT, assoc); + } + + /** + * Filter to allow the {@link ChildAssocRowHandler} to filter results. + * + * @author Derek Hulley + * @since 3.4 + */ + private interface ChildAssocRowHandlerFilter + { + boolean isResult(ChildAssocEntity assoc); + } + + /** + * Class that pushes results to a {@link ChildAssocRefQueryCallback}. + * + * @author Derek Hulley + * @since 3.4 + */ + private class ChildAssocRowHandler implements RowHandler + { + private final ChildAssocRowHandlerFilter filter; + private final ChildAssocRefQueryCallback resultsCallback; + private boolean more = true; + + private ChildAssocRowHandler(ChildAssocRefQueryCallback resultsCallback) + { + this(null, resultsCallback); + } + + private ChildAssocRowHandler(ChildAssocRowHandlerFilter filter, ChildAssocRefQueryCallback resultsCallback) + { + this.filter = filter; + this.resultsCallback = resultsCallback; + } + + public void handleRow(Object valueObject) + { + // Do nothing if no further results are required + // TODO: Use iBatis' new feature (when we upgrade) to kill the resultset walking + if (!more) + { + return; + } + ChildAssocEntity assoc = (ChildAssocEntity) valueObject; + if (filter != null && !filter.isResult(assoc)) + { + // Filtered out + return; + } + Pair childAssocPair = assoc.getPair(qnameDAO); + Pair parentNodePair = assoc.getParentNode().getNodePair(); + Pair childNodePair = assoc.getChildNode().getNodePair(); + // Call back + boolean more = resultsCallback.handle(childAssocPair, parentNodePair, childNodePair); + if (!more) + { + this.more = false; + } + } + } + + @Override + protected void selectChildAssocs( + Long parentNodeId, + Long childNodeId, + QName assocTypeQName, + QName assocQName, + Boolean isPrimary, + Boolean sameStore, + ChildAssocRefQueryCallback resultsCallback) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Parent + NodeEntity parentNode = new NodeEntity(); + parentNode.setId(parentNodeId); + assoc.setParentNode(parentNode); + // Child + if (childNodeId != null) + { + NodeEntity childNode = new NodeEntity(); + childNode.setId(childNodeId); + assoc.setChildNode(childNode); + } + // Type QName + if (assocTypeQName != null) + { + if (!assoc.setTypeQNameAll(qnameDAO, assocTypeQName, false)) + { + return; // Shortcut + } + } + // QName + if (assocQName != null) + { + if (!assoc.setQNameAll(qnameDAO, assocQName, false)) + { + return; // Shortcut + } + } + // Primary + if (isPrimary != null) + { + assoc.setPrimary(isPrimary); + } + // Same store + if (sameStore != null) + { + assoc.setSameStore(sameStore); + } + + ChildAssocRowHandler rowHandler = new ChildAssocRowHandler(resultsCallback); + template.queryWithRowHandler(SELECT_CHILD_ASSOCS_OF_PARENT, assoc, rowHandler); + } + + @Override + protected void selectChildAssocs( + Long parentNodeId, + Set assocTypeQNames, + ChildAssocRefQueryCallback resultsCallback) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Parent + NodeEntity parentNode = new NodeEntity(); + parentNode.setId(parentNodeId); + assoc.setParentNode(parentNode); + // Type QNames + Set assocTypeQNameIds = qnameDAO.convertQNamesToIds(assocTypeQNames, false); + if (assocTypeQNameIds.size() == 0) + { + return; // Shortcut as they don't exist + } + assoc.setTypeQNameIds(new ArrayList(assocTypeQNameIds)); + + ChildAssocRowHandler rowHandler = new ChildAssocRowHandler(resultsCallback); + template.queryWithRowHandler(SELECT_CHILD_ASSOCS_OF_PARENT, assoc, rowHandler); + } + + @Override + protected ChildAssocEntity selectChildAssoc(Long parentNodeId, QName assocTypeQName, String childName) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Parent + NodeEntity parentNode = new NodeEntity(); + parentNode.setId(parentNodeId); + assoc.setParentNode(parentNode); + // Type QName + if (!assoc.setTypeQNameAll(qnameDAO, assocTypeQName, false)) + { + return null; // Shortcut + } + // Child name + assoc.setChildNodeNameAll(null, assocTypeQName, childName); + + // Note: This single results was assumed from inception of the original method. It's correct. + return (ChildAssocEntity) template.queryForObject(SELECT_CHILD_ASSOCS_OF_PARENT, assoc); + } + + @Override + protected void selectChildAssocs( + Long parentNodeId, + QName assocTypeQName, + Collection childNames, + ChildAssocRefQueryCallback resultsCallback) + { + if (childNames.size() == 0) + { + return; + } + else if (childNames.size() > 1000) + { + throw new IllegalArgumentException("Unable to process more than 1000 child names in getChildAssocs"); + } + // Work out the child names to query on + final Set childNamesShort = new HashSet(childNames.size()); + final List childNamesCrc = new ArrayList(childNames.size()); + for (String childName : childNames) + { + String childNameLower = childName.toLowerCase(); + String childNameShort = ChildAssocEntity.getChildNodeNameShort(childNameLower); + Long childNameCrc = ChildAssocEntity.getChildNodeNameCrc(childNameLower); + childNamesShort.add(childNameShort); + childNamesCrc.add(childNameCrc); + } + // Create a filter that checks that the name CRC is present + ChildAssocRowHandlerFilter filter = new ChildAssocRowHandlerFilter() + { + public boolean isResult(ChildAssocEntity assoc) + { + return childNamesShort.contains(assoc.getChildNodeName()); + } + }; + + ChildAssocEntity assoc = new ChildAssocEntity(); + // Parent + NodeEntity parentNode = new NodeEntity(); + parentNode.setId(parentNodeId); + assoc.setParentNode(parentNode); + // Type QName + if (assocTypeQName != null) + { + if (!assoc.setTypeQNameAll(qnameDAO, assocTypeQName, false)) + { + return; // Shortcut + } + } + // Child names + assoc.setChildNodeNameCrcs(childNamesCrc); + + ChildAssocRowHandler rowHandler = new ChildAssocRowHandler(filter, resultsCallback); + template.queryWithRowHandler(SELECT_CHILD_ASSOCS_OF_PARENT, assoc, rowHandler); + } + + @Override + protected void selectChildAssocsByChildTypes( + Long parentNodeId, + Set childNodeTypeQNames, + ChildAssocRefQueryCallback resultsCallback) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Parent + NodeEntity parentNode = new NodeEntity(); + parentNode.setId(parentNodeId); + assoc.setParentNode(parentNode); + // Child Node Type QNames + Set childNodeTypeQNameIds = qnameDAO.convertQNamesToIds(childNodeTypeQNames, false); + if (childNodeTypeQNameIds.size() == 0) + { + return; // Shortcut as they don't exist + } + assoc.setChildNodeTypeQNameIds(new ArrayList(childNodeTypeQNameIds)); + + ChildAssocRowHandler rowHandler = new ChildAssocRowHandler(resultsCallback); + template.queryWithRowHandler(SELECT_CHILD_ASSOCS_OF_PARENT, assoc, rowHandler); + } + + @Override + protected void selectChildAssocsWithoutParentAssocsOfType( + Long parentNodeId, + QName assocTypeQName, + ChildAssocRefQueryCallback resultsCallback) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Parent + NodeEntity parentNode = new NodeEntity(); + parentNode.setId(parentNodeId); + assoc.setParentNode(parentNode); + // Type QName + if (!assoc.setTypeQNameAll(qnameDAO, assocTypeQName, false)) + { + return; // Shortcut + } + + ChildAssocRowHandler rowHandler = new ChildAssocRowHandler(resultsCallback); + template.queryWithRowHandler(SELECT_CHILD_ASSOCS_OF_PARENT_WITHOUT_PARENT_ASSOCS_OF_TYPE, assoc, rowHandler); + } + + @SuppressWarnings("unchecked") + @Override + protected List selectPrimaryParentAssocs(Long childNodeId) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Child + NodeEntity childNode = new NodeEntity(); + childNode.setId(childNodeId); + assoc.setChildNode(childNode); + // Primary + assoc.setPrimary(Boolean.TRUE); + + return template.queryForList(SELECT_PARENT_ASSOCS_OF_CHILD, assoc); + } + + @Override + protected void selectParentAssocs( + Long childNodeId, + QName assocTypeQName, + QName assocQName, + Boolean isPrimary, + ChildAssocRefQueryCallback resultsCallback) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Child + NodeEntity childNode = new NodeEntity(); + childNode.setId(childNodeId); + assoc.setChildNode(childNode); + // Type QName + if (assocTypeQName != null) + { + if (!assoc.setTypeQNameAll(qnameDAO, assocTypeQName, false)) + { + return; // Shortcut + } + } + // QName + if (assocQName != null) + { + if (!assoc.setQNameAll(qnameDAO, assocQName, false)) + { + return; // Shortcut + } + } + // Primary + if (isPrimary != null) + { + assoc.setPrimary(isPrimary); + } + + ChildAssocRowHandler rowHandler = new ChildAssocRowHandler(resultsCallback); + template.queryWithRowHandler(SELECT_PARENT_ASSOCS_OF_CHILD, assoc, rowHandler); + } + + @SuppressWarnings("unchecked") + @Override + protected List selectParentAssocs(Long childNodeId) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Child + NodeEntity childNode = new NodeEntity(); + childNode.setId(childNodeId); + assoc.setChildNode(childNode); + + return template.queryForList(SELECT_PARENT_ASSOCS_OF_CHILD, assoc); + } + + @Override + protected int updatePrimaryParentAssocs( + Long childNodeId, + Long parentNodeId, + QName assocTypeQName, + QName assocQName, + String childNodeName) + { + ChildAssocEntity assoc = new ChildAssocEntity(); + // Parent + NodeEntity parentNode = new NodeEntity(); + parentNode.setId(parentNodeId); + assoc.setParentNode(parentNode); + // Child + NodeEntity childNode = new NodeEntity(); + childNode.setId(childNodeId); + assoc.setChildNode(childNode); + // Type QName + if (assocTypeQName != null) + { + assoc.setTypeQNameAll(qnameDAO, assocTypeQName, true); + // Have to recalculate the crc values for the association + assoc.setChildNodeNameAll(dictionaryService, assocTypeQName, childNodeName); + } + // QName + if (assocQName != null) + { + assoc.setQNameAll(qnameDAO, assocQName, true); + } + // Primary + assoc.setPrimary(Boolean.TRUE); + + return template.update(UPDATE_PARENT_ASSOCS_OF_CHILD, assoc); + } + + @SuppressWarnings("unchecked") + @Override + protected Transaction selectLastTxnBeforeCommitTime(Long maxCommitTime) + { + Assert.notNull(maxCommitTime, "maxCommitTime"); + + TransactionQueryEntity query = new TransactionQueryEntity(); + query.setMaxCommitTime(maxCommitTime); + + List txns = template.queryForList(SELECT_TXN_LAST, query, 0, 1); + if (txns.size() > 0) + { + return txns.get(0); + } + else + { + return null; + } + } + + @Override + protected void selectNodesDeletedInOldTxns( + Long minNodeId, + Long maxCommitTime, + Integer count, + NodeRefQueryCallback resultsCallback) + { + throw new UnsupportedOperationException(); + } + + @Override + protected int selectTransactionCount() + { + return (Integer) template.queryForObject(SELECT_TXN_COUNT); + } + + @Override + protected Transaction selectTxnById(Long txnId) + { + TransactionQueryEntity query = new TransactionQueryEntity(); + query.setId(txnId); + + return (Transaction) template.queryForObject(SELECT_TXNS, query); + } + + @SuppressWarnings("unchecked") + @Override + protected List selectTxnChanges(Long txnId, Long storeId) + { + TransactionQueryEntity query = new TransactionQueryEntity(); + query.setId(txnId); + if (storeId != null) + { + query.setStoreId(storeId); + } + + // TODO: Return List for quicker node_deleted access + return (List) template.queryForList(SELECT_TXN_NODES, query); + } + + @Override + protected int selectTxnNodeChangeCount(Long txnId, Boolean updates) + { + NodeEntity node = new NodeEntity(); + // Updates or deletes + if (updates != null) + { + node.setDeleted(Boolean.valueOf(!updates)); + } + // Transaction + TransactionEntity transaction = new TransactionEntity(); + transaction.setId(txnId); + node.setTransaction(transaction); + + return (Integer) template.queryForObject(SELECT_TXN_NODE_COUNT, node); + } + + @SuppressWarnings("unchecked") + @Override + protected List selectTxns( + Long fromTimeInclusive, + Long toTimeExclusive, + Integer count, + List includeTxnIds, + List excludeTxnIds, + Long excludeServerId, + Boolean ascending) + { + TransactionQueryEntity query = new TransactionQueryEntity(); + query.setMinCommitTime(fromTimeInclusive); + query.setMaxCommitTime(toTimeExclusive); + query.setIncludeTxnIds(includeTxnIds); + query.setExcludeTxnIds(excludeTxnIds); + query.setExcludeServerId(excludeServerId); + + if (count == null) + { + return template.queryForList(SELECT_TXNS, query); + } + else + { + return template.queryForList(SELECT_TXNS, query, 0, count); + } + } + + @SuppressWarnings("unchecked") + @Override + protected List selectTxnsUnused(Long minTxnId, Long maxCommitTime, Integer count) + { + TransactionQueryEntity query = new TransactionQueryEntity(); + query.setMinId(minTxnId); + query.setMaxCommitTime(maxCommitTime); + if (count == null) + { + return template.queryForList(SELECT_TXNS_UNUSED, query); + } + else + { + return template.queryForList(SELECT_TXNS_UNUSED, query, 0, count); + } + } + + @Override + protected Long selectMinTxnCommitTime() + { + return (Long) template.queryForObject(SELECT_TXN_MIN_COMMIT_TIME); + } + + @Override + protected Long selectMaxTxnCommitTime() + { + return (Long) template.queryForObject(SELECT_TXN_MAX_COMMIT_TIME); + } +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/patch/AbstractAppliedPatchDAOImpl.java b/source/java/org/alfresco/repo/domain/patch/AbstractAppliedPatchDAOImpl.java index b33fc9d058..c7e568d92b 100644 --- a/source/java/org/alfresco/repo/domain/patch/AbstractAppliedPatchDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/patch/AbstractAppliedPatchDAOImpl.java @@ -29,7 +29,7 @@ import org.alfresco.repo.admin.patch.AppliedPatch; * Abstract implementation for DAO alf_applied_patch. * * @author Derek Hulley - * @since 3.3 + * @since 3.4 */ public abstract class AbstractAppliedPatchDAOImpl implements AppliedPatchDAO { diff --git a/source/java/org/alfresco/repo/domain/patch/AbstractPatchDAOImpl.java b/source/java/org/alfresco/repo/domain/patch/AbstractPatchDAOImpl.java index ede58f597a..81cf8791a1 100644 --- a/source/java/org/alfresco/repo/domain/patch/AbstractPatchDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/patch/AbstractPatchDAOImpl.java @@ -25,6 +25,7 @@ import org.alfresco.ibatis.BatchingDAO; import org.alfresco.repo.domain.avm.AVMNodeEntity; import org.alfresco.repo.domain.contentdata.ContentDataDAO; import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.StoreRef; /** @@ -51,6 +52,14 @@ public abstract class AbstractPatchDAOImpl implements PatchDAO, BatchingDAO this.contentDataDAO = contentDataDAO; } + /** + * {@inheritDoc} + */ + public boolean supportsProgressTracking() + { + return supportsProgressTrackingImpl(); + } + /** * {@inheritDoc} */ @@ -59,31 +68,85 @@ public abstract class AbstractPatchDAOImpl implements PatchDAO, BatchingDAO return getAVMNodeEntitiesCountWhereNewInStore(); } - protected abstract Long getAVMNodeEntitiesCountWhereNewInStore(); - public List getEmptyGUIDS(int count) { - // TODO limit results - count is currently ignored - return getAVMNodeEntitiesWithEmptyGUID(); + return getAVMNodeEntitiesWithEmptyGUID(count); } - protected abstract List getAVMNodeEntitiesWithEmptyGUID(); - public List getNullVersionLayeredDirectories(int count) { - // TODO limit results - count is currently ignored - return getNullVersionLayeredDirectoryNodeEntities(); + return getNullVersionLayeredDirectoryNodeEntities(count); } public List getNullVersionLayeredFiles(int count) { - // TODO limit results - count is currently ignored - return getNullVersionLayeredFileNodeEntities(); + return getNullVersionLayeredFileNodeEntities(count); } - protected abstract List getNullVersionLayeredDirectoryNodeEntities(); + public int updateAVMNodesNullifyAcl(List nodeIds) + { + return updateAVMNodeEntitiesNullifyAcl(nodeIds); + } - protected abstract List getNullVersionLayeredFileNodeEntities(); + public int updateAVMNodesSetAcl(long aclId, List nodeIds) + { + return updateAVMNodeEntitiesSetAcl(aclId, nodeIds); + } + + protected abstract boolean supportsProgressTrackingImpl(); + protected abstract Long getAVMNodeEntitiesCountWhereNewInStore(); + protected abstract List getAVMNodeEntitiesWithEmptyGUID(int maxResults); + protected abstract List getNullVersionLayeredDirectoryNodeEntities(int maxResults); + protected abstract List getNullVersionLayeredFileNodeEntities(int maxResults); + protected abstract int updateAVMNodeEntitiesNullifyAcl(List nodeIds); + protected abstract int updateAVMNodeEntitiesSetAcl(long aclId, List nodeIds); + + public Long getMaxAclId() + { + return getMaxAclEntityId(); + } + + public long getDmNodeCount() + { + return getDmNodeEntitiesCount(); + } + + public long getDmNodeCountWithNewACLs(Long above) + { + return getDmNodeEntitiesCountWithNewACLs(above); + } + + public List selectAllAclIds() + { + return selectAllAclEntityIds(); + } + + public List selectNonDanglingAclIds() + { + return selectNonDanglingAclEntityIds(); + } + + public int deleteDanglingAces() + { + return deleteDanglingAceEntities(); + } + + public int deleteAcls(List aclIds) + { + return deleteAclEntities(aclIds); + } + + public int deleteAclMembersForAcls(List aclIds) + { + return deleteAclMemberEntitiesForAcls(aclIds); + } + + public void getUsersWithoutUsageProp(StoreRef storeRef, StringHandler handler) + { + selectUsersWithoutUsageProp(storeRef, handler); + } + + protected abstract void selectUsersWithoutUsageProp(StoreRef storeRef,StringHandler handler); /** * {@inheritDoc} @@ -159,4 +222,13 @@ public abstract class AbstractPatchDAOImpl implements PatchDAO, BatchingDAO Integer listIndex, Long localeId, Long longValue); + + protected abstract Long getMaxAclEntityId(); + protected abstract long getDmNodeEntitiesCount(); + protected abstract long getDmNodeEntitiesCountWithNewACLs(Long above); + protected abstract List selectAllAclEntityIds(); + protected abstract List selectNonDanglingAclEntityIds(); + protected abstract int deleteDanglingAceEntities(); + protected abstract int deleteAclEntities(List aclIds); + protected abstract int deleteAclMemberEntitiesForAcls(List aclIds); } diff --git a/source/java/org/alfresco/repo/domain/patch/AppliedPatchDAO.java b/source/java/org/alfresco/repo/domain/patch/AppliedPatchDAO.java index aeb1051e6e..c5d608c8ee 100644 --- a/source/java/org/alfresco/repo/domain/patch/AppliedPatchDAO.java +++ b/source/java/org/alfresco/repo/domain/patch/AppliedPatchDAO.java @@ -26,7 +26,7 @@ import org.alfresco.repo.admin.patch.AppliedPatch; /** * Provides data access support for patch persistence in alf_applied_patch. * - * @since 3.3 + * @since 3.4 * @author Derek Hulley */ public interface AppliedPatchDAO diff --git a/source/java/org/alfresco/repo/domain/patch/AppliedPatchDAOTest.java b/source/java/org/alfresco/repo/domain/patch/AppliedPatchDAOTest.java index 56ae13de80..a9d9496816 100644 --- a/source/java/org/alfresco/repo/domain/patch/AppliedPatchDAOTest.java +++ b/source/java/org/alfresco/repo/domain/patch/AppliedPatchDAOTest.java @@ -34,7 +34,7 @@ import org.springframework.context.ApplicationContext; * @see AppliedPatchDAO * * @author Derek Hulley - * @since 3.3 + * @since 3.4 */ public class AppliedPatchDAOTest extends TestCase { diff --git a/source/java/org/alfresco/repo/domain/patch/AppliedPatchEntity.java b/source/java/org/alfresco/repo/domain/patch/AppliedPatchEntity.java index 6fb5b56056..210bb82ac8 100644 --- a/source/java/org/alfresco/repo/domain/patch/AppliedPatchEntity.java +++ b/source/java/org/alfresco/repo/domain/patch/AppliedPatchEntity.java @@ -24,7 +24,7 @@ import org.alfresco.repo.admin.patch.AppliedPatch; * Entity for alf_applied_patch persistence. * * @author Derek Hulley - * @since 3.3 + * @since 3.4 */ public class AppliedPatchEntity extends AppliedPatch { diff --git a/source/java/org/alfresco/repo/domain/patch/PatchDAO.java b/source/java/org/alfresco/repo/domain/patch/PatchDAO.java index 155538ae73..1df0005037 100644 --- a/source/java/org/alfresco/repo/domain/patch/PatchDAO.java +++ b/source/java/org/alfresco/repo/domain/patch/PatchDAO.java @@ -23,6 +23,7 @@ import java.util.List; import org.alfresco.repo.domain.avm.AVMNodeEntity; import org.alfresco.repo.domain.contentdata.ContentDataDAO; import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.StoreRef; /** * Additional DAO services for patches @@ -33,6 +34,13 @@ import org.alfresco.service.cmr.repository.ContentData; */ public interface PatchDAO { + /** + * Does the underlying connection support isolation level 1 (dirty read) + * + * @return true if we can do a dirty db read and so track changes (Oracle can not) + */ + public boolean supportsProgressTracking(); + // AVM-related public Long getAVMNodesCountWhereNewInStore(); @@ -47,6 +55,10 @@ public interface PatchDAO public List getAvmNodesWithOldContentProperties(Long minNodeId, Long maxNodeId); + public int updateAVMNodesNullifyAcl(List nodeIds); + + public int updateAVMNodesSetAcl(long aclId, List nodeIds); + // DM-related public Long getMaxAdmNodeID(); @@ -68,4 +80,60 @@ public interface PatchDAO * @return the number of rows affected */ public int updateContentMimetypeIds(Long oldMimetypeId, Long newMimetypeId); + + /** + * A callback handler for iterating over the string results + */ + public interface StringHandler + { + void handle(String string); + } + + /** + * Iterate over all person nodes with missing usage property (for one-off patch) + * + * @param storeRef the store to search in + * @param handler the callback to use while iterating over the people + * @return Returns the values for person node uuid + */ + public void getUsersWithoutUsageProp(StoreRef storeRef, StringHandler handler); + + // ACL-related + + /** + * Get the max acl id + * + * @return - max acl id + */ + public Long getMaxAclId(); + + /** + * How many DM nodes are there? + * + * @return - the count + */ + public long getDmNodeCount(); + + /** + * How many DM nodes are three with new ACls (to track patch progress) + * + * @param above + * @return - the count + */ + public long getDmNodeCountWithNewACLs(Long above); + + public List selectAllAclIds(); + + public List selectNonDanglingAclIds(); + + public int deleteDanglingAces(); + + public int deleteAcls(List aclIds); + + public int deleteAclMembersForAcls(List aclIds); + + /** + * @return Returns the names of authorities with incorrect CRC values + */ + public List getAuthoritiesWithNonUtf8Crcs(); } diff --git a/source/java/org/alfresco/repo/domain/patch/ibatis/AppliedPatchDAOImpl.java b/source/java/org/alfresco/repo/domain/patch/ibatis/AppliedPatchDAOImpl.java index 14e47b96bf..efe992cef0 100644 --- a/source/java/org/alfresco/repo/domain/patch/ibatis/AppliedPatchDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/patch/ibatis/AppliedPatchDAOImpl.java @@ -28,7 +28,7 @@ import org.springframework.orm.ibatis.SqlMapClientTemplate; * iBatis-specific implementation of the AppliedPatch DAO. * * @author Derek Hulley - * @since 3.3 + * @since 3.4 */ public class AppliedPatchDAOImpl extends AbstractAppliedPatchDAOImpl { diff --git a/source/java/org/alfresco/repo/domain/patch/ibatis/IdListOfIdsParam.java b/source/java/org/alfresco/repo/domain/patch/ibatis/IdListOfIdsParam.java new file mode 100644 index 0000000000..3d6be34a4e --- /dev/null +++ b/source/java/org/alfresco/repo/domain/patch/ibatis/IdListOfIdsParam.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.patch.ibatis; + +import java.util.List; + +public class IdListOfIdsParam +{ + private Long id; + private List listOfIds; + + public IdListOfIdsParam() + { + } + + public Long getId() + { + return id; + } + public void setId(Long id) + { + this.id = id; + } + public List getListOfIds() + { + return listOfIds; + } + public void setListOfIds(List listOfIds) + { + this.listOfIds = listOfIds; + } +} diff --git a/source/java/org/alfresco/repo/domain/patch/ibatis/PatchDAOImpl.java b/source/java/org/alfresco/repo/domain/patch/ibatis/PatchDAOImpl.java index e575fa07fd..271fc1076f 100644 --- a/source/java/org/alfresco/repo/domain/patch/ibatis/PatchDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/patch/ibatis/PatchDAOImpl.java @@ -18,16 +18,29 @@ */ package org.alfresco.repo.domain.patch.ibatis; +import java.sql.Connection; import java.sql.SQLException; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.ibatis.IdsEntity; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.CrcHelper; import org.alfresco.repo.domain.avm.AVMNodeEntity; import org.alfresco.repo.domain.patch.AbstractPatchDAOImpl; +import org.alfresco.repo.domain.qname.QNameDAO; +import org.alfresco.service.cmr.repository.StoreRef; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.orm.ibatis.SqlMapClientTemplate; +import com.ibatis.sqlmap.client.SqlMapSession; +import com.ibatis.sqlmap.client.event.RowHandler; +import com.ibatis.sqlmap.engine.execution.SqlExecutor; + /** * iBatis-specific implementation of the AVMPatch DAO. * @@ -36,6 +49,8 @@ import org.springframework.orm.ibatis.SqlMapClientTemplate; */ public class PatchDAOImpl extends AbstractPatchDAOImpl { + private static Log logger = LogFactory.getLog(PatchDAOImpl.class); + private static final String SELECT_AVM_NODE_ENTITIES_COUNT_WHERE_NEW_IN_STORE = "alfresco.avm.select_AVMNodeEntitiesCountWhereNewInStore"; private static final String SELECT_AVM_NODE_ENTITIES_WITH_EMPTY_GUID = "alfresco.avm.select_AVMNodesWithEmptyGUID"; private static final String SELECT_AVM_LD_NODE_ENTITIES_NULL_VERSION = "alfresco.avm.select_AVMNodes_nullVersionLayeredDirectories"; @@ -44,16 +59,38 @@ public class PatchDAOImpl extends AbstractPatchDAOImpl private static final String SELECT_ADM_MAX_NODE_ID = "alfresco.patch.select_admMaxNodeId"; private static final String SELECT_AVM_NODES_WITH_OLD_CONTENT_PROPERTIES = "alfresco.patch.select_avmNodesWithOldContentProperties"; private static final String SELECT_ADM_OLD_CONTENT_PROPERTIES = "alfresco.patch.select_admOldContentProperties"; + private static final String SELECT_AUTHORITIES_AND_CRC = "alfresco.patch.select_authoritiesAndCrc"; private static final String UPDATE_ADM_OLD_CONTENT_PROPERTY = "alfresco.patch.update_admOldContentProperty"; private static final String UPDATE_CONTENT_MIMETYPE_ID = "alfresco.patch.update_contentMimetypeId"; + private static final String UPDATE_AVM_NODE_LIST_NULLIFY_ACL = "alfresco.avm.update_AVMNodeList_nullifyAcl"; + private static final String UPDATE_AVM_NODE_LIST_SET_ACL = "alfresco.avm.update_AVMNodeList_setAcl"; + + private static final String SELECT_USERS_WITHOUT_USAGE_PROP = "alfresco.usage.select_GetUsersWithoutUsageProp"; + + private static final String SELECT_PERMISSIONS_MAX_ACL_ID = "alfresco.permissions.select_MaxAclId"; + private static final String SELECT_PERMISSIONS_DM_NODE_COUNT = "alfresco.permissions.select_DmNodeCount"; + private static final String SELECT_PERMISSIONS_DM_NODE_COUNT_WITH_NEW_ACLS = "alfresco.permissions.select_DmNodeCountWherePermissionsHaveChanged"; + + private static final String SELECT_PERMISSIONS_ALL_ACL_IDS = "alfresco.permissions.select_AllAclIds"; + private static final String SELECT_PERMISSIONS_USED_ACL_IDS = "alfresco.permissions.select_UsedAclIds"; + private static final String DELETE_PERMISSIONS_UNUSED_ACES = "alfresco.permissions.delete_UnusedAces"; + private static final String DELETE_PERMISSIONS_ACL_LIST = "alfresco.permissions.delete_AclList"; + private static final String DELETE_PERMISSIONS_ACL_MEMBERS_FOR_ACL_LIST = "alfresco.permissions.delete_AclMembersForAclList"; + private SqlMapClientTemplate template; + private QNameDAO qnameDAO; public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) { this.template = sqlMapClientTemplate; } - + + public void setQnameDAO(QNameDAO qnameDAO) + { + this.qnameDAO = qnameDAO; + } + public void startBatch() { try @@ -78,6 +115,19 @@ public class PatchDAOImpl extends AbstractPatchDAOImpl } } + @Override + protected boolean supportsProgressTrackingImpl() + { + try + { + return template.getSqlMapClient().getCurrentConnection().getMetaData().supportsTransactionIsolationLevel(1); + } + catch (SQLException e) + { + return false; + } + } + @Override protected Long getAVMNodeEntitiesCountWhereNewInStore() { @@ -86,23 +136,38 @@ public class PatchDAOImpl extends AbstractPatchDAOImpl @SuppressWarnings("unchecked") @Override - protected List getAVMNodeEntitiesWithEmptyGUID() + protected List getAVMNodeEntitiesWithEmptyGUID(int maxResults) { - return (List) template.queryForList(SELECT_AVM_NODE_ENTITIES_WITH_EMPTY_GUID); + if (maxResults < 0) + { + maxResults = SqlExecutor.NO_MAXIMUM_RESULTS; + } + + return (List) template.queryForList(SELECT_AVM_NODE_ENTITIES_WITH_EMPTY_GUID, 0, maxResults); } @SuppressWarnings("unchecked") @Override - protected List getNullVersionLayeredDirectoryNodeEntities() + protected List getNullVersionLayeredDirectoryNodeEntities(int maxResults) { - return (List) template.queryForList(SELECT_AVM_LD_NODE_ENTITIES_NULL_VERSION); + if (maxResults < 0) + { + maxResults = SqlExecutor.NO_MAXIMUM_RESULTS; + } + + return (List) template.queryForList(SELECT_AVM_LD_NODE_ENTITIES_NULL_VERSION, 0, maxResults); } @SuppressWarnings("unchecked") @Override - protected List getNullVersionLayeredFileNodeEntities() + protected List getNullVersionLayeredFileNodeEntities(int maxResults) { - return (List) template.queryForList(SELECT_AVM_LF_NODE_ENTITIES_NULL_VERSION); + if (maxResults < 0) + { + maxResults = SqlExecutor.NO_MAXIMUM_RESULTS; + } + + return (List) template.queryForList(SELECT_AVM_LF_NODE_ENTITIES_NULL_VERSION, 0, maxResults); } public Long getMaxAvmNodeID() @@ -153,4 +218,224 @@ public class PatchDAOImpl extends AbstractPatchDAOImpl params.put("oldMimetypeId", oldMimetypeId); return template.update(UPDATE_CONTENT_MIMETYPE_ID, params); } + + @Override + protected void selectUsersWithoutUsageProp(StoreRef storeRef, StringHandler handler) + { + long personTypeQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.TYPE_PERSON).getFirst(); + long sizeCurrentPropQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.PROP_SIZE_CURRENT).getFirst(); + + Map params = new HashMap(1); + params.put("personTypeQNameID", personTypeQNameEntityId); // cm:person + params.put("sizeCurrentPropQNameID",sizeCurrentPropQNameEntityId); // cm:sizeCurrent + params.put("storeProtocol", storeRef.getProtocol()); + params.put("storeIdentifier", storeRef.getIdentifier()); + params.put("isDeleted", false); + + StringRowHandler rowHandler = new StringRowHandler(handler); + + template.queryWithRowHandler(SELECT_USERS_WITHOUT_USAGE_PROP, params, rowHandler); + + if (logger.isDebugEnabled()) + { + logger.debug(" Listed " + rowHandler.total + " users without usage"); + } + } + + /** + * Row handler for getting strings + */ + private static class StringRowHandler implements RowHandler + { + private final StringHandler handler; + + private int total = 0; + + private StringRowHandler(StringHandler handler) + { + this.handler = handler; + } + public void handleRow(Object valueObject) + { + handler.handle((String)valueObject); + total++; + if (logger.isDebugEnabled() && (total == 0 || (total % 1000 == 0) )) + { + logger.debug(" Listed " + total + " strings"); + } + } + } + + @Override + protected int updateAVMNodeEntitiesNullifyAcl(List nodeIds) + { + return template.update(UPDATE_AVM_NODE_LIST_NULLIFY_ACL, nodeIds); + } + + @Override + protected int updateAVMNodeEntitiesSetAcl(long aclId, List nodeIds) + { + IdListOfIdsParam params = new IdListOfIdsParam(); + params.setId(aclId); + params.setListOfIds(nodeIds); + + return template.update(UPDATE_AVM_NODE_LIST_SET_ACL, params); + } + + @Override + protected Long getMaxAclEntityId() + { + SqlMapSession session = null; + try + { + session = template.getSqlMapClient().openSession(); + Connection conn = template.getSqlMapClient().getCurrentConnection(); + int isolationLevel = conn.getTransactionIsolation(); + try + { + conn.setTransactionIsolation(1); + return (Long)template.queryForObject(SELECT_PERMISSIONS_MAX_ACL_ID, null); + } + finally + { + conn.setTransactionIsolation(isolationLevel); + } + } + catch (SQLException e) + { + throw new AlfrescoRuntimeException("Failed to set TX isolation level", e); + } + finally + { + if (session != null) + { + session.close(); + } + } + } + + @Override + protected long getDmNodeEntitiesCount() + { + SqlMapSession session = null; + try + { + session = template.getSqlMapClient().openSession(); + Connection conn = template.getSqlMapClient().getCurrentConnection(); + int isolationLevel = conn.getTransactionIsolation(); + try + { + conn.setTransactionIsolation(1); + + return (Long)template.queryForObject(SELECT_PERMISSIONS_DM_NODE_COUNT, null); + } + finally + { + conn.setTransactionIsolation(isolationLevel); + } + } + catch (SQLException e) + { + throw new AlfrescoRuntimeException("Failed to set TX isolation level", e); + } + finally + { + if (session != null) + { + session.close(); + } + } + } + + @Override + protected long getDmNodeEntitiesCountWithNewACLs(Long above) + { + SqlMapSession session = null; + try + { + session = template.getSqlMapClient().openSession(); + Connection conn = template.getSqlMapClient().getCurrentConnection(); + int isolationLevel = conn.getTransactionIsolation(); + try + { + conn.setTransactionIsolation(1); + + Map params = new HashMap(1); + params.put("id", above); + + return (Long)template.queryForObject(SELECT_PERMISSIONS_DM_NODE_COUNT_WITH_NEW_ACLS, params); + } + finally + { + conn.setTransactionIsolation(isolationLevel); + } + } + catch (SQLException e) + { + throw new AlfrescoRuntimeException("Failed to set TX isolation level", e); + } + finally + { + if (session != null) + { + session.close(); + } + } + } + + @SuppressWarnings("unchecked") + @Override + protected List selectAllAclEntityIds() + { + return (List) template.queryForList(SELECT_PERMISSIONS_ALL_ACL_IDS); + } + + @SuppressWarnings("unchecked") + @Override + protected List selectNonDanglingAclEntityIds() + { + return (List) template.queryForList(SELECT_PERMISSIONS_USED_ACL_IDS); + } + + @Override + protected int deleteDanglingAceEntities() + { + return template.delete(DELETE_PERMISSIONS_UNUSED_ACES); + } + + @Override + protected int deleteAclEntities(List aclIds) + { + return template.delete(DELETE_PERMISSIONS_ACL_LIST, aclIds); + } + + @Override + protected int deleteAclMemberEntitiesForAcls(List aclIds) + { + return template.delete(DELETE_PERMISSIONS_ACL_MEMBERS_FOR_ACL_LIST, aclIds); + } + + public List getAuthoritiesWithNonUtf8Crcs() + { + final List results = new ArrayList(1000); + RowHandler rowHandler = new RowHandler() + { + @SuppressWarnings("unchecked") + public void handleRow(Object valueObject) + { + Map result = (Map) valueObject; + String authority = (String) result.get("authority"); + Long crc = (Long) result.get("crc"); + Long crcShouldBe = CrcHelper.getStringCrcPair(authority, 32, true, true).getSecond(); + if (!crcShouldBe.equals(crc)) + { + // One to fix + results.add(authority); + } + } + }; + template.queryWithRowHandler(SELECT_AUTHORITIES_AND_CRC, rowHandler); + // Done + return results; + } } diff --git a/source/java/org/alfresco/repo/domain/permissions/ADMAccessControlListDAO.java b/source/java/org/alfresco/repo/domain/permissions/ADMAccessControlListDAO.java new file mode 100644 index 0000000000..3610e0c28d --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/ADMAccessControlListDAO.java @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.repo.domain.permissions; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.repo.domain.AccessControlListDAO; +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.repo.domain.node.NodeIdAndAclId; +import org.alfresco.repo.domain.permissions.AVMAccessControlListDAO.CounterSet; +import org.alfresco.repo.security.permissions.ACLType; +import org.alfresco.repo.security.permissions.AccessControlList; +import org.alfresco.repo.security.permissions.AccessControlListProperties; +import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties; +import org.alfresco.repo.security.permissions.impl.AclChange; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.util.Pair; + +/** + * DAO layer for the improved ACL implementation. This layer is responsible for setting ACLs and any cascade behaviour + * required. It also implements the migration from the old implementation to the new. + * + * @author andyh + */ +public class ADMAccessControlListDAO implements AccessControlListDAO +{ + /** + * The DAO for Nodes. + */ + private NodeDAO nodeDAO; + + private AclDAO aclDaoComponent; + + public void setNodeDAO(NodeDAO nodeDAO) + { + this.nodeDAO = nodeDAO; + } + + public void setAclDAO(AclDAO aclDaoComponent) + { + this.aclDaoComponent = aclDaoComponent; + } + + public void forceCopy(NodeRef nodeRef) + { + // Nothing to do + } + + private Long getNodeIdNotNull(NodeRef nodeRef) + { + Pair nodePair = nodeDAO.getNodePair(nodeRef); + if (nodePair == null) + { + throw new InvalidNodeRefException(nodeRef); + } + return nodePair.getFirst(); + } + + public DbAccessControlList getAccessControlList(NodeRef nodeRef) + { + Long nodeId = getNodeIdNotNull(nodeRef); + Long aclId = nodeDAO.getNodeAclId(nodeId); + return aclDaoComponent.getDbAccessControlList(aclId); + } + + public DbAccessControlList getAccessControlList(StoreRef storeRef) + { + return null; + } + + public Long getIndirectAcl(NodeRef nodeRef) + { + return getAccessControlList(nodeRef).getId(); + } + + public Long getInheritedAcl(NodeRef nodeRef) + { + Pair nodePair = nodeDAO.getNodePair(nodeRef); + if (nodePair == null) + { + return null; + } + Pair parentAssocRefPair = nodeDAO.getPrimaryParentAssoc(nodePair.getFirst()); + if (parentAssocRefPair == null || parentAssocRefPair.getSecond().getParentRef() == null) + { + return null; + } + DbAccessControlList acl = getAccessControlList(parentAssocRefPair.getSecond().getParentRef()); + if (acl != null) + { + return acl.getId(); + } + else + { + return null; + } + } + + public Map patchAcls() + { + CounterSet result = new CounterSet(); + List> stores = nodeDAO.getStores(); + + for (Pair pair : stores) + { + if (!pair.getSecond().getProtocol().equals(StoreRef.PROTOCOL_AVM)) + { + CounterSet update; + update = fixOldDmAcls(nodeDAO.getRootNode(pair.getSecond()).getFirst(), (Long)null, true); + result.add(update); + } + } + + HashMap toReturn = new HashMap(); + toReturn.put(ACLType.DEFINING, Integer.valueOf(result.get(ACLType.DEFINING).getCounter())); + toReturn.put(ACLType.FIXED, Integer.valueOf(result.get(ACLType.FIXED).getCounter())); + toReturn.put(ACLType.GLOBAL, Integer.valueOf(result.get(ACLType.GLOBAL).getCounter())); + toReturn.put(ACLType.LAYERED, Integer.valueOf(result.get(ACLType.LAYERED).getCounter())); + toReturn.put(ACLType.OLD, Integer.valueOf(result.get(ACLType.OLD).getCounter())); + toReturn.put(ACLType.SHARED, Integer.valueOf(result.get(ACLType.SHARED).getCounter())); + return toReturn; + } + + private CounterSet fixOldDmAcls(Long nodeId, Long inherited, boolean isRoot) + { + return fixOldDmAclsImpl(nodeId, inherited, isRoot); + } + + private CounterSet fixOldDmAclsImpl(Long nodeId, Long inherited, boolean isRoot) + { + CounterSet result = new CounterSet(); + // Do the children first + + Long aclId = nodeDAO.getNodeAclId(nodeId); + DbAccessControlList existingAcl = aclDaoComponent.getDbAccessControlList(aclId); + + Long toInherit = null; + Long idToInheritFrom = null; + + if (existingAcl != null) + { + if (existingAcl.getAclType() == ACLType.OLD) + { + result.increment(ACLType.DEFINING); + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(aclDaoComponent.getDefaultProperties()); + properties.setInherits(existingAcl.getInherits()); + AccessControlList existing = aclDaoComponent.getAccessControlList(existingAcl.getId()); + Long actuallyInherited = null; + if (existingAcl.getInherits()) + { + if (inherited != null) + { + actuallyInherited = inherited; + } + } + Acl newAcl = aclDaoComponent.createAcl(properties, existing.getEntries(), actuallyInherited); + idToInheritFrom = newAcl.getId(); + nodeDAO.setNodeAclId(nodeId, idToInheritFrom); + } + else + { + // Already fixed up + return result; + } + } + else + { + // Set default ACL on roots with no settings + if (isRoot) + { + result.increment(ACLType.DEFINING); + + AccessControlListProperties properties = aclDaoComponent.getDefaultProperties(); + DbAccessControlList newAcl = aclDaoComponent.createDbAccessControlList(properties); + long id = newAcl.getId(); + + idToInheritFrom = id; + nodeDAO.setNodeAclId(nodeId, id); + } + else + { + // Unset - simple inherit + nodeDAO.setNodeAclId(nodeId, inherited); + } + } + + List children = nodeDAO.getPrimaryChildrenAcls(nodeId); + if (children.size() > 0) + { + // Only make inherited if required + if (toInherit == null) + { + if (idToInheritFrom == null) + { + toInherit = inherited; + } + else + { + toInherit = aclDaoComponent.getInheritedAccessControlList(idToInheritFrom); + } + } + + } + for (NodeIdAndAclId child : children) + { + CounterSet update = fixOldDmAcls(child.getId(), toInherit, false); + result.add(update); + } + + return result; + } + + public void setAccessControlList(NodeRef nodeRef, Long aclId) + { + Long nodeId = getNodeIdNotNull(nodeRef); + nodeDAO.setNodeAclId(nodeId, aclId); + } + + public void setAccessControlList(NodeRef nodeRef, DbAccessControlList acl) + { + Long aclId = null; + if (acl != null) + { + aclId = acl.getId(); + } + setAccessControlList(nodeRef, aclId); + } + + public void setAccessControlList(StoreRef storeRef, DbAccessControlList acl) + { + throw new UnsupportedOperationException(); + } + + public List setInheritanceForChildren(NodeRef parent, Long inheritFrom, Long sharedAclToReplace) + { + List changes = new ArrayList(); + setFixedAcls(getNodeIdNotNull(parent), inheritFrom, null, sharedAclToReplace, changes, false); + return changes; + } + + public void updateChangedAcls(NodeRef startingPoint, List changes) + { + // Nothing to do: no nodes change as a result of ACL changes + } + + /** + * Support to set a shared ACL on a node and all of its children + * + * @param nodeRef + * the parent node + * @param inheritFrom + * the parent node's ACL + * @param mergeFrom + * the shared ACL, if already known. If null, will be retrieved / created lazily + * @param changes + * the list in which to record changes + * @param set + * set the shared ACL on the parent ? + */ + public void setFixedAcls(Long nodeId, Long inheritFrom, Long mergeFrom, Long sharedAclToReplace, List changes, boolean set) + { + if (nodeId == null) + { + return; + } + else + { + if (set) + { + // Lazily retrieve/create the shared ACL + if (mergeFrom == null) + { + mergeFrom = aclDaoComponent.getInheritedAccessControlList(inheritFrom); + } + nodeDAO.setNodeAclId(nodeId, mergeFrom); + } + + // update all shared in one shot - recurse later + + if (mergeFrom == null) + { + mergeFrom = aclDaoComponent.getInheritedAccessControlList(inheritFrom); + } + + + List children = nodeDAO.getPrimaryChildrenAcls(nodeId); + + if(children.size() > 0) + { + nodeDAO.setPrimaryChildrenSharedAclId(nodeId, sharedAclToReplace, mergeFrom); + } + + for (NodeIdAndAclId child : children) + { + // Lazily retrieve/create the shared ACL + if (mergeFrom == null) + { + mergeFrom = aclDaoComponent.getInheritedAccessControlList(inheritFrom); + } + + Long acl = child.getAclId(); + + if (acl == null) + { + setFixedAcls(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false); + } + else + { +// if(acl.equals(mergeFrom)) +// { +// setFixedAcls(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false); +// } + // Already replaced + if(acl.equals(sharedAclToReplace)) + { + setFixedAcls(child.getId(), inheritFrom, mergeFrom, sharedAclToReplace, changes, false); + } + else + { + DbAccessControlList dbAcl = aclDaoComponent.getDbAccessControlList(acl); + if (dbAcl.getAclType() == ACLType.LAYERED) + { + throw new UnsupportedOperationException(); + } + else if (dbAcl.getAclType() == ACLType.DEFINING) + { + if (dbAcl.getInherits()) + { + @SuppressWarnings("unused") + List newChanges = aclDaoComponent.mergeInheritedAccessControlList(mergeFrom, acl); + } + } + else if (dbAcl.getAclType() == ACLType.SHARED) + { + throw new IllegalStateException(); + } + } + } + } + } + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.AccessControlListDAO#updateInheritance(java.lang.Long, java.lang.Long, java.lang.Long) + */ + public void updateInheritance(Long childNodeId, Long oldParentNodeId, Long newParentNodeId) + { + if(oldParentNodeId == null) + { + // nothing to do + return; + } + List changes = new ArrayList(); + Long newParentAclId = nodeDAO.getNodeAclId(newParentNodeId); + + Long childAclId = nodeDAO.getNodeAclId(childNodeId); + if(childAclId == null) + { + if(newParentAclId != null) + { + Long newParentSharedAclId = aclDaoComponent.getInheritedAccessControlList(newParentAclId); + setFixedAcls(childNodeId, newParentSharedAclId, null, null, changes, true); + } + } + DbAccessControlList dbAccessControlList = aclDaoComponent.getDbAccessControlList(childAclId); + if(dbAccessControlList != null) + { + if(dbAccessControlList.getInherits()) + { + // Does it inherit from the old parent - if not nothing changes + Long oldParentAclId = nodeDAO.getNodeAclId(oldParentNodeId); + if(oldParentAclId != null) + { + Long oldParentSharedAclId = aclDaoComponent.getInheritedAccessControlList(oldParentAclId); + Long sharedAclchildInheritsFrom = dbAccessControlList.getInheritsFrom(); + if(childAclId.equals(oldParentSharedAclId)) + { + // child had old shared acl + if(newParentAclId != null) + { + Long newParentSharedAclId = aclDaoComponent.getInheritedAccessControlList(newParentAclId); + setFixedAcls(childNodeId, newParentSharedAclId, null, childAclId, changes, true); + } + } + else if(sharedAclchildInheritsFrom == null) + { + // child has defining acl of some form that does not inherit ? + // Leave alone + } + else if(sharedAclchildInheritsFrom.equals(oldParentSharedAclId)) + { + // child has defining acl and needs to be remerged + if (dbAccessControlList.getAclType() == ACLType.LAYERED) + { + throw new UnsupportedOperationException(); + } + else if (dbAccessControlList.getAclType() == ACLType.DEFINING) + { + Long newParentSharedAclId = aclDaoComponent.getInheritedAccessControlList(newParentAclId); + @SuppressWarnings("unused") + List newChanges = aclDaoComponent.mergeInheritedAccessControlList(newParentSharedAclId, childAclId); + } + else if (dbAccessControlList.getAclType() == ACLType.SHARED) + { + throw new IllegalStateException(); + } + } + else + { + // the acl does not inherit from a node and does not need to be fixed up + // Leave alone + } + } + } + } + } +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/DMPermissionsDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/permissions/ADMPermissionsDaoComponentImpl.java similarity index 66% rename from source/java/org/alfresco/repo/domain/hibernate/DMPermissionsDaoComponentImpl.java rename to source/java/org/alfresco/repo/domain/permissions/ADMPermissionsDaoComponentImpl.java index a7bae8a629..1fbbba70ba 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/DMPermissionsDaoComponentImpl.java +++ b/source/java/org/alfresco/repo/domain/permissions/ADMPermissionsDaoComponentImpl.java @@ -1,22 +1,28 @@ /* * Copyright (C) 2005-2010 Alfresco Software Limited. * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing */ -package org.alfresco.repo.domain.hibernate; +package org.alfresco.repo.domain.permissions; import java.util.ArrayList; import java.util.Collections; @@ -28,19 +34,17 @@ import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties; import org.alfresco.repo.security.permissions.impl.AclChange; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** - * Manage creation and deletion of ACL entries for the new DM ACL implementation + * ADM permissions dao component impl + * + * Manage creation and deletion of ACL entries for the new ADM ACL implementation * * @author andyh * */ -public class DMPermissionsDaoComponentImpl extends AbstractPermissionsDaoComponentImpl +public class ADMPermissionsDaoComponentImpl extends AbstractPermissionsDaoComponentImpl { - private static Log logger = LogFactory.getLog(DMPermissionsDaoComponentImpl.class); - @Override protected CreationReport createAccessControlList(NodeRef nodeRef, boolean inherit, DbAccessControlList existing) { @@ -50,12 +54,13 @@ public class DMPermissionsDaoComponentImpl extends AbstractPermissionsDaoCompone properties.setAclType(ACLType.DEFINING); properties.setInherits(inherit); properties.setVersioned(false); - // Accept default versioning - Long id = aclDaoComponent.createAccessControlList(properties); + + DbAccessControlList acl = aclDaoComponent.createDbAccessControlList(properties); + long id = acl.getId(); + List changes = new ArrayList(); - DbAccessControlList acl = aclDaoComponent.getDbAccessControlList(id); - changes.add(new AclDaoComponentImpl.AclChangeImpl(null, id, null, acl.getAclType())); - changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id)); + changes.add(new AclDAOImpl.AclChangeImpl(null, id, null, acl.getAclType())); + changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id, null)); getACLDAO(nodeRef).setAccessControlList(nodeRef, acl); return new CreationReport(acl, changes); } @@ -77,14 +82,16 @@ public class DMPermissionsDaoComponentImpl extends AbstractPermissionsDaoCompone properties.setAclType(ACLType.DEFINING); properties.setInherits(existing.getInherits()); properties.setVersioned(false); - id = aclDaoComponent.createAccessControlList(properties); + + acl = aclDaoComponent.createDbAccessControlList(properties); + id = acl.getId(); + changes = new ArrayList(); - acl = aclDaoComponent.getDbAccessControlList(id); - changes.add(new AclDaoComponentImpl.AclChangeImpl(existing.getId(), id, existing.getAclType(), acl.getAclType())); + changes.add(new AclDAOImpl.AclChangeImpl(existing.getId(), id, existing.getAclType(), acl.getAclType())); changes.addAll(aclDaoComponent.mergeInheritedAccessControlList(existing.getId(), id)); // set this to inherit to children - changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id)); - + changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id, aclDaoComponent.getInheritedAccessControlList(existing.getId()))); + getACLDAO(nodeRef).setAccessControlList(nodeRef, acl); return new CreationReport(acl, changes); case LAYERED: @@ -92,9 +99,8 @@ public class DMPermissionsDaoComponentImpl extends AbstractPermissionsDaoCompone default: throw new IllegalStateException("Unknown type " + existing.getAclType()); } - } - + public void deletePermissions(NodeRef nodeRef) { DbAccessControlList acl = null; @@ -106,10 +112,7 @@ public class DMPermissionsDaoComponentImpl extends AbstractPermissionsDaoCompone { return; } - - if (logger.isDebugEnabled()) - logger.debug("Deleting " + acl + " on " + nodeRef); - + System.out.println("Deleting "+acl+" on "+nodeRef); if (acl != null) { switch (acl.getAclType()) @@ -119,28 +122,28 @@ public class DMPermissionsDaoComponentImpl extends AbstractPermissionsDaoCompone case DEFINING: if (acl.getInheritsFrom() != null) { - Long deleted = acl.getId(); Long inheritsFrom = acl.getInheritsFrom(); getACLDAO(nodeRef).setAccessControlList(nodeRef, aclDaoComponent.getDbAccessControlList(inheritsFrom)); List changes = new ArrayList(); - changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, inheritsFrom)); + changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, inheritsFrom, aclDaoComponent.getInheritedAccessControlList(acl.getId()))); getACLDAO(nodeRef).updateChangedAcls(nodeRef, changes); aclDaoComponent.deleteAccessControlList(acl.getId()); } else { - // TODO: could just cear out existing - Long deleted = acl.getId(); + // TODO: could just clear out existing SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); properties = new SimpleAccessControlListProperties(); properties.setAclType(ACLType.DEFINING); properties.setInherits(Boolean.FALSE); properties.setVersioned(false); - - Long id = aclDaoComponent.createAccessControlList(properties); - getACLDAO(nodeRef).setAccessControlList(nodeRef, aclDaoComponent.getDbAccessControlList(id)); + + DbAccessControlList newAcl = aclDaoComponent.createDbAccessControlList(properties); + long id = newAcl.getId(); + + getACLDAO(nodeRef).setAccessControlList(nodeRef, newAcl); List changes = new ArrayList(); - changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id)); + changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id, acl.getInheritedAcl())); getACLDAO(nodeRef).updateChangedAcls(nodeRef, changes); aclDaoComponent.deleteAccessControlList(acl.getId()); } @@ -158,22 +161,5 @@ public class DMPermissionsDaoComponentImpl extends AbstractPermissionsDaoCompone throw new IllegalStateException("Unknown type " + acl.getAclType()); } } - } - - - /** - * Get the default ACL properties - * - * @return the default properties - */ - public static SimpleAccessControlListProperties getDefaultProperties() - { - SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); - properties.setAclType(ACLType.DEFINING); - properties.setInherits(true); - properties.setVersioned(false); - return properties; - } - } diff --git a/source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java b/source/java/org/alfresco/repo/domain/permissions/AVMAccessControlListDAO.java similarity index 80% rename from source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java rename to source/java/org/alfresco/repo/domain/permissions/AVMAccessControlListDAO.java index e2f2d8e925..6acc1b53f7 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java +++ b/source/java/org/alfresco/repo/domain/permissions/AVMAccessControlListDAO.java @@ -1,23 +1,29 @@ /* * Copyright (C) 2005-2010 Alfresco Software Limited. * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have received a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.domain.hibernate; +package org.alfresco.repo.domain.permissions; import java.util.ArrayList; import java.util.HashMap; @@ -33,8 +39,8 @@ import org.alfresco.repo.avm.util.AVMUtil; import org.alfresco.repo.domain.AccessControlListDAO; import org.alfresco.repo.domain.DbAccessControlList; import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.hibernate.AclDaoComponentImpl.Indirection; -import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor; +import org.alfresco.repo.domain.avm.AVMNodeDAO; +import org.alfresco.repo.domain.avm.AVMNodeEntity; import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor.StoreType; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; @@ -43,7 +49,6 @@ import org.alfresco.repo.security.permissions.AccessControlEntry; import org.alfresco.repo.security.permissions.AccessControlList; import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties; import org.alfresco.repo.security.permissions.impl.AclChange; -import org.alfresco.repo.security.permissions.impl.AclDaoComponent; import org.alfresco.service.cmr.avm.AVMException; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMService; @@ -67,31 +72,13 @@ import org.apache.commons.logging.LogFactory; */ public class AVMAccessControlListDAO implements AccessControlListDAO { - /** - * The logger. - */ private static Log s_logger = LogFactory.getLog(AVMAccessControlListDAO.class); - - /** - * Reference to the AVM Repository instance. - */ + private AVMRepository fAVMRepository; - private AVMService fAVMService; - - private AclDaoComponent aclDaoComponent; - - private AVMSnapShotTriggeredIndexingMethodInterceptor avmSnapShotTriggeredIndexingMethodInterceptor; - - private HibernateSessionHelper hibernateSessionHelper; - - /** - * Default constructory. - */ - public AVMAccessControlListDAO() - { - } - + private AclDAO aclDaoComponent; + private AVMNodeDAO avmNodeDAO; + /** * Set the AVM repository * @@ -101,7 +88,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO { fAVMRepository = repository; } - + /** * Set the AVM service * @@ -111,33 +98,30 @@ public class AVMAccessControlListDAO implements AccessControlListDAO { fAVMService = avmService; } - + /** * Set the ACL DAO component * - * @param aclDaoComponent + * @param aclDAO */ - public void setAclDaoComponent(AclDaoComponent aclDaoComponent) + public void setAclDAO(AclDAO aclDaoComponent) { this.aclDaoComponent = aclDaoComponent; } - - /** - * @param avmSnapShotTriggeredIndexingMethodInterceptor - */ - public void setAvmSnapShotTriggeredIndexingMethodInterceptor(AVMSnapShotTriggeredIndexingMethodInterceptor avmSnapShotTriggeredIndexingMethodInterceptor) + + public void setAvmNodeDAO(AVMNodeDAO avmNodeDAO) { - this.avmSnapShotTriggeredIndexingMethodInterceptor = avmSnapShotTriggeredIndexingMethodInterceptor; + this.avmNodeDAO = avmNodeDAO; } - + + /** - * @param hibernateSessionHelper + * Default constructor */ - public void setHibernateSessionHelper(HibernateSessionHelper hibernateSessionHelper) + public AVMAccessControlListDAO() { - this.hibernateSessionHelper = hibernateSessionHelper; } - + public Long getIndirectAcl(NodeRef nodeRef) { Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); @@ -313,40 +297,32 @@ public class AVMAccessControlListDAO implements AccessControlListDAO private void updateChangedAclsImpl(NodeRef startingPoint, List changes, SetMode mode, Long inherited, Long setAcl, Map> indirections) { - hibernateSessionHelper.mark(); - try + HashMap changeMap = new HashMap(); + HashSet unchangedSet = new HashSet(); + for (AclChange change : changes) { - HashMap changeMap = new HashMap(); - HashSet unchangedSet = new HashSet(); - for (AclChange change : changes) + if (change.getBefore() == null) { - if (change.getBefore() == null) - { - // null is treated using the inherited acl - } - else if (!change.getBefore().equals(change.getAfter())) - { - changeMap.put(change.getBefore(), change.getAfter()); - } - else - { - unchangedSet.add(change.getBefore()); - } + // null is treated using the inherited acl } - unchangedSet.add(inherited); - unchangedSet.add(setAcl); + else if (!change.getBefore().equals(change.getAfter())) + { + changeMap.put(change.getBefore(), change.getAfter()); + } + else + { + unchangedSet.add(change.getBefore()); + } + } + unchangedSet.add(inherited); + unchangedSet.add(setAcl); - if (inherited != null) - { - updateReferencingLayeredAcls(startingPoint, inherited, indirections); - } - updateInheritedChangedAcls(startingPoint, changeMap, unchangedSet, inherited, mode, indirections); - updateLayeredAclsChangedByInheritance(changes, changeMap, unchangedSet, indirections); - } - finally + if (inherited != null) { - hibernateSessionHelper.resetAndRemoveMark(); + updateReferencingLayeredAcls(startingPoint, inherited, indirections); } + updateInheritedChangedAcls(startingPoint, changeMap, unchangedSet, inherited, mode, indirections); + updateLayeredAclsChangedByInheritance(changes, changeMap, unchangedSet, indirections); } public void forceCopy(NodeRef nodeRef) @@ -381,7 +357,6 @@ public class AVMAccessControlListDAO implements AccessControlListDAO { AVMNodeDescriptor descriptor = fAVMService.lookup(version, path); return descriptor; - } catch (AVMException e) { @@ -389,6 +364,104 @@ public class AVMAccessControlListDAO implements AccessControlListDAO } } + /** + * Support to describe AVM indirections for permission performance improvements when permissions are set. + * + * @author andyh + */ + public static class Indirection + { + Long from; + String to; + Integer toVersion; + + Indirection(Long from, String to, Integer toVersion) + { + this.from = from; + this.to = to; + this.toVersion = toVersion; + } + + /** + * @return - from id + */ + public Long getFrom() + { + return from; + } + + /** + * @return - to id + */ + public String getTo() + { + return to; + } + + /** + * @return - version + */ + public Integer getToVersion() + { + return toVersion; + } + } + + + /** + * Find layered directories Used to improve performance during patching and cascading the effect of permission + * changes between layers + * + * @return - layered directories + */ + private List getLayeredDirectories() + { + List ldNodeEntities = avmNodeDAO.getAllLayeredDirectories(); + + ArrayList indirections = new ArrayList(ldNodeEntities.size()); + + for (AVMNodeEntity ldNodeEntity : ldNodeEntities) + { + Long from = ldNodeEntity.getId(); + String to = ldNodeEntity.getIndirection(); + Integer version = ldNodeEntity.getIndirectionVersion(); + indirections.add(new Indirection(from, to, version)); + } + return indirections; + } + + /** + * Find layered files Used to improve performance during patching and cascading the effect of permission changes + * between layers + * + * @return - layered files + */ + private List getLayeredFiles() + { + List lfNodeEntities = avmNodeDAO.getAllLayeredFiles(); + + ArrayList indirections = new ArrayList(lfNodeEntities.size()); + + for (AVMNodeEntity lfNodeEntity : lfNodeEntities) + { + Long from = lfNodeEntity.getId(); + String to = lfNodeEntity.getIndirection(); + Integer version = lfNodeEntity.getIndirectionVersion(); + indirections.add(new Indirection(from, to, version)); + } + return indirections; + } + + private List getAvmIndirections() + { + List dirList = getLayeredDirectories(); + List fileList = getLayeredFiles(); + ArrayList answer = new ArrayList(dirList.size() + fileList.size()); + answer.addAll(dirList); + answer.addAll(fileList); + return answer; + } + private Map> buildIndirections(AVMNodeDescriptor desc) { if ((desc != null) && (desc.getVersionID() == 1)) @@ -409,7 +482,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO Map> answer = new HashMap>(); - List indirections = aclDaoComponent.getAvmIndirections(); + List indirections = getAvmIndirections(); for (Indirection indirection : indirections) { AVMNodeDescriptor toDesc = fAVMService.lookup(indirection.getToVersion(), indirection.getTo(), true); @@ -506,8 +579,8 @@ public class AVMAccessControlListDAO implements AccessControlListDAO if ((change.getTypeBefore() == ACLType.LAYERED) && (change.getTypeAfter() == ACLType.LAYERED)) { // Query for affected nodes - List avmNodeIds = aclDaoComponent.getAvmNodesByACL(change.getBefore()); - + List avmNodeIds = aclDaoComponent.getAVMNodesByAcl(change.getBefore(), -1); + for (Long id : avmNodeIds) { // Find all paths to the nodes @@ -613,15 +686,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO } for (AVMNodeDescriptor child : children.values()) { - hibernateSessionHelper.mark(); - try - { - fixUpAcls(child, changes, unchanged, unsetAcl, mode, indirections); - } - finally - { - hibernateSessionHelper.resetAndRemoveMark(); - } + fixUpAcls(child, changes, unchanged, unsetAcl, mode, indirections); } } @@ -640,7 +705,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO } } - public List setInheritanceForChildren(NodeRef parent, Long inheritFrom) + public List setInheritanceForChildren(NodeRef parent, Long inheritFrom, Long sharedAclToReplace) { // Walk children and fix up any that reference the given list .. // If previous is null we need to visit all descendants with a null acl and set @@ -740,15 +805,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO if (acl == null) { - hibernateSessionHelper.mark(); - try - { - setFixedAcls(child, inheritFrom, mergeFrom, changes, mode, true, indirections); - } - finally - { - hibernateSessionHelper.resetAndRemoveMark(); - } + setFixedAcls(child, inheritFrom, mergeFrom, changes, mode, true, indirections); } else if (acl.getAclType() == ACLType.LAYERED) { @@ -766,34 +823,17 @@ public class AVMAccessControlListDAO implements AccessControlListDAO { if (change.getBefore().equals(acl.getId())) { - hibernateSessionHelper.mark(); - try - { - setAclAsSystem(child.getPath(), aclDaoComponent.getDbAccessControlList(change.getAfter())); - setFixedAcls(child, change.getAfter(), null, newChanges, SetMode.DIRECT_ONLY, false, indirections); - changes.addAll(newChanges); - break; - } - finally - { - hibernateSessionHelper.resetAndRemoveMark(); - } + setAclAsSystem(child.getPath(), aclDaoComponent.getDbAccessControlList(change.getAfter())); + setFixedAcls(child, change.getAfter(), null, newChanges, SetMode.DIRECT_ONLY, false, indirections); + changes.addAll(newChanges); + break; } } } else { - hibernateSessionHelper.mark(); - try - { - setFixedAcls(child, inheritFrom, mergeFrom, changes, mode, true, indirections); - } - finally - { - hibernateSessionHelper.resetAndRemoveMark(); - } + setFixedAcls(child, inheritFrom, mergeFrom, changes, mode, true, indirections); } - } } } @@ -870,15 +910,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO private CounterSet fixOldAvmAcls(AVMNodeDescriptor node, boolean searchDirectories, Map> indirections) { - hibernateSessionHelper.mark(); - try - { - return fixOldAvmAclsImpl(node, searchDirectories, indirections); - } - finally - { - hibernateSessionHelper.resetAndRemoveMark(); - } + return fixOldAvmAclsImpl(node, searchDirectories, indirections); } private CounterSet fixOldAvmAclsImpl(AVMNodeDescriptor node, boolean searchDirectories, Map> indirections) @@ -906,10 +938,11 @@ public class AVMAccessControlListDAO implements AccessControlListDAO // SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); properties.setAclType(ACLType.DEFINING); - // Accept default versioning - Long id = aclDaoComponent.createAccessControlList(properties); - DbAccessControlList newAcl = aclDaoComponent.getDbAccessControlList(id); - + properties.setVersioned(true); + + DbAccessControlList newAcl = aclDaoComponent.createDbAccessControlList(properties); + long id = newAcl.getId(); + AccessControlList existing = aclDaoComponent.getAccessControlList(existingAcl.getId()); for (AccessControlEntry entry : existing.getEntries()) { @@ -952,21 +985,21 @@ public class AVMAccessControlListDAO implements AccessControlListDAO DbAccessControlList acl = getAclAsSystem(-1, referencedNode.getPath()); if (acl != null) { - setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(acl.getId())); + setAclAsSystem(node.getPath(), aclDaoComponent.createLayeredAcl(acl.getId())); } else { - setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(null)); + setAclAsSystem(node.getPath(), aclDaoComponent.createLayeredAcl(null)); } } else { - setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(null)); + setAclAsSystem(node.getPath(), aclDaoComponent.createLayeredAcl(null)); } } else { - setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(null)); + setAclAsSystem(node.getPath(), aclDaoComponent.createLayeredAcl(null)); } List changes = new ArrayList(); @@ -989,24 +1022,24 @@ public class AVMAccessControlListDAO implements AccessControlListDAO AVMNodeDescriptor referencedNode = fAVMService.lookup(-1, node.getIndirection(), false); if (referencedNode != null) { - DbAccessControlList acl = getAclAsSystem(-1, referencedNode.getPath()); + Acl acl = getAclAsSystem(-1, referencedNode.getPath()); if (acl != null) { - setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(acl.getId())); + setAclAsSystem(node.getPath(), aclDaoComponent.createLayeredAcl(acl.getId())); } else { - setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(null)); + setAclAsSystem(node.getPath(), aclDaoComponent.createLayeredAcl(null)); } } else { - setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(null)); + setAclAsSystem(node.getPath(), aclDaoComponent.createLayeredAcl(null)); } } else { - setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(null)); + setAclAsSystem(node.getPath(), aclDaoComponent.createLayeredAcl(null)); } List changes = new ArrayList(); @@ -1170,4 +1203,12 @@ public class AVMAccessControlListDAO implements AccessControlListDAO } } + /* (non-Javadoc) + * @see org.alfresco.repo.domain.AccessControlListDAO#updateInheritance(java.lang.Long, java.lang.Long, java.lang.Long) + */ + public void updateInheritance(Long childNodeId, Long oldParentNodeId, Long newParentNodeId) + { + throw new UnsupportedOperationException(); + } + } diff --git a/source/java/org/alfresco/repo/domain/hibernate/PermissionsDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/permissions/AVMPermissionsDaoComponentImpl.java similarity index 68% rename from source/java/org/alfresco/repo/domain/hibernate/PermissionsDaoComponentImpl.java rename to source/java/org/alfresco/repo/domain/permissions/AVMPermissionsDaoComponentImpl.java index 9343b6ee29..8dfd7cbd19 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/PermissionsDaoComponentImpl.java +++ b/source/java/org/alfresco/repo/domain/permissions/AVMPermissionsDaoComponentImpl.java @@ -1,22 +1,28 @@ /* * Copyright (C) 2005-2010 Alfresco Software Limited. * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.domain.hibernate; +package org.alfresco.repo.domain.permissions; import java.util.ArrayList; import java.util.Collections; @@ -32,13 +38,14 @@ import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; /** - * Old permissions dao component impl + * AVM permissions dao component impl + * + * Manage creation and deletion of ACL entries for the AVM ACL implementation * * @author andyh */ -public class PermissionsDaoComponentImpl extends AbstractPermissionsDaoComponentImpl +public class AVMPermissionsDaoComponentImpl extends AbstractPermissionsDaoComponentImpl { - @Override protected CreationReport createAccessControlList(NodeRef nodeRef, boolean inherit, DbAccessControlList existing) { @@ -46,12 +53,14 @@ public class PermissionsDaoComponentImpl extends AbstractPermissionsDaoComponent { SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); properties.setAclType(ACLType.DEFINING); - // Accept default versioning - Long id = aclDaoComponent.createAccessControlList(properties); + properties.setVersioned(true); + + DbAccessControlList acl = aclDaoComponent.createDbAccessControlList(properties); + long id = acl.getId(); + List changes = new ArrayList(); - DbAccessControlList acl = aclDaoComponent.getDbAccessControlList(id); - changes.add(new AclDaoComponentImpl.AclChangeImpl(null, id, null, acl.getAclType())); - changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id)); + changes.add(new AclDAOImpl.AclChangeImpl(null, id, null, acl.getAclType())); + changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id, null)); getACLDAO(nodeRef).setAccessControlList(nodeRef, acl); return new CreationReport(acl, changes); } @@ -72,22 +81,24 @@ public class PermissionsDaoComponentImpl extends AbstractPermissionsDaoComponent properties = new SimpleAccessControlListProperties(); properties.setAclType(ACLType.DEFINING); properties.setInherits(existing.getInherits()); - // Accept default versioning - id = aclDaoComponent.createAccessControlList(properties); + properties.setVersioned(true); + + acl = aclDaoComponent.createDbAccessControlList(properties); + id = acl.getId(); + changes = new ArrayList(); - acl = aclDaoComponent.getDbAccessControlList(id); - changes.add(new AclDaoComponentImpl.AclChangeImpl(existing.getId(), id, existing.getAclType(), acl.getAclType())); + changes.add(new AclDAOImpl.AclChangeImpl(existing.getId(), id, existing.getAclType(), acl.getAclType())); changes.addAll(aclDaoComponent.mergeInheritedAccessControlList(existing.getId(), id)); // set this to inherit to children - changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id)); - + changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id, aclDaoComponent.getInheritedAccessControlList(existing.getId()))); + getACLDAO(nodeRef).setAccessControlList(nodeRef, acl); return new CreationReport(acl, changes); case LAYERED: // Need to get the indirected node ACL Long indirectAclId = getACLDAO(nodeRef).getIndirectAcl(nodeRef); Long inheritedAclId = getACLDAO(nodeRef).getInheritedAcl(nodeRef); - + // create new defining, wire up and report changes to acl required. properties = new SimpleAccessControlListProperties(); properties.setAclType(ACLType.DEFINING); @@ -95,11 +106,13 @@ public class PermissionsDaoComponentImpl extends AbstractPermissionsDaoComponent { properties.setInherits(aclDaoComponent.getAccessControlListProperties(indirectAclId).getInherits()); } - // Accept default versioning - id = aclDaoComponent.createAccessControlList(properties); + properties.setVersioned(true); + + acl = aclDaoComponent.createDbAccessControlList(properties); + id = acl.getId(); + changes = new ArrayList(); - acl = aclDaoComponent.getDbAccessControlList(id); - changes.add(new AclDaoComponentImpl.AclChangeImpl(existing.getId(), id, existing.getAclType(), acl.getAclType())); + changes.add(new AclDAOImpl.AclChangeImpl(existing.getId(), id, existing.getAclType(), acl.getAclType())); if (indirectAclId != null) { AccessControlList indirectAcl = aclDaoComponent.getAccessControlList(indirectAclId); @@ -116,15 +129,15 @@ public class PermissionsDaoComponentImpl extends AbstractPermissionsDaoComponent changes.addAll(aclDaoComponent.mergeInheritedAccessControlList(inheritedAclId, id)); } // set this to inherit to children - changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id)); - + changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id, existing.getInheritedAcl())); + getACLDAO(nodeRef).setAccessControlList(nodeRef, acl); return new CreationReport(acl, changes); default: throw new IllegalStateException("Unknown type " + existing.getAclType()); } } - + public void deletePermissions(NodeRef nodeRef) { DbAccessControlList acl = null; @@ -143,31 +156,29 @@ public class PermissionsDaoComponentImpl extends AbstractPermissionsDaoComponent case OLD: throw new IllegalStateException("Can not mix old and new style permissions"); case DEFINING: - if (acl.getInheritsFrom() != null) { - @SuppressWarnings("unused") - Long deleted = acl.getId(); Long inheritsFrom = acl.getInheritsFrom(); getACLDAO(nodeRef).setAccessControlList(nodeRef, aclDaoComponent.getDbAccessControlList(inheritsFrom)); List changes = new ArrayList(); - changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, inheritsFrom)); + changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, inheritsFrom, aclDaoComponent.getInheritedAccessControlList(acl.getId()))); getACLDAO(nodeRef).updateChangedAcls(nodeRef, changes); aclDaoComponent.deleteAccessControlList(acl.getId()); } else { // TODO: could just cear out existing - @SuppressWarnings("unused") - Long deleted = acl.getId(); SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); properties.setAclType(ACLType.DEFINING); properties.setInherits(Boolean.FALSE); - // Accept default versioning - Long id = aclDaoComponent.createAccessControlList(properties); - getACLDAO(nodeRef).setAccessControlList(nodeRef, aclDaoComponent.getDbAccessControlList(id)); + properties.setVersioned(true); + + DbAccessControlList newAcl = aclDaoComponent.createDbAccessControlList(properties); + long id = newAcl.getId(); + + getACLDAO(nodeRef).setAccessControlList(nodeRef, newAcl); List changes = new ArrayList(); - changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id)); + changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id, acl.getInheritedAcl())); getACLDAO(nodeRef).updateChangedAcls(nodeRef, changes); aclDaoComponent.deleteAccessControlList(acl.getId()); } diff --git a/source/java/org/alfresco/repo/domain/permissions/AbstractAclCrudDAOImpl.java b/source/java/org/alfresco/repo/domain/permissions/AbstractAclCrudDAOImpl.java new file mode 100644 index 0000000000..483f878508 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AbstractAclCrudDAOImpl.java @@ -0,0 +1,1008 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.cache.lookup.EntityLookupCache; +import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAO; +import org.alfresco.repo.domain.CrcHelper; +import org.alfresco.repo.domain.qname.QNameDAO; +import org.alfresco.repo.security.permissions.ACEType; +import org.alfresco.repo.security.permissions.PermissionReference; +import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.extensions.surf.util.ParameterCheck; + + +/** + * Abstract implementation for ACL crud DAO. + *

+ * This provides basic services such as caching, but defers to the underlying implementation + * for CRUD operations for: + * + * alf_access_control_list + * alf_acl_member + * alf_acl_change_set + * alf_access_control_entry + * alf_permission + * alf_authority + * + * Also, following are currently unused: + * + * alf_ace_context + * alf_authority_alias + * + * + * + * @author janv + * @since 3.4 + */ +public abstract class AbstractAclCrudDAOImpl implements AclCrudDAO +{ + private static final String CACHE_REGION_ACL = "Acl"; + private static final String CACHE_REGION_AUTHORITY = "Authority"; + private static final String CACHE_REGION_PERMISSION = "Permission"; + + private final AclEntityCallbackDAO aclEntityDaoCallback; + private final AuthorityEntityCallbackDAO authorityEntityDaoCallback; + private final PermissionEntityCallbackDAO permissionEntityDaoCallback; + + private QNameDAO qnameDAO; + private static int batchSize = 500; + + public void setQnameDAO(QNameDAO qnameDAO) + { + this.qnameDAO = qnameDAO; + } + + public void setBatchSize(int batchSizeOverride) + { + batchSize = batchSizeOverride; + } + + /** + * Cache for the ACL entity:
+ * KEY: ID (ACL)
+ * VALUE: AclEntity
+ * VALUE KEY: None
+ */ + private EntityLookupCache aclCache; + + /** + * Cache for the Authority entity:
+ * KEY: ID (Authority)
+ * VALUE: AuthorityEntity
+ * VALUE KEY: Name
+ */ + private EntityLookupCache authorityCache; + + /** + * Cache for the Permission entity:
+ * KEY: ID (Permission)
+ * VALUE: PermissionEntity
+ * VALUE KEY: PermissionEntity (compound key: qnameId + name)
+ */ + private EntityLookupCache permissionCache; + + /** + * Set the cache to use for alf_access_control_list lookups (optional). + * + * @param aclCache the cache of IDs to AclEntities + */ + public void setAclCache(SimpleCache aclCache) + { + this.aclCache = new EntityLookupCache( + aclCache, + CACHE_REGION_ACL, + aclEntityDaoCallback); + } + + /** + * Set the cache to use for alf_authority lookups (optional). + * + * @param authorityCache the cache of IDs to AclEntities + */ + public void setAuthorityCache(SimpleCache authorityCache) + { + this.authorityCache = new EntityLookupCache( + authorityCache, + CACHE_REGION_AUTHORITY, + authorityEntityDaoCallback); + } + + /** + * Set the cache to use for alf_permission lookups (optional). + * + * @param permissionCache the cache of IDs to PermissionEntities + */ + public void setPermissionCache(SimpleCache permissionCache) + { + this.permissionCache = new EntityLookupCache( + permissionCache, + CACHE_REGION_PERMISSION, + permissionEntityDaoCallback); + } + + + /** + * Default constructor. + *

+ * This sets up the DAO accessors to bypass any caching to handle the case where the caches are not + * supplied in the setters. + */ + public AbstractAclCrudDAOImpl() + { + this.aclEntityDaoCallback = new AclEntityCallbackDAO(); + this.aclCache = new EntityLookupCache(aclEntityDaoCallback); + + this.authorityEntityDaoCallback = new AuthorityEntityCallbackDAO(); + this.authorityCache = new EntityLookupCache(authorityEntityDaoCallback); + + this.permissionEntityDaoCallback = new PermissionEntityCallbackDAO(); + this.permissionCache = new EntityLookupCache(permissionEntityDaoCallback); + } + + // + // Access Control List (ACL) + // + + public AclEntity createAcl(AclEntity entity) + { + ParameterCheck.mandatory("entity", entity); + + ParameterCheck.mandatory("entity.aclId", entity.getAclId()); + ParameterCheck.mandatory("entity.aclVersion", entity.getAclVersion()); + + entity.setVersion(0L); + + Pair entityPair = aclCache.getOrCreateByValue(entity); + return entityPair.getSecond(); + } + + public Acl getAcl(long id) + { + return getAclImpl(id); + } + + private AclEntity getAclImpl(long id) + { + Pair entityPair = aclCache.getByKey(id); + if (entityPair == null) + { + return null; + } + return entityPair.getSecond(); + } + + public AclEntity getAclForUpdate(long id) + { + AclEntity acl = getAclImpl(id); + if (acl == null) + { + return null; + } + + // copy for update + AclEntity aclEntity = new AclEntity(); + aclEntity.setId(acl.getId()); + aclEntity.setVersion(acl.getVersion()); + aclEntity.setAclChangeSetId(acl.getAclChangeSetId()); + aclEntity.setAclId(acl.getAclId()); + aclEntity.setAclType(acl.getAclType()); + aclEntity.setAclVersion(acl.getAclVersion()); + aclEntity.setInheritedAcl(acl.getInheritedAcl()); + aclEntity.setInherits(acl.getInherits()); + aclEntity.setInheritsFrom(acl.getInheritsFrom()); + aclEntity.setLatest(acl.isLatest()); + aclEntity.setVersioned(acl.isVersioned()); + aclEntity.setRequiresVersion(acl.getRequiresVersion()); + + return aclEntity; + } + + public List getAclsThatInheritFromAcl(long aclEntityId) + { + // not cached + return getAclEntitiesThatInheritFromAcl(aclEntityId); + } + + public Long getLatestAclByGuid(String aclGuid) + { + // not cached + return getLatestAclEntityByGuid(aclGuid); + } + + public List getADMNodesByAcl(long aclEntityId, int maxResults) + { + return getADMNodeEntityIdsByAcl(aclEntityId, maxResults); + } + + public List getAVMNodesByAcl(long aclEntityId, int maxResults) + { + return getAVMNodeEntityIdsByAcl(aclEntityId, maxResults); + } + + public void updateAcl(AclEntity entity) + { + ParameterCheck.mandatory("entity", entity); + ParameterCheck.mandatory("entity.id", entity.getId()); + ParameterCheck.mandatory("entity.aclVersion", entity.getAclVersion()); + ParameterCheck.mandatory("entity.version", entity.getVersion()); + + int updated = aclCache.updateValue(entity.getId(), entity); + if (updated < 1) + { + throw new ConcurrencyFailureException("AclEntity with ID (" + entity.getId() + ") no longer exists or has been updated concurrently"); + } + } + + public void deleteAcl(long id) + { + Pair entityPair = aclCache.getByKey(id); + if (entityPair == null) + { + return; + } + + int deleted = aclCache.deleteByKey(id); + if (deleted < 1) + { + throw new ConcurrencyFailureException("AclEntity with ID " + id + " no longer exists"); + } + } + + /** + * Callback for alf_access_control_list DAO + */ + private class AclEntityCallbackDAO implements EntityLookupCallbackDAO + { + private final Pair convertEntityToPair(AclEntity entity) + { + if (entity == null) + { + return null; + } + else + { + return new Pair(entity.getId(), entity); + } + } + + public Serializable getValueKey(AclEntity value) + { + return null; + } + + public Pair createValue(AclEntity value) + { + AclEntity entity = createAclEntity(value); + return convertEntityToPair(entity); + } + + public Pair findByKey(Long key) + { + AclEntity entity = getAclEntity(key); + return convertEntityToPair(entity); + } + + public Pair findByValue(AclEntity value) + { + if ((value != null) && (value.getId() != null)) + { + return findByKey(value.getId()); + } + return null; + } + + public int updateValue(Long key, AclEntity value) + { + return updateAclEntity(value); + } + + public int deleteByKey(Long key) + { + return deleteAclEntity(key); + } + + public int deleteByValue(AclEntity value) + { + throw new UnsupportedOperationException("deleteByValue"); + } + } + + protected abstract AclEntity createAclEntity(AclEntity entity); + protected abstract AclEntity getAclEntity(long id); + protected abstract List getAclEntitiesThatInheritFromAcl(long idOfAcl); + protected abstract Long getLatestAclEntityByGuid(String aclGuid); + protected abstract int updateAclEntity(AclEntity entity); + protected abstract int deleteAclEntity(long id); + + protected abstract List getADMNodeEntityIdsByAcl(long aclEntityId, int maxResults); + protected abstract List getAVMNodeEntityIdsByAcl(long aclEntityId, int maxResults); + + // + // ACL Member + // + + public void addAclMembersToAcl(long aclId, List aceIds, int depth) + { + ParameterCheck.mandatory("aceIds", aceIds); + + List newMembers = new ArrayList(aceIds.size()); + + for (Long aceId : aceIds) + { + AclMemberEntity newMember = new AclMemberEntity(); + newMember.setAclId(aclId); + newMember.setAceId(aceId); + newMember.setPos(depth); + + AclMemberEntity result = createAclMemberEntity(newMember); + newMembers.add(result); + } + } + + public void addAclMembersToAcl(long aclId, List> aceIdsWithDepths) + { + ParameterCheck.mandatory("aceIdsWithDepths", aceIdsWithDepths); + + List newMembers = new ArrayList(aceIdsWithDepths.size()); + + for (Pair aceIdWithDepth : aceIdsWithDepths) + { + AclMemberEntity newMember = new AclMemberEntity(); + newMember.setAclId(aclId); + newMember.setAceId(aceIdWithDepth.getFirst()); + newMember.setPos(aceIdWithDepth.getSecond()); + + AclMemberEntity result = createAclMemberEntity(newMember); + newMembers.add(result); + } + } + + public List getAclMembersByAcl(long idOfAcl) + { + List entities = getAclMemberEntitiesByAcl(idOfAcl); + List result = new ArrayList(entities.size()); + result.addAll(entities); + return result; + } + + public List getAclMembersByAclForUpdate(long idOfAcl) + { + List members = getAclMemberEntitiesByAcl(idOfAcl); + List membersForUpdate = new ArrayList(members.size()); + for (AclMemberEntity member : members) + { + AclMemberEntity newMember = new AclMemberEntity(); + newMember.setId(member.getId()); + newMember.setVersion(member.getVersion()); + newMember.setAceId(member.getAceId()); + newMember.setAclId(member.getAclId()); + newMember.setPos(member.getPos()); + membersForUpdate.add(newMember); + } + return membersForUpdate; + } + + public List getAclMembersByAuthority(String authorityName) + { + List entities = getAclMemberEntitiesByAuthority(authorityName); + List result = new ArrayList(entities.size()); + result.addAll(entities); + return result; + } + + public void updateAclMember(AclMemberEntity entity) + { + ParameterCheck.mandatory("entity", entity); + ParameterCheck.mandatory("entity.id", entity.getId()); + ParameterCheck.mandatory("entity.version", entity.getVersion()); + ParameterCheck.mandatory("entity.aceId", entity.getAceId()); + ParameterCheck.mandatory("entity.aclId", entity.getAclId()); + ParameterCheck.mandatory("entity.pos", entity.getPos()); + + int updated = updateAclMemberEntity(entity); + + if (updated < 1) + { + throw new ConcurrencyFailureException("AclMemberEntity with ID (" + entity.getId() + ") no longer exists or has been updated concurrently"); + } + } + + public int deleteAclMembers(List aclMemberIds) + { + int totalDeletedCount = 0; + + if (aclMemberIds.size() == 0) + { + return 0; + } + else if (aclMemberIds.size() <= batchSize) + { + totalDeletedCount = deleteAclMemberEntities(aclMemberIds); + } + else + { + Iterator idIterator = aclMemberIds.iterator(); + List batchIds = new ArrayList(batchSize); + + while (idIterator.hasNext()) + { + Long id = idIterator.next(); + batchIds.add(id); + + if (batchIds.size() == batchSize || (! idIterator.hasNext())) + { + int batchDeletedCount = deleteAclMemberEntities(batchIds); + + totalDeletedCount = totalDeletedCount + batchDeletedCount; + batchIds.clear(); + } + } + } + + // TODO manually update the cache + + return totalDeletedCount; + } + + public int deleteAclMembersByAcl(long idOfAcl) + { + return deleteAclMemberEntitiesByAcl(idOfAcl); + } + + protected abstract AclMemberEntity createAclMemberEntity(AclMemberEntity entity); + protected abstract List getAclMemberEntitiesByAcl(long idOfAcl); + protected abstract List getAclMemberEntitiesByAuthority(String authorityName); + protected abstract int updateAclMemberEntity(AclMemberEntity entity); + protected abstract int deleteAclMemberEntities(List aclMemberIds); + protected abstract int deleteAclMemberEntitiesByAcl(long idOfAcl); + + // + // ACL Change Set + // + + public long createAclChangeSet() + { + return createAclChangeSetEntity(); + } + + public AclChangeSetEntity getAclChangeSet(long changeSetId) + { + return getAclChangeSetEntity(changeSetId); + } + + public void deleteAclChangeSet(long changeSetId) + { + deleteAclChangeSetEntity(changeSetId); + } + + protected abstract long createAclChangeSetEntity(); + protected abstract AclChangeSetEntity getAclChangeSetEntity(long changeSetId); + protected abstract int deleteAclChangeSetEntity(long id); + + + // + // Access Control Entry (ACE) + // + + public Ace createAce(Permission permission, Authority authority, ACEType type, AccessStatus accessStatus) + { + ParameterCheck.mandatory("permission", permission); + ParameterCheck.mandatory("authority", authority); + ParameterCheck.mandatory("type", type); + ParameterCheck.mandatory("accessStatus", accessStatus); + + AceEntity entity = new AceEntity(); + + entity.setApplies(type.getId()); // note: 'applies' stores the ACE type + entity.setAllowed((accessStatus == AccessStatus.ALLOWED) ? true : false); + entity.setAuthorityId(authority.getId()); + entity.setPermissionId(permission.getId()); + + long aceId = createAceEntity(entity); + + entity.setVersion(0L); + entity.setId(aceId); + + return entity; + } + + public Ace getAce(Permission permission, Authority authority, ACEType type, AccessStatus accessStatus) + { + ParameterCheck.mandatory("permission", permission); + ParameterCheck.mandatory("authority", authority); + ParameterCheck.mandatory("type", type); + ParameterCheck.mandatory("accessStatus", accessStatus); + + return getAceEntity(permission.getId(), + authority.getId(), + ((accessStatus == AccessStatus.ALLOWED) ? true : false), + type); + } + + public Ace getAce(long aceEntityId) + { + return getAceEntity(aceEntityId); + } + + public Ace getOrCreateAce(Permission permission, Authority authority, ACEType type, AccessStatus accessStatus) + { + Ace entity = getAce(permission, authority, type, accessStatus); + if (entity == null) + { + entity = createAce(permission, authority, type, accessStatus); + } + return entity; + } + + public List getAcesByAuthority(long authorityId) + { + return (List)getAceEntitiesByAuthority(authorityId); + } + + public List> getAcesAndAuthoritiesByAcl(long idOfAcl) + { + return getAceAndAuthorityEntitiesByAcl(idOfAcl); + } + + public int deleteAces(List aceIds) + { + int totalDeletedCount = 0; + + if (aceIds.size() == 0) + { + return 0; + } + else if (aceIds.size() <= batchSize) + { + totalDeletedCount = deleteAceEntities(aceIds); + } + else + { + Iterator idIterator = aceIds.iterator(); + List batchIds = new ArrayList(batchSize); + + while (idIterator.hasNext()) + { + Long id = idIterator.next(); + batchIds.add(id); + + if (batchIds.size() == batchSize || (! idIterator.hasNext())) + { + int batchDeletedCount = deleteAceEntities(batchIds); + + totalDeletedCount = totalDeletedCount + batchDeletedCount; + batchIds.clear(); + } + } + } + + return totalDeletedCount; + } + + protected abstract long createAceEntity(AceEntity entity); + protected abstract AceEntity getAceEntity(long aceEntityId); + protected abstract AceEntity getAceEntity(long permissionId, long authorityId, boolean allowed, ACEType type); + protected abstract List getAceEntitiesByAuthority(long authorityId); + protected abstract List> getAceAndAuthorityEntitiesByAcl(long idOfAcl); + protected abstract int deleteAceEntities(List aceIds); + + // + // Permission + // + + public Permission createPermission(PermissionReference permissionReference) + { + ParameterCheck.mandatory("permissionReference", permissionReference); + + PermissionEntity entity = null; + + // Get the persistent ID for the QName + Pair qnamePair = qnameDAO.getOrCreateQName(permissionReference.getQName()); + if (qnamePair != null) + { + Long qnameId = qnamePair.getFirst(); + entity = new PermissionEntity(qnameId, permissionReference.getName()); + + entity.setVersion(0L); + + Pair entityPair = permissionCache.getOrCreateByValue(entity); + entity = entityPair.getSecond(); + } + return entity; + } + + public Permission getPermission(long id) + { + Pair entityPair = permissionCache.getByKey(id); + if (entityPair == null) + { + return null; + } + return entityPair.getSecond(); + } + + public Permission getPermission(PermissionReference permissionReference) + { + return getPermissionImpl(permissionReference); + } + + private PermissionEntity getPermissionImpl(PermissionReference permissionReference) + { + ParameterCheck.mandatory("permissionReference", permissionReference); + + PermissionEntity entity = null; + + // Get the persistent ID for the QName + Pair qnamePair = qnameDAO.getOrCreateQName(permissionReference.getQName()); + if (qnamePair != null) + { + Long qnameId = qnamePair.getFirst(); + + PermissionEntity permission = new PermissionEntity(qnameId, permissionReference.getName()); + Pair entityPair = permissionCache.getByValue(permission); + if (entityPair != null) + { + entity = entityPair.getSecond(); + } + } + + return entity; + } + + private PermissionEntity getPermissionForUpdate(PermissionReference permissionReference) + { + PermissionEntity perm = getPermissionImpl(permissionReference); + + PermissionEntity newPerm = new PermissionEntity(); + newPerm.setId(perm.getId()); + newPerm.setVersion(perm.getVersion()); + newPerm.setTypeQNameId(perm.getTypeQNameId()); + newPerm.setName(perm.getName()); + + return newPerm; + } + + public Permission getOrCreatePermission(PermissionReference permissionReference) + { + Permission entity = getPermission(permissionReference); + if (entity == null) + { + entity = createPermission(permissionReference); + } + return entity; + } + + public void renamePermission(QName oldTypeQName, String oldName, QName newTypeQName, String newName) + { + ParameterCheck.mandatory("oldTypeQName", oldTypeQName); + ParameterCheck.mandatory("oldName", oldName); + ParameterCheck.mandatory("newTypeQName", newTypeQName); + ParameterCheck.mandatory("newName", newName); + + if (oldTypeQName.equals(newTypeQName) && oldName.equals(newName)) + { + throw new IllegalArgumentException("Cannot move permission to itself: " + oldTypeQName + "-" + oldName); + } + + SimplePermissionReference oldPermRef = SimplePermissionReference.getPermissionReference(oldTypeQName, oldName); + PermissionEntity permission = getPermissionForUpdate(oldPermRef); + if (permission != null) + { + Long newTypeQNameId = qnameDAO.getOrCreateQName(newTypeQName).getFirst(); + permission.setTypeQNameId(newTypeQNameId); + permission.setName(newName); + + int updated = permissionCache.updateValue(permission.getId(), permission); + if (updated < 1) + { + throw new ConcurrencyFailureException("PermissionEntity with ID (" + permission.getId() + ") no longer exists or has been updated concurrently"); + } + } + } + + public void deletePermission(long id) + { + Pair entityPair = permissionCache.getByKey(id); + if (entityPair == null) + { + return; + } + + int deleted = permissionCache.deleteByKey(id); + if (deleted < 1) + { + throw new ConcurrencyFailureException("PermissionEntity with ID " + id + " no longer exists"); + } + } + + /** + * Callback for alf_permission DAO + */ + private class PermissionEntityCallbackDAO implements EntityLookupCallbackDAO + { + private final Pair convertEntityToPair(PermissionEntity entity) + { + if (entity == null) + { + return null; + } + else + { + return new Pair(entity.getId(), entity); + } + } + + public PermissionEntity getValueKey(PermissionEntity value) + { + return value; + } + + public Pair createValue(PermissionEntity value) + { + PermissionEntity entity = createPermissionEntity(value); + return convertEntityToPair(entity); + } + + public Pair findByKey(Long key) + { + PermissionEntity entity = getPermissionEntity(key); + return convertEntityToPair(entity); + } + + public Pair findByValue(PermissionEntity value) + { + if ((value == null) || (value.getName() == null) || (value.getTypeQNameId() == null)) + { + throw new AlfrescoRuntimeException("Unexpected: PermissionEntity / name / qnameId must not be null"); + } + return convertEntityToPair(getPermissionEntity(value.getTypeQNameId(), value.getName())); + } + + public int updateValue(Long key, PermissionEntity value) + { + return updatePermissionEntity(value); + } + + public int deleteByKey(Long key) + { + return deletePermissionEntity(key); + } + + public int deleteByValue(PermissionEntity value) + { + throw new UnsupportedOperationException("deleteByValue"); + } + } + + protected abstract PermissionEntity createPermissionEntity(PermissionEntity entity); + protected abstract PermissionEntity getPermissionEntity(long id); + protected abstract PermissionEntity getPermissionEntity(long qnameId, String name); + protected abstract int updatePermissionEntity(PermissionEntity updateEntity); + protected abstract int deletePermissionEntity(long id); + + // + // Authority + // + + public Authority createAuthority(String authorityName) + { + ParameterCheck.mandatory("authorityName", authorityName); + + AuthorityEntity entity = new AuthorityEntity(); + entity.setAuthority(authorityName); + entity.setCrc(CrcHelper.getStringCrcPair(authorityName, 32, true, true).getSecond()); + + entity.setVersion(0L); + + Pair entityPair = authorityCache.getOrCreateByValue(entity); + return entityPair.getSecond(); + } + + public Authority getAuthority(long id) + { + Pair entityPair = authorityCache.getByKey(id); + if (entityPair == null) + { + return null; + } + return entityPair.getSecond(); + } + + public Authority getAuthority(String authorityName) + { + return getAuthorityImpl(authorityName); + } + + private AuthorityEntity getAuthorityImpl(String authorityName) + { + ParameterCheck.mandatory("authorityName", authorityName); + + AuthorityEntity authority = new AuthorityEntity(); + authority.setAuthority(authorityName); + + Pair entityPair = authorityCache.getByValue(authority); + if (entityPair == null) + { + return null; + } + return entityPair.getSecond(); + } + + private AuthorityEntity getAuthorityForUpdate(String authorityName) + { + AuthorityEntity auth = getAuthorityImpl(authorityName); + + if (auth == null) + { + return null; + } + + AuthorityEntity newAuth = new AuthorityEntity(); + newAuth.setId(auth.getId()); + newAuth.setVersion(auth.getVersion()); + newAuth.setAuthority(auth.getAuthority()); + newAuth.setCrc(auth.getCrc()); + return newAuth; + } + + public Authority getOrCreateAuthority(String name) + { + Authority entity = getAuthority(name); + + if (entity == null) + { + entity = createAuthority(name); + } + + return entity; + } + + public void renameAuthority(String before, String after) + { + ParameterCheck.mandatory("before", before); + ParameterCheck.mandatory("after", after); + + AuthorityEntity entity = getAuthorityForUpdate(before); + + if (entity != null) + { + entity.setAuthority(after); + entity.setCrc(CrcHelper.getStringCrcPair(after, 32, true, true).getSecond()); + + int updated = authorityCache.updateValue(entity.getId(), entity); + if (updated < 1) + { + throw new ConcurrencyFailureException("AuthorityEntity with ID (" + entity.getId() + ") no longer exists or has been updated concurrently"); + } + } + } + + public void deleteAuthority(long id) + { + Pair entityPair = authorityCache.getByKey(id); + if (entityPair == null) + { + return; + } + + int deleted = authorityCache.deleteByKey(id); + if (deleted < 1) + { + throw new ConcurrencyFailureException("AuthorityEntity with ID " + id + " no longer exists"); + } + } + + /** + * Callback for alf_authority DAO + */ + private class AuthorityEntityCallbackDAO implements EntityLookupCallbackDAO + { + private final Pair convertEntityToPair(AuthorityEntity entity) + { + if (entity == null) + { + return null; + } + else + { + return new Pair(entity.getId(), entity); + } + } + + public String getValueKey(AuthorityEntity value) + { + return value.getAuthority(); + } + + public Pair createValue(AuthorityEntity value) + { + AuthorityEntity entity = createAuthorityEntity(value); + return convertEntityToPair(entity); + } + + public Pair findByKey(Long key) + { + AuthorityEntity entity = getAuthorityEntity(key); + return convertEntityToPair(entity); + } + + public Pair findByValue(AuthorityEntity value) + { + if ((value == null) || (value.getAuthority() == null)) + { + throw new AlfrescoRuntimeException("Unexpected: AuthorityEntity / name must not be null"); + } + return convertEntityToPair(getAuthorityEntity(value.getAuthority())); + } + + public int updateValue(Long key, AuthorityEntity value) + { + return updateAuthorityEntity(value); + } + + public int deleteByKey(Long key) + { + return deleteAuthorityEntity(key); + } + + public int deleteByValue(AuthorityEntity value) + { + throw new UnsupportedOperationException("deleteByValue"); + } + } + + protected abstract AuthorityEntity createAuthorityEntity(AuthorityEntity entity); + protected abstract AuthorityEntity getAuthorityEntity(long id); + protected abstract AuthorityEntity getAuthorityEntity(String authorityName); + protected abstract int updateAuthorityEntity(AuthorityEntity updateEntity); + protected abstract int deleteAuthorityEntity(long id); + + // ACE Context (NOTE: currently unused - intended for possible future enhancement) + + protected abstract long createAceContextEntity(AceContextEntity entity); + protected abstract AceContextEntity getAceContextEntity(long aceContextId); + protected abstract int deleteAceContextEntity(long aceContextId); + + + // + // Authority Alias (NOTE: currently unused - intended for possible future enhancement) + // + + protected abstract long createAuthorityAliasEntity(AuthorityAliasEntity entity); + protected abstract int deleteAuthorityAliasEntity(long id); +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/permissions/AbstractPermissionsDaoComponentImpl.java similarity index 89% rename from source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java rename to source/java/org/alfresco/repo/domain/permissions/AbstractPermissionsDaoComponentImpl.java index a4f4f4b364..a5d9a31a0b 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java +++ b/source/java/org/alfresco/repo/domain/permissions/AbstractPermissionsDaoComponentImpl.java @@ -1,27 +1,34 @@ /* * Copyright (C) 2005-2010 Alfresco Software Limited. * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" */ -package org.alfresco.repo.domain.hibernate; +package org.alfresco.repo.domain.permissions; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; import org.alfresco.repo.domain.AccessControlListDAO; import org.alfresco.repo.domain.DbAccessControlList; @@ -36,36 +43,35 @@ import org.alfresco.repo.security.permissions.PermissionReference; import org.alfresco.repo.security.permissions.SimpleAccessControlEntry; import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties; import org.alfresco.repo.security.permissions.impl.AclChange; -import org.alfresco.repo.security.permissions.impl.AclDaoComponent; 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.transaction.TransactionalDao; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.util.GUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** - * Common support for permissions DAO + * Common support for permisisons dao * * Sub classes determine how ACLs are cascaded to children and how changes may COW/version children as ACLs are pushed down. * - * TODO: remove the protocol to DAO mapping + * TODO: remove the protocol to dao mapping * * @author andyh * */ -public abstract class AbstractPermissionsDaoComponentImpl implements PermissionsDaoComponent, TransactionalDao +public abstract class AbstractPermissionsDaoComponentImpl implements PermissionsDaoComponent { private static Log logger = LogFactory.getLog(AbstractPermissionsDaoComponentImpl.class); protected static final boolean INHERIT_PERMISSIONS_DEFAULT = true; - protected AclDaoComponent aclDaoComponent; + protected AclDAO aclDaoComponent; private Map fProtocolToACLDAO; @@ -79,20 +85,11 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions this.uuid = GUID.generate(); } - /** - * Get the ACL DAO component - * @return - the acl dao component - */ - public AclDaoComponent getAclDaoComponent() - { - return aclDaoComponent; - } - /** * Set the ACL DAO component * @param aclDaoComponent */ - public void setAclDaoComponent(AclDaoComponent aclDaoComponent) + public void setAclDAO(AclDAO aclDaoComponent) { this.aclDaoComponent = aclDaoComponent; } @@ -122,32 +119,6 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions return uuid.hashCode(); } - /** - * Does this Session contain any changes which must be synchronized with the store? - * - * @return true => changes are pending - */ - public boolean isDirty() - { - return aclDaoComponent.isDirty(); - } - - /** - * Just flushes the session - */ - public void flush() - { - aclDaoComponent.flush(); - } - - /** - * NO-OP - */ - public void beforeCommit() - { - aclDaoComponent.beforeCommit(); - } - /** * Set the mapping of protocol to DAO * @param map @@ -252,6 +223,15 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions return npe; } + public Map> getAllSetPermissions(final String authority) + { + throw new UnsupportedOperationException(); + } + + public Set findNodeByPermission(final String authority, final PermissionReference permission, final boolean allow) + { + throw new UnsupportedOperationException(); + } // Utility methods to create simple detached objects for the outside world // We do not pass out the hibernate objects @@ -333,13 +313,11 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions } } - @SuppressWarnings("unchecked") public void deletePermissions(String authority) { @SuppressWarnings("unused") List changes = aclDaoComponent.deleteAccessControlEntries(authority); - // ignore changes - deleting an authority does not casue all acls to version - + // ignore changes - deleting an authority does not cause all acls to version } public void deletePermissions(NodeRef nodeRef, final String authority) @@ -557,11 +535,10 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions { SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); properties.setAclType(ACLType.DEFINING); - properties.setVersioned(false); properties.setInherits(false); - // Accept default versioning - Long id = aclDaoComponent.createAccessControlList(properties); - acl = aclDaoComponent.getDbAccessControlList(id); + properties.setVersioned(false); + + acl = aclDaoComponent.createDbAccessControlList(properties); getACLDAO(storeRef).setAccessControlList(storeRef, acl); } return acl; diff --git a/source/java/org/alfresco/repo/domain/permissions/Ace.java b/source/java/org/alfresco/repo/domain/permissions/Ace.java new file mode 100644 index 0000000000..d5db6b3d5e --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/Ace.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + +import org.alfresco.repo.security.permissions.ACEType; + + +/** + * Entity for alf_access_control_entry persistence. + * + * @author janv + * @since 3.4 + */ +public interface Ace +{ + public Long getId(); + public Long getPermissionId(); + public Long getAuthorityId(); + public boolean isAllowed(); + public Integer getApplies(); + public Long getContextId(); + public ACEType getAceType(); +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AceContext.java b/source/java/org/alfresco/repo/domain/permissions/AceContext.java new file mode 100644 index 0000000000..a2911d397e --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AceContext.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + + +/** + * Entity for alf_ace_context persistence. + * + * @author janv + * @since 3.4 + */ +public interface AceContext +{ + public Long getId(); + public String getClassContext(); + public String getPropertyContext(); + public String getKvpContext(); +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AceContextEntity.java b/source/java/org/alfresco/repo/domain/permissions/AceContextEntity.java new file mode 100644 index 0000000000..f5339d0eab --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AceContextEntity.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + + +/** + * Entity for alf_ace_context persistence. + * + * @author janv + * @since 3.4 + */ +public class AceContextEntity implements AceContext +{ + private Long id; + private Long version; + private String classContext; + private String propertyContext; + private String kvpContext; + + /** + * Default constructor + */ + public AceContextEntity() + { + } + + public AceContextEntity(String classContext, String propertyContext, String kvpContext) + { + this.classContext = classContext; + this.propertyContext = propertyContext; + this.kvpContext = kvpContext; + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + public String getClassContext() + { + return classContext; + } + + public void setClassContext(String classContext) + { + this.classContext = classContext; + } + + public String getPropertyContext() + { + return propertyContext; + } + + public void setPropertyContext(String propertyContext) + { + this.propertyContext = propertyContext; + } + + public String getKvpContext() + { + return kvpContext; + } + + public void setKvpContext(String kvpContext) + { + this.kvpContext = kvpContext; + } + + @Override + public int hashCode() + { + final int PRIME = 31; + int result = 1; + result = PRIME * result + ((classContext == null) ? 0 : classContext.hashCode()); + result = PRIME * result + ((kvpContext == null) ? 0 : kvpContext.hashCode()); + result = PRIME * result + ((propertyContext == null) ? 0 : propertyContext.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + + if (obj == null) + { + return false; + } + + if (getClass() != obj.getClass()) + { + return false; + } + + final AceContextEntity other = (AceContextEntity) obj; + if (classContext == null) + { + if (other.classContext != null) + return false; + } + else if (!classContext.equals(other.classContext)) + { + return false; + } + + if (kvpContext == null) + { + if (other.kvpContext != null) + { + return false; + } + } + else if (!kvpContext.equals(other.kvpContext)) + { + return false; + } + + if (propertyContext == null) + { + if (other.propertyContext != null) + { + return false; + } + } + else if (!propertyContext.equals(other.propertyContext)) + { + return false; + } + + return true; + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("AceContextEntity") + .append("[ ID=").append(id) + .append(", version=").append(version) + .append(", classContext=").append(classContext) + .append(", propertyContext=").append(propertyContext) + .append(", kvpContext=").append(kvpContext) + .append("]"); + return sb.toString(); + } +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AceEntity.java b/source/java/org/alfresco/repo/domain/permissions/AceEntity.java new file mode 100644 index 0000000000..a23379fede --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AceEntity.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + +import org.alfresco.repo.security.permissions.ACEType; +import org.alfresco.util.EqualsHelper; + + +/** + * Entity for alf_access_control_entry persistence. + * + * @author janv + * @since 3.4 + */ +public class AceEntity implements Ace +{ + private Long id; + private Long version; + private Long permissionId; + private Long authorityId; + private boolean allowed; + private Integer applies; + private Long contextId; + + /** + * Default constructor + */ + public AceEntity() + { + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + public Long getPermissionId() + { + return permissionId; + } + + public void setPermissionId(Long permissionId) + { + this.permissionId = permissionId; + } + + public Long getAuthorityId() + { + return authorityId; + } + + public void setAuthorityId(Long authorityId) + { + this.authorityId = authorityId; + } + + public boolean isAllowed() + { + return allowed; + } + + public void setAllowed(boolean allowed) + { + this.allowed = allowed; + } + + public Integer getApplies() + { + return applies; + } + + public void setApplies(Integer applies) + { + this.applies = applies; + } + + public Long getContextId() + { + return contextId; + } + + public void setContextId(Long contextId) + { + this.contextId = contextId; + } + + public ACEType getAceType() + { + return ACEType.getACETypeFromId(getApplies()); + } + + public void setAceType(ACEType aceType) + { + setApplies(aceType.getId()); + } + + @Override + public int hashCode() + { + return (id == null ? 0 : id.hashCode()); + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + else if (obj instanceof AceEntity) + { + AceEntity that = (AceEntity)obj; + return (EqualsHelper.nullSafeEquals(this.id, that.id)); + } + else + { + return false; + } + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("AceEntity") + .append("[ ID=").append(id) + .append(", version=").append(version) + .append(", permissionId=").append(permissionId) + .append(", authorityId=").append(authorityId) + .append(", isAllowed=").append(allowed) + .append(", applies=").append(applies) + .append(", contextId=").append(contextId) + .append("]"); + return sb.toString(); + } +} diff --git a/source/java/org/alfresco/repo/domain/permissions/Acl.java b/source/java/org/alfresco/repo/domain/permissions/Acl.java new file mode 100644 index 0000000000..0cf3da17ca --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/Acl.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + +import org.alfresco.repo.security.permissions.ACLType; +import org.alfresco.repo.security.permissions.AccessControlListProperties; + + +/** + * Entity for alf_access_control_list persistence. + * + * @author janv + * @since 3.4 + */ +public interface Acl extends AccessControlListProperties +{ + /** + * Get the long key + * @return + */ + public Long getId(); + + /** + * Get the ACL ID + * @return + */ + public String getAclId(); + + /** + * Get the ACL version + * @return + */ + public Long getAclVersion(); + + /** + * Is this the latest version of the acl identified by the acl id string? + * @return + */ + public Boolean isLatest(); + + /** + * Get inheritance behaviour + * @return Returns the inheritance status of this list + */ + public Boolean getInherits(); + + /** + * Get the ACL from which this one inherits + * + * @return + */ + public Long getInheritsFrom(); + + /** + * Get the type for this ACL + * + * @return + */ + public ACLType getAclType(); + + /** + * Get the ACL inherited from nodes which have this ACL + * + * @return + */ + public Long getInheritedAcl(); + + /** + * Is this ACL versioned - if not there will be no old versions of the ACL + * and the long id will remain unchanged. + * + * If an acl is versioned it can not be updated - a new copy has to be created, + * + * @return + */ + public Boolean isVersioned(); + + public Boolean getRequiresVersion(); + + public Long getAclChangeSetId(); +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AclChangeSet.java b/source/java/org/alfresco/repo/domain/permissions/AclChangeSet.java new file mode 100644 index 0000000000..ae2ba8d0f4 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AclChangeSet.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + + +/** + * Entity for alf_acl_change_set persistence. + * + * @author janv + * @since 3.4 + */ +public interface AclChangeSet +{ + public Long getId(); +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AclChangeSetEntity.java b/source/java/org/alfresco/repo/domain/permissions/AclChangeSetEntity.java new file mode 100644 index 0000000000..ac6e645ab5 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AclChangeSetEntity.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + +import org.alfresco.util.EqualsHelper; + + +/** + * Entity for alf_acl_change_set persistence. + * + * @author janv + * @since 3.4 + */ +public class AclChangeSetEntity implements AclChangeSet +{ + private Long id; + private Long version; + + /** + * Default constructor + */ + public AclChangeSetEntity() + { + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + @Override + public int hashCode() + { + return (id == null ? 0 : id.hashCode()); + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + else if (obj instanceof AclChangeSetEntity) + { + AclChangeSetEntity that = (AclChangeSetEntity)obj; + return (EqualsHelper.nullSafeEquals(this.id, that.id)); + } + else + { + return false; + } + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("AclChangeSetEntity") + .append("[ ID=").append(id) + .append(", version=").append(version) + .append("]"); + return sb.toString(); + } +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AclCrudDAO.java b/source/java/org/alfresco/repo/domain/permissions/AclCrudDAO.java new file mode 100644 index 0000000000..802c6602cc --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AclCrudDAO.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + +import java.util.List; +import java.util.Map; + +import org.alfresco.repo.security.permissions.ACEType; +import org.alfresco.repo.security.permissions.PermissionReference; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; + +/** + * This provides basic services such as caching, but defers to the underlying implementation + * for CRUD operations. + * + * alf_access_control_list + * alf_acl_member + * alf_acl_change_set + * alf_access_control_entry + * alf_ace_context + * alf_permission + * alf_authority + * alf_authority_alias + * + * @since 3.4 + * @author janv + */ +public interface AclCrudDAO +{ + // + // Access Control List (ACL) + // + + public Acl createAcl(AclEntity entity); + public Acl getAcl(long aclEntityId); + public AclEntity getAclForUpdate(long aclEntityId); + public List getAclsThatInheritFromAcl(long aclEntityId); + public Long getLatestAclByGuid(String aclGuid); + public void updateAcl(AclEntity entity); + public void deleteAcl(long aclEntityId); + public List getADMNodesByAcl(long aclEntityId, int maxResults); + public List getAVMNodesByAcl(long aclEntityId, int maxResults); + // + // Access Control Entry (ACE) + // + + public Ace createAce(Permission permission, Authority authority, ACEType type, AccessStatus accessStatus); + public Ace getAce(Permission permission, Authority authority, ACEType type, AccessStatus accessStatus); + public Ace getAce(long aceEntityId); + public Ace getOrCreateAce(Permission permission, Authority authority, ACEType type, AccessStatus accessStatus); + public List getAcesByAuthority(long authorityEntityId); + public List> getAcesAndAuthoritiesByAcl(long aclEntityId); + public int deleteAces(List aceEntityIds); + + // + // ACL Change Set + // + + public long createAclChangeSet(); + public AclChangeSet getAclChangeSet(long aclChangeSetEntityId); + public void deleteAclChangeSet(long aclChangeSetEntityId); + + // + // ACL Member + // + + public void addAclMembersToAcl(long aclId, List aceIds, int depth); + public void addAclMembersToAcl(long aclId, List> aceIdsWithDepths); + public List getAclMembersByAcl(long aclEntityId); + public List getAclMembersByAclForUpdate(long aclEntityId); + public List getAclMembersByAuthority(String authorityName); + public void updateAclMember(AclMemberEntity entity); + public int deleteAclMembers(List aclMemberIds); + public int deleteAclMembersByAcl(long aclEntityId); + + // + // Permission + // + + public Permission createPermission(PermissionReference permissionReference); + public Permission getPermission(long permissionEntityId); + public Permission getPermission(PermissionReference permissionReference); + public Permission getOrCreatePermission(PermissionReference permissionReference); + public void renamePermission(QName oldTypeQName, String oldName, QName newTypeQName, String newName); + public void deletePermission(long permissionEntityId); + + // + // Authority + // + + public Authority getAuthority(long authorityEntityId); + public Authority getAuthority(String authorityName); + public Authority getOrCreateAuthority(String authorityName); + public void renameAuthority(String authorityNameBefore, String authorityAfter); + public void deleteAuthority(long authorityEntityId); + + // AceContext (NOTE: currently unused - intended for possible future enhancement) + // AuthorityAlias (NOTE: currently unused - intended for possible future enhancement) +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AclCrudDAOTest.java b/source/java/org/alfresco/repo/domain/permissions/AclCrudDAOTest.java new file mode 100644 index 0000000000..41bab9eafc --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AclCrudDAOTest.java @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.alfresco.repo.security.permissions.PermissionReference; +import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.springframework.context.ApplicationContext; + +/** + * @see AclCrudDAO + * + * @author janv + * @since 3.4 + */ +public class AclCrudDAOTest extends TestCase +{ + private ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + + private TransactionService transactionService; + private RetryingTransactionHelper txnHelper; + private AclCrudDAO aclCrudDAO; + + @Override + public void setUp() throws Exception + { + ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); + transactionService = serviceRegistry.getTransactionService(); + txnHelper = transactionService.getRetryingTransactionHelper(); + + aclCrudDAO = (AclCrudDAO)ctx.getBean("aclCrudDAO"); + } + + // TODO - alf_access_control_list, alf_acl_member, alf_access_control_entry + + // + // alf_acl_change_set + // + + private long createAclChangeSet() throws Exception + { + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Long execute() throws Throwable + { + return aclCrudDAO.createAclChangeSet(); + } + }; + return txnHelper.doInTransaction(callback); + } + + private void deleteAclChangeSet(final long aclChangeSetId) throws Exception + { + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + aclCrudDAO.deleteAclChangeSet(aclChangeSetId); + return null; + } + }; + txnHelper.doInTransaction(callback); + } + + private AclChangeSet getAclChangeSet(final long aclChangeSetId) throws Exception + { + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public AclChangeSet execute() throws Throwable + { + return aclCrudDAO.getAclChangeSet(aclChangeSetId); + } + }; + return txnHelper.doInTransaction(callback); + } + + public void testCreateAndDeleteAclChangeSet() throws Exception + { + long aclChangeSetId = createAclChangeSet(); + + AclChangeSet acsEntity= getAclChangeSet(aclChangeSetId); + assertNotNull(acsEntity); + assertEquals(new Long(aclChangeSetId), acsEntity.getId()); + + deleteAclChangeSet(aclChangeSetId); + + assertNull(getAclChangeSet(aclChangeSetId)); + } + + public void testCreateAclChangeSetWithRollback() throws Exception + { + final List tmp = new ArrayList(1); + + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + long acsEntityId = createAclChangeSet(); + tmp.add(acsEntityId); + + // Now force a rollback + throw new RuntimeException("Forced"); + } + }; + + try + { + txnHelper.doInTransaction(callback); + fail("Transaction didn't roll back"); + } + catch (RuntimeException e) + { + // Expected + } + + assertEquals(1, tmp.size()); + + // Check that it doesn't exist + assertNull(getAclChangeSet(tmp.get(0))); + } + + // + // alf_authority + // + + private Authority createAuth(final String authName) throws Exception + { + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Authority execute() throws Throwable + { + return aclCrudDAO.getOrCreateAuthority(authName); + } + }; + return txnHelper.doInTransaction(callback); + } + + private void deleteAuth(final long authId) throws Exception + { + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + aclCrudDAO.deleteAuthority(authId); + return null; + } + }; + txnHelper.doInTransaction(callback); + } + + private void updateAuth(final String before, final String after) throws Exception + { + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + aclCrudDAO.renameAuthority(before, after); + return null; + } + }; + txnHelper.doInTransaction(callback); + } + + private Authority getAuth(final String authName) throws Exception + { + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Authority execute() throws Throwable + { + return aclCrudDAO.getAuthority(authName); + } + }; + return txnHelper.doInTransaction(callback); + } + + public void testCreateUpdateAndDeleteAuth() throws Exception + { + final String authName = getName() + "-" + System.currentTimeMillis(); + + Authority authEntity= getAuth(authName); + assertNull(authEntity); + + Authority createAuthEntity = createAuth(authName); + assertNotNull(createAuthEntity); + + authEntity= getAuth(authName); + assertEquals(createAuthEntity, authEntity); + + String newAuthName = authName+"-new"; + updateAuth(authName, newAuthName); + + assertNull(getAuth(authName)); + + authEntity = getAuth(newAuthName); + assertNotNull(authEntity); + assertEquals(createAuthEntity.getId(), authEntity.getId()); + assertEquals(newAuthName, authEntity.getAuthority()); + + deleteAuth(authEntity.getId()); + + assertNull(getAuth(newAuthName)); + } + + public void testCreateAuthWithRollback() throws Exception + { + final String authName = getName() + "-" + System.currentTimeMillis(); + + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + createAuth(authName); + // Now force a rollback + throw new RuntimeException("Forced"); + } + }; + + try + { + txnHelper.doInTransaction(callback); + fail("Transaction didn't roll back"); + } + catch (RuntimeException e) + { + // Expected + } + + // Check that it doesn't exist + assertNull(getAuth(authName)); + } + + // + // alf_permission + // + + private Permission createPermission(final PermissionReference permissionReference) throws Exception + { + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Permission execute() throws Throwable + { + return aclCrudDAO.getOrCreatePermission(permissionReference); + } + }; + return txnHelper.doInTransaction(callback); + } + + private void deletePermission(final long permissionId) throws Exception + { + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + aclCrudDAO.deletePermission(permissionId); + return null; + } + }; + txnHelper.doInTransaction(callback); + } + + private Permission getPermission(final PermissionReference permissionReference) throws Exception + { + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Permission execute() throws Throwable + { + return aclCrudDAO.getPermission(permissionReference); + } + }; + return txnHelper.doInTransaction(callback); + } + + public void testCreateAndDeletePermission() throws Exception + { + String name = getName() + "-" + System.currentTimeMillis(); + final SimplePermissionReference permRef = SimplePermissionReference.getPermissionReference(QName.createQName("cm:cmobject"), name); + + Permission createdPermEntity = createPermission(permRef); + assertNotNull(createdPermEntity); + + Permission permEntity = getPermission(permRef); + assertEquals(createdPermEntity, permEntity); + + deletePermission(permEntity.getId()); + + assertNull(getPermission(permRef)); + } + + public void testCreatePermissionWithRollback() throws Exception + { + String name = getName() + "-" + System.currentTimeMillis(); + final SimplePermissionReference permRef = SimplePermissionReference.getPermissionReference(QName.createQName("cm:cmobject"), name); + + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + createPermission(permRef); + // Now force a rollback + throw new RuntimeException("Forced"); + } + }; + + try + { + txnHelper.doInTransaction(callback); + fail("Transaction didn't roll back"); + } + catch (RuntimeException e) + { + // Expected + } + + // Check that it doesn't exist + assertNull(getPermission(permRef)); + } +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AclDAO.java b/source/java/org/alfresco/repo/domain/permissions/AclDAO.java new file mode 100644 index 0000000000..3838babd7a --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AclDAO.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + +import java.util.List; + +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.security.permissions.ACLCopyMode; +import org.alfresco.repo.security.permissions.AccessControlEntry; +import org.alfresco.repo.security.permissions.AccessControlList; +import org.alfresco.repo.security.permissions.AccessControlListProperties; +import org.alfresco.repo.security.permissions.impl.AclChange; + +/** + * Provides data access support for persistence in alf_access_control_list. + * + * @since 3.4 + * @author Andy Hind, janv + */ +public interface AclDAO +{ + /** + * Get an ACL (including entries) + */ + public AccessControlList getAccessControlList(Long id); + + /** + * Get an ACL + */ + public Acl getAcl(Long id); + + /** + * Get an ACL + */ + public DbAccessControlList getDbAccessControlList(Long id); + + /** + * Delete an ACL + * + * @return - the id of all ACLs affected + */ + public List deleteAccessControlList(Long id); + + /** + * Delete the ACEs in position 0 (those set directly on the ACL and not inherited) Cleans up existing acls + * + * @return - the id of all ACLs affected + */ + public List deleteLocalAccessControlEntries(Long id); + + /** + * Delete the ACEs in position > 0 (those not set directly on the ACL but inherited) No affect on any other acl + * + * @return - the id of all ACLs affected + */ + public List deleteInheritedAccessControlEntries(Long id); + + /** + * Delete all ACEs that reference this authority as no longer valid. THIS DOES NOT CAUSE ANY ACL TO VERSION + * Used when deleting a user. No ACL is updated - the user has gone the aces and all related info is deleted. + * + * @return - the id of all ACLs affected + */ + public List deleteAccessControlEntries(String authority); + + /** + * Delete some locally set ACLs according to the pattern + * + * @param pattern - + * non null elements are used for the match + * @return - the id of all ACLs affected + */ + public List deleteAccessControlEntries(Long id, AccessControlEntry pattern); + + /** + * Add an access control entry + */ + public List setAccessControlEntry(Long id, AccessControlEntry ace); + + /** + * Enable inheritance + */ + public List enableInheritance(Long id, Long parent); + + /** + * Disable inheritance + */ + public List disableInheritance(Long id, boolean setInheritedOnAcl); + + /** + * Get the ACL properties + * + * @return - the id of all ACLs affected + */ + public AccessControlListProperties getAccessControlListProperties(Long id); + + /** + * Create a new ACL with default properties + * + * @see #getDefaultProperties() + * @see #createAccessControlList(AccessControlListProperties) + */ + public Long createAccessControlList(); + + /** + * Get the default ACL properties + * + * @return the default properties + */ + public AccessControlListProperties getDefaultProperties(); + + /** + * Create a new ACL with the given properties. Unset properties are assigned defaults. + * + * @return ID of AccessControlList + */ + public Long createAccessControlList(AccessControlListProperties properties); + + public DbAccessControlList createDbAccessControlList(AccessControlListProperties properties); + + /** + * @see #createAccessControlList(AccessControlListProperties) + * @return Acl + */ + public Acl createAcl(AccessControlListProperties properties); + + /** + * @see #createAccessControlList(AccessControlListProperties) + * @return Acl + */ + public Acl createAcl(AccessControlListProperties properties, List aces, Long inherited); + + /** + * Get the id of the ACL inherited from the one given + * May return null if there is nothing to inherit -> OLD world where nodes have their own ACL and we walk the parent chain + */ + public Long getInheritedAccessControlList(Long id); + + /** + * Merge inherited ACEs in to target - the merged ACEs will go in at their current position +1 + */ + public List mergeInheritedAccessControlList(Long inherited, Long target); + + public DbAccessControlList getDbAccessControlListCopy(Long toCopy, Long toInheritFrom, ACLCopyMode mode); + + public List getAVMNodesByAcl(long aclEntityId, int maxResults); + + public List getADMNodesByAcl(long aclEntityId, int maxResults); + + public DbAccessControlList createLayeredAcl(Long indirectedAcl); + + public void renameAuthority(String before, String after); + + public void deleteAclForNode(long aclId, boolean isAVMNode); +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AclDAOImpl.java b/source/java/org/alfresco/repo/domain/permissions/AclDAOImpl.java new file mode 100644 index 0000000000..79dd20b897 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AclDAOImpl.java @@ -0,0 +1,1789 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.domain.qname.QNameDAO; +import org.alfresco.repo.security.permissions.ACEType; +import org.alfresco.repo.security.permissions.ACLCopyMode; +import org.alfresco.repo.security.permissions.ACLType; +import org.alfresco.repo.security.permissions.AccessControlEntry; +import org.alfresco.repo.security.permissions.AccessControlList; +import org.alfresco.repo.security.permissions.AccessControlListProperties; +import org.alfresco.repo.security.permissions.SimpleAccessControlEntry; +import org.alfresco.repo.security.permissions.SimpleAccessControlList; +import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties; +import org.alfresco.repo.security.permissions.impl.AclChange; +import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.AuthorityType; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.GUID; +import org.alfresco.util.Pair; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * DAO to manage ACL persistence + * + * Note: based on earlier AclDaoComponentImpl + * + * @author Andy Hind, janv + * @since 3.4 + */ +public class AclDAOImpl implements AclDAO +{ + private static Log logger = LogFactory.getLog(AclDAOImpl.class); + + /** Access to QName entities */ + private QNameDAO qnameDAO; + + /** Access to ACL entities */ + private AclCrudDAO aclCrudDAO; + + /** a transactionally-safe cache to be injected */ + private SimpleCache aclCache; + + private enum WriteMode + { + /** + * Remove inherited ACEs after that set + */ + TRUNCATE_INHERITED, + /** + * Add inherited ACEs + */ + ADD_INHERITED, + /** + * The source of inherited ACEs is changing + */ + CHANGE_INHERITED, + /** + * Remove all inherited ACEs + */ + REMOVE_INHERITED, + /** + * Insert inherited ACEs + */ + INSERT_INHERITED, + /** + * Copy ACLs and update ACEs and inheritance + */ + COPY_UPDATE_AND_INHERIT, + /** + * Simple copy + */ + COPY_ONLY, CREATE_AND_INHERIT; + } + + public void setQnameDAO(QNameDAO qnameDAO) + { + this.qnameDAO = qnameDAO; + } + + public void setAclCrudDAO(AclCrudDAO aclCrudDAO) + { + this.aclCrudDAO = aclCrudDAO; + } + + /** + * Set the ACL cache + * + * @param aclCache + */ + public void setAclCache(SimpleCache aclCache) + { + this.aclCache = aclCache; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#createAccessControlList() + */ + public Long createAccessControlList() + { + return createAccessControlList(getDefaultProperties()); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#getDefaultProperties() + */ + public AccessControlListProperties getDefaultProperties() + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + properties.setInherits(true); + properties.setVersioned(false); + return properties; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#createAccessControlList(org.alfresco.repo.security.permissions.AccessControlListProperties) + */ + public Long createAccessControlList(AccessControlListProperties properties) + { + return createAcl(properties).getId(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#createDbAccessControlList(org.alfresco.repo.security.permissions.AccessControlListProperties) + */ + public DbAccessControlList createDbAccessControlList(AccessControlListProperties properties) + { + return (DbAccessControlList)createAcl(properties); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#createAcl(org.alfresco.repo.security.permissions.AccessControlListProperties) + */ + public Acl createAcl(AccessControlListProperties properties) + { + if (properties == null) + { + throw new IllegalArgumentException("Properties cannot be null"); + } + + if (properties.getAclType() == null) + { + throw new IllegalArgumentException("ACL Type must be defined"); + } + switch (properties.getAclType()) + { + case OLD: + if (properties.isVersioned() == Boolean.TRUE) + { + throw new IllegalArgumentException("Old acls can not be versioned"); + } + break; + case SHARED: + throw new IllegalArgumentException("Can not create shared acls direct - use get inherited"); + case DEFINING: + case LAYERED: + break; + case FIXED: + if (properties.getInherits() == Boolean.TRUE) + { + throw new IllegalArgumentException("Fixed ACLs can not inherit"); + } + case GLOBAL: + if (properties.getInherits() == Boolean.TRUE) + { + throw new IllegalArgumentException("Fixed ACLs can not inherit"); + } + default: + break; + } + return createAcl(properties, null, null); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#createAcl(org.alfresco.repo.security.permissions.AccessControlListProperties, java.util.List, java.lang.Long) + */ + public Acl createAcl(AccessControlListProperties properties, List aces, Long inherited) + { + if (properties == null) + { + throw new IllegalArgumentException("Properties cannot be null"); + } + + AclEntity acl = new AclEntity(); + if (properties.getAclId() != null) + { + acl.setAclId(properties.getAclId()); + } + else + { + acl.setAclId(GUID.generate()); + } + acl.setAclType(properties.getAclType()); + acl.setAclVersion(Long.valueOf(1l)); + + switch (properties.getAclType()) + { + case FIXED: + case GLOBAL: + acl.setInherits(Boolean.FALSE); + case OLD: + case SHARED: + case DEFINING: + case LAYERED: + default: + if (properties.getInherits() != null) + { + acl.setInherits(properties.getInherits()); + } + else + { + acl.setInherits(Boolean.TRUE); + } + break; + } + acl.setLatest(Boolean.TRUE); + + switch (properties.getAclType()) + { + case OLD: + acl.setVersioned(Boolean.FALSE); + break; + case LAYERED: + if (properties.isVersioned() != null) + { + acl.setVersioned(properties.isVersioned()); + } + else + { + acl.setVersioned(Boolean.TRUE); + } + break; + case FIXED: + case GLOBAL: + case SHARED: + case DEFINING: + default: + if (properties.isVersioned() != null) + { + acl.setVersioned(properties.isVersioned()); + } + else + { + acl.setVersioned(Boolean.FALSE); + } + break; + } + + acl.setAclChangeSetId(getCurrentChangeSetId()); + acl.setRequiresVersion(false); + + Acl createdAcl = (AclEntity)aclCrudDAO.createAcl(acl); + long created = createdAcl.getId(); + + if ((aces != null) && aces.size() > 0) + { + List changes = new ArrayList(); + + List toAdd = new ArrayList(aces.size()); + List excluded = new ArrayList(aces.size()); + for (AccessControlEntry ace : aces) + { + if ((ace.getPosition() != null) && (ace.getPosition() != 0)) + { + throw new IllegalArgumentException("Invalid position"); + } + + // Find authority + Authority authority = aclCrudDAO.getOrCreateAuthority(ace.getAuthority()); + Permission permission = aclCrudDAO.getOrCreatePermission(ace.getPermission()); + + // Find context + if (ace.getContext() != null) + { + throw new UnsupportedOperationException(); + } + + // Find ACE + Ace entry = aclCrudDAO.getOrCreateAce(permission, authority, ace.getAceType(), ace.getAccessStatus()); + + // Wire up + // COW and remove any existing matches + + SimpleAccessControlEntry exclude = new SimpleAccessControlEntry(); + // match any access status + exclude.setAceType(ace.getAceType()); + exclude.setAuthority(ace.getAuthority()); + exclude.setPermission(ace.getPermission()); + exclude.setPosition(0); + + toAdd.add(entry); + excluded.add(exclude); + // Will remove from the cache + } + Long toInherit = null; + if (inherited != null) + { + toInherit = getInheritedAccessControlList(inherited); + } + getWritable(created, toInherit, excluded, toAdd, toInherit, false, changes, WriteMode.CREATE_AND_INHERIT); + } + + return createdAcl; + } + + private void getWritable(final Long id, final Long parent, List exclude, List toAdd, Long inheritsFrom, boolean cascade, + List changes, WriteMode mode) + { + List inherited = null; + List positions = null; + + if ((mode == WriteMode.ADD_INHERITED) || (mode == WriteMode.INSERT_INHERITED) || (mode == WriteMode.CHANGE_INHERITED)) + { + inherited = new ArrayList(); + positions = new ArrayList(); + + // get aces for acl (via acl member) + List members = aclCrudDAO.getAclMembersByAcl(parent); + + for (AclMember member : members) + { + Ace aceEntity = aclCrudDAO.getAce(member.getAceId()); + + if ((mode == WriteMode.INSERT_INHERITED) && (member.getPos() == 0)) + { + inherited.add(aceEntity); + positions.add(member.getPos()); + } + else + { + inherited.add(aceEntity); + positions.add(member.getPos()); + } + } + } + + getWritable(id, parent, exclude, toAdd, inheritsFrom, inherited, positions, cascade, 0, changes, mode, false); + } + + /** + * Make a whole tree of ACLs copy on write if required Includes adding and removing ACEs which can be optimised + * slightly for copy on write (no need to add and then remove) + * + * @param id + * @param parent + * @param exclude + * @param toAdd + * @param inheritsFrom + * @param cascade + * @param depth + * @param changes + */ + private void getWritable(final Long id, final Long parent, List exclude, List toAdd, Long inheritsFrom, + List inherited, List positions, boolean cascade, int depth, List changes, WriteMode mode, boolean requiresVersion) + { + AclChange current = getWritable(id, parent, exclude, toAdd, inheritsFrom, inherited, positions, depth, mode, requiresVersion); + changes.add(current); + + boolean cascadeVersion = requiresVersion; + if (!cascadeVersion) + { + cascadeVersion = !current.getBefore().equals(current.getAfter()); + } + + if (cascade) + { + List inheritors = aclCrudDAO.getAclsThatInheritFromAcl(id); + for (Long nextId : inheritors) + { + // Check for those that inherit themselves to other nodes ... + if (nextId != id) + { + getWritable(nextId, current.getAfter(), exclude, toAdd, current.getAfter(), inherited, positions, cascade, depth + 1, changes, mode, cascadeVersion); + } + } + } + } + + /** + * COW for an individual ACL + * + * @param id + * @param parent + * @param exclude + * @param toAdd + * @param inheritsFrom + * @param depth + * @return - an AclChange + */ + private AclChange getWritable(final Long id, final Long parent, List exclude, List acesToAdd, Long inheritsFrom, + List inherited, List positions, int depth, WriteMode mode, boolean requiresVersion) + { + AclEntity acl = (AclEntity)aclCrudDAO.getAcl(id); + if (!acl.isLatest()) + { + aclCache.remove(id); + return new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType()); + } + + List toAdd = new ArrayList(0); + if (acesToAdd != null) + { + for (Ace ace : acesToAdd) + { + toAdd.add(ace.getId()); + } + } + + if (!acl.isVersioned()) + { + switch (mode) + { + case COPY_UPDATE_AND_INHERIT: + removeAcesFromAcl(id, exclude, depth); + aclCrudDAO.addAclMembersToAcl(acl.getId(), toAdd, depth); + break; + case CHANGE_INHERITED: + replaceInherited(id, acl, inherited, positions, depth); + break; + case ADD_INHERITED: + addInherited(acl, inherited, positions, depth); + break; + case TRUNCATE_INHERITED: + truncateInherited(id, depth); + break; + case INSERT_INHERITED: + insertInherited(id, acl, inherited, positions, depth); + break; + case REMOVE_INHERITED: + removeInherited(id, depth); + break; + case CREATE_AND_INHERIT: + aclCrudDAO.addAclMembersToAcl(acl.getId(), toAdd, depth); + addInherited(acl, inherited, positions, depth); + case COPY_ONLY: + default: + break; + } + if (inheritsFrom != null) + { + acl.setInheritsFrom(inheritsFrom); + aclCrudDAO.updateAcl(acl); + } + aclCache.remove(id); + return new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType()); + } + else if ((acl.getAclChangeSetId() == getCurrentChangeSetId()) && (!requiresVersion) && (!acl.getRequiresVersion())) + { + switch (mode) + { + case COPY_UPDATE_AND_INHERIT: + removeAcesFromAcl(id, exclude, depth); + aclCrudDAO.addAclMembersToAcl(acl.getId(), toAdd, depth); + break; + case CHANGE_INHERITED: + replaceInherited(id, acl, inherited, positions, depth); + break; + case ADD_INHERITED: + addInherited(acl, inherited, positions, depth); + break; + case TRUNCATE_INHERITED: + truncateInherited(id, depth); + break; + case INSERT_INHERITED: + insertInherited(id, acl, inherited, positions, depth); + break; + case REMOVE_INHERITED: + removeInherited(id, depth); + break; + case CREATE_AND_INHERIT: + aclCrudDAO.addAclMembersToAcl(acl.getId(), toAdd, depth); + addInherited(acl, inherited, positions, depth); + case COPY_ONLY: + default: + break; + } + if (inheritsFrom != null) + { + acl.setInheritsFrom(inheritsFrom); + aclCrudDAO.updateAcl(acl); + } + aclCache.remove(id); + return new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType()); + } + else + { + AclEntity newAcl = new AclEntity(); + newAcl.setAclChangeSetId(getCurrentChangeSetId()); + newAcl.setAclId(acl.getAclId()); + newAcl.setAclType(acl.getAclType()); + newAcl.setAclVersion(acl.getAclVersion() + 1); + newAcl.setInheritedAcl(-1l); + newAcl.setInherits(acl.getInherits()); + newAcl.setInheritsFrom((inheritsFrom != null) ? inheritsFrom : acl.getInheritsFrom()); + newAcl.setLatest(Boolean.TRUE); + newAcl.setVersioned(Boolean.TRUE); + newAcl.setRequiresVersion(Boolean.FALSE); + + AclEntity createdAcl = (AclEntity)aclCrudDAO.createAcl(newAcl); + long created = createdAcl.getId(); + + // Create new membership entries - excluding those in the given pattern + + // AcePatternMatcher excluder = new AcePatternMatcher(exclude); + + // get aces for acl (via acl member) + List members = aclCrudDAO.getAclMembersByAcl(id); + + if (members.size() > 0) + { + List> aceIdsWithDepths = new ArrayList>(members.size()); + + for (AclMember member : members) + { + aceIdsWithDepths.add(new Pair(member.getAceId(), member.getPos())); + } + + // copy acl members to new acl + aclCrudDAO.addAclMembersToAcl(newAcl.getId(), aceIdsWithDepths); + } + + // add new + + switch (mode) + { + case COPY_UPDATE_AND_INHERIT: + // Done above + removeAcesFromAcl(newAcl.getId(), exclude, depth); + aclCrudDAO.addAclMembersToAcl(newAcl.getId(), toAdd, depth); + break; + case CHANGE_INHERITED: + replaceInherited(newAcl.getId(), newAcl, inherited, positions, depth); + break; + case ADD_INHERITED: + addInherited(newAcl, inherited, positions, depth); + break; + case TRUNCATE_INHERITED: + truncateInherited(newAcl.getId(), depth); + break; + case INSERT_INHERITED: + insertInherited(newAcl.getId(), newAcl, inherited, positions, depth); + break; + case REMOVE_INHERITED: + removeInherited(newAcl.getId(), depth); + break; + case CREATE_AND_INHERIT: + aclCrudDAO.addAclMembersToAcl(acl.getId(), toAdd, depth); + addInherited(acl, inherited, positions, depth); + case COPY_ONLY: + default: + break; + } + + // Fix up inherited ACL if required + if (newAcl.getAclType() == ACLType.SHARED) + { + if (parent != null) + { + Long writableParentAcl = getWritable(parent, null, null, null, null, null, null, 0, WriteMode.COPY_ONLY, false).getAfter(); + AclEntity parentAcl = aclCrudDAO.getAclForUpdate(writableParentAcl); + parentAcl.setInheritedAcl(created); + aclCrudDAO.updateAcl(parentAcl); + } + } + + // fix up old version + acl.setLatest(Boolean.FALSE); + acl.setRequiresVersion(Boolean.FALSE); + aclCrudDAO.updateAcl(acl); + aclCache.remove(id); + return new AclChangeImpl(id, created, acl.getAclType(), newAcl.getAclType()); + } + } + + /** + * Helper to remove ACEs from an ACL + * + * @param id + * @param exclude + * @param depth + */ + private void removeAcesFromAcl(final Long id, final List exclude, final int depth) + { + if (exclude == null) + { + // cascade delete all acl members - no exclusion + aclCrudDAO.deleteAclMembersByAcl(id); + } + else + { + AcePatternMatcher excluder = new AcePatternMatcher(exclude); + + List> results = aclCrudDAO.getAcesAndAuthoritiesByAcl(id); + List memberIds = new ArrayList(results.size()); + + for (Map result : results) + { + Long result_aclmemId = (Long) result.get("aclmemId"); + + if ((exclude != null) && excluder.matches(aclCrudDAO, result, depth)) + { + memberIds.add(result_aclmemId); + } + } + + // delete list of acl members + aclCrudDAO.deleteAclMembers(memberIds); + } + } + + private void replaceInherited(Long id, Acl acl, List inherited, List positions, int depth) + { + truncateInherited(id, depth); + addInherited(acl, inherited, positions, depth); + } + + private void truncateInherited(final Long id, int depth) + { + List members = aclCrudDAO.getAclMembersByAcl(id); + + List membersToDelete = new ArrayList(members.size()); + for (AclMember member : members) + { + if (member.getPos() > depth) + { + membersToDelete.add(member.getId()); + } + } + + if (membersToDelete.size() > 0) + { + // delete list of acl members + aclCrudDAO.deleteAclMembers(membersToDelete); + } + } + + private void removeInherited(final Long id, int depth) + { + List members = aclCrudDAO.getAclMembersByAclForUpdate(id); + + List membersToDelete = new ArrayList(members.size()); + for (AclMemberEntity member : members) + { + if (member.getPos() == depth + 1) + { + membersToDelete.add(member.getId()); + } + else if (member.getPos() > (depth + 1)) + { + member.setPos(member.getPos() - 1); + aclCrudDAO.updateAclMember(member); + } + } + + if (membersToDelete.size() > 0) + { + // delete list of acl members + aclCrudDAO.deleteAclMembers(membersToDelete); + } + } + + private void addInherited(Acl acl, List inherited, List positions, int depth) + { + if ((inherited != null) && (inherited.size() > 0)) + { + List> aceIdsWithDepths = new ArrayList>(inherited.size()); + for (int i = 0; i < inherited.size(); i++) + { + Ace add = inherited.get(i); + Integer position = positions.get(i); + aceIdsWithDepths.add(new Pair(add.getId(), position.intValue() + depth + 1)); + } + aclCrudDAO.addAclMembersToAcl(acl.getId(), aceIdsWithDepths); + } + } + + private void insertInherited(final Long id, AclEntity acl, List inherited, List positions, int depth) + { + // get aces for acl (via acl member) + List members = aclCrudDAO.getAclMembersByAclForUpdate(id); + + for (AclMemberEntity member : members) + { + if (member.getPos() > depth) + { + member.setPos(member.getPos() + 1); + aclCrudDAO.updateAclMember(member); + } + } + + addInherited(acl, inherited, positions, depth); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#deleteAccessControlEntries(java.lang.String) + */ + public List deleteAccessControlEntries(final String authority) + { + List acls = new ArrayList(); + + // get authority + Authority authEntity = aclCrudDAO.getAuthority(authority); + if (authEntity == null) + { + return acls; + } + + List aces = new ArrayList(); + + List members = aclCrudDAO.getAclMembersByAuthority(authority); + + if (members.size() > 0) + { + List membersToDelete = new ArrayList(members.size()); + + // fix up members and extract acls and aces + for (AclMember member : members) + { + // Delete acl entry + Long aclMemberId = member.getId(); + Long aclId = member.getAclId(); + Long aceId = member.getAceId(); + + aclCache.remove(aclId); + Acl list = aclCrudDAO.getAcl(aclId); + acls.add(new AclChangeImpl(aclId, aclId, list.getAclType(), list.getAclType())); + membersToDelete.add(aclMemberId); + aces.add((Long)aceId); + } + + // delete list of acl members + aclCrudDAO.deleteAclMembers(membersToDelete); + } + + // remove ACEs + aclCrudDAO.deleteAces(aces); + + // Tidy up any unreferenced ACEs + + // get aces by authority + List unreferenced = aclCrudDAO.getAcesByAuthority(authEntity.getId()); + + if (unreferenced.size() > 0) + { + List unrefencedAcesToDelete = new ArrayList(unreferenced.size()); + for (Ace ace : unreferenced) + { + unrefencedAcesToDelete.add(ace.getId()); + } + aclCrudDAO.deleteAces(unrefencedAcesToDelete); + } + + // remove authority + if (authEntity != null) + { + aclCrudDAO.deleteAuthority(authEntity.getId()); + } + + return acls; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#deleteAclForNode(long, boolean) + */ + public void deleteAclForNode(long aclId, boolean isAVMNode) + { + Acl dbAcl = getAcl(aclId); + if (dbAcl.getAclType() == ACLType.DEFINING) + { + // delete acl members & acl + aclCrudDAO.deleteAclMembersByAcl(aclId); + aclCrudDAO.deleteAcl(aclId); + + aclCache.remove(aclId); + } + if (dbAcl.getAclType() == ACLType.SHARED) + { + // check unused + Long defining = dbAcl.getInheritsFrom(); + if (aclCrudDAO.getAcl(defining) == null) + { + if (! isAVMNode) + { + // ADM + if (getADMNodesByAcl(aclId, 1).size() == 0) + { + // delete acl members & acl + aclCrudDAO.deleteAclMembersByAcl(aclId); + aclCrudDAO.deleteAcl(aclId); + + aclCache.remove(aclId); + } + } + else + { + // TODO: AVM + } + } + } + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#deleteAccessControlList(java.lang.Long) + */ + public List deleteAccessControlList(final Long id) + { + if (logger.isDebugEnabled()) + { + // debug only + int maxForDebug = 11; + List nodeIds = getADMNodesByAcl(id, maxForDebug); + + for (Long nodeId : nodeIds) + { + logger.debug("deleteAccessControlList: Found nodeId=" + nodeId + ", aclId=" + id); + } + } + + List acls = new ArrayList(); + + final AclEntity acl = aclCrudDAO.getAclForUpdate(id); + if (!acl.isLatest()) + { + throw new UnsupportedOperationException("Old ACL versions can not be updated"); + } + if (acl.getAclType() == ACLType.SHARED) + { + throw new UnsupportedOperationException("Delete is not supported for shared acls - they are deleted with the defining acl"); + } + + if ((acl.getAclType() == ACLType.DEFINING) || (acl.getAclType() == ACLType.LAYERED)) + { + if ((acl.getInheritedAcl() != null) && (acl.getInheritedAcl() != -1)) + { + final Acl inherited = aclCrudDAO.getAcl(acl.getInheritedAcl()); + + // Will remove from the cache + getWritable(inherited.getId(), acl.getInheritsFrom(), null, null, null, true, acls, WriteMode.REMOVE_INHERITED); + Acl unusedInherited = null; + for (AclChange change : acls) + { + if (change.getBefore() == inherited.getId()) + { + unusedInherited = aclCrudDAO.getAcl(change.getAfter()); + } + } + + final Long newId = unusedInherited.getId(); + List inheritors = aclCrudDAO.getAclsThatInheritFromAcl(newId); + for (Long nextId : inheritors) + { + // Will remove from the cache + getWritable(nextId, acl.getInheritsFrom(), null, null, acl.getInheritsFrom(), true, acls, WriteMode.REMOVE_INHERITED); + } + + // delete acl members + aclCrudDAO.deleteAclMembersByAcl(newId); + + // delete 'unusedInherited' acl + aclCrudDAO.deleteAcl(unusedInherited.getId()); + + if (inherited.isVersioned()) + { + AclEntity inheritedForUpdate = aclCrudDAO.getAclForUpdate(inherited.getId()); + if (inheritedForUpdate != null) + { + inheritedForUpdate.setLatest(Boolean.FALSE); + aclCrudDAO.updateAcl(inheritedForUpdate); + } + } + else + { + // delete 'inherited' acl + aclCrudDAO.deleteAcl(inherited.getId()); + } + } + } + else + { + List inheritors = aclCrudDAO.getAclsThatInheritFromAcl(id); + for (Long nextId : inheritors) + { + // Will remove from the cache + getWritable(nextId, acl.getInheritsFrom(), null, null, null, true, acls, WriteMode.REMOVE_INHERITED); + } + } + + // delete + if (acl.isVersioned()) + { + acl.setLatest(Boolean.FALSE); + aclCrudDAO.updateAcl(acl); + } + else + { + // delete acl members & acl + aclCrudDAO.deleteAclMembersByAcl(id); + aclCrudDAO.deleteAcl(acl.getId()); + } + + // remove the deleted acl from the cache + aclCache.remove(id); + acls.add(new AclChangeImpl(id, null, acl.getAclType(), null)); + return acls; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#deleteLocalAccessControlEntries(java.lang.Long) + */ + public List deleteLocalAccessControlEntries(Long id) + { + List changes = new ArrayList(); + SimpleAccessControlEntry pattern = new SimpleAccessControlEntry(); + pattern.setPosition(Integer.valueOf(0)); + // Will remove from the cache + getWritable(id, null, Collections.singletonList(pattern), null, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT); + return changes; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#deleteInheritedAccessControlEntries(java.lang.Long) + */ + public List deleteInheritedAccessControlEntries(Long id) + { + List changes = new ArrayList(); + SimpleAccessControlEntry pattern = new SimpleAccessControlEntry(); + pattern.setPosition(Integer.valueOf(-1)); + // Will remove from the cache + getWritable(id, null, Collections.singletonList(pattern), null, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT); + return changes; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#deleteAccessControlEntries(java.lang.Long, org.alfresco.repo.security.permissions.AccessControlEntry) + */ + public List deleteAccessControlEntries(Long id, AccessControlEntry pattern) + { + List changes = new ArrayList(); + // Will remove from the cache + getWritable(id, null, Collections.singletonList(pattern), null, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT); + return changes; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#getDbAccessControlList(java.lang.Long) + */ + public Acl getAcl(Long id) + { + return aclCrudDAO.getAcl(id); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#getDbAccessControlList(java.lang.Long) + */ + public DbAccessControlList getDbAccessControlList(Long id) + { + return (DbAccessControlList)getAcl(id); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#getAccessControlList(java.lang.Long) + */ + public AccessControlList getAccessControlList(Long id) + { + AccessControlList acl = aclCache.get(id); + if (acl == null) + { + acl = getAccessControlListImpl(id); + aclCache.put(id, acl); + } + else + { + // System.out.println("Used cache for "+id); + } + return acl; + } + + /** + * @param id + * @return the access control list + */ + public AccessControlList getAccessControlListImpl(final Long id) + { + SimpleAccessControlList acl = new SimpleAccessControlList(); + AccessControlListProperties properties = getAccessControlListProperties(id); + if (properties == null) + { + return null; + } + + acl.setProperties(properties); + + List> results = aclCrudDAO.getAcesAndAuthoritiesByAcl(id); + + List entries = new ArrayList(results.size()); + for (Map result : results) + // for (AclMemberEntity member : members) + { + Boolean aceIsAllowed = (Boolean) result.get("allowed"); + Integer aceType = (Integer) result.get("applies"); + String authority = (String) result.get("authority"); + Long permissionId = (Long) result.get("permissionId"); + Integer position = (Integer) result.get("pos"); + //Long result_aclmemId = (Long) result.get("aclmemId"); // not used here + + SimpleAccessControlEntry sacEntry = new SimpleAccessControlEntry(); + sacEntry.setAccessStatus(aceIsAllowed ? AccessStatus.ALLOWED : AccessStatus.DENIED); + sacEntry.setAceType(ACEType.getACETypeFromId(aceType)); + sacEntry.setAuthority(authority); + // if (entry.getContext() != null) + // { + // SimpleAccessControlEntryContext context = new SimpleAccessControlEntryContext(); + // context.setClassContext(entry.getContext().getClassContext()); + // context.setKVPContext(entry.getContext().getKvpContext()); + // context.setPropertyContext(entry.getContext().getPropertyContext()); + // sacEntry.setContext(context); + // } + Permission perm = aclCrudDAO.getPermission(permissionId); + QName permTypeQName = qnameDAO.getQName(perm.getTypeQNameId()).getSecond(); // Has an ID so must exist + SimplePermissionReference permissionRefernce = SimplePermissionReference.getPermissionReference(permTypeQName, perm.getName()); + sacEntry.setPermission(permissionRefernce); + sacEntry.setPosition(position); + entries.add(sacEntry); + } + + Collections.sort(entries); + acl.setEntries(entries); + + return acl; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#getAccessControlListProperties(java.lang.Long) + */ + public AccessControlListProperties getAccessControlListProperties(Long id) + { + return aclCrudDAO.getAcl(id); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#getInheritedAccessControlList(java.lang.Long) + */ + public Long getInheritedAccessControlList(Long id) + { + AclEntity acl = aclCrudDAO.getAclForUpdate(id); + if (acl.getAclType() == ACLType.OLD) + { + return null; + } + if ((acl.getInheritedAcl() != null) && (acl.getInheritedAcl() != -1)) + { + return acl.getInheritedAcl(); + } + + Long inheritedAclId = null; + + if ((acl.getAclType() == ACLType.DEFINING) || (acl.getAclType() == ACLType.LAYERED)) + { + List changes = new ArrayList(); + // created shared acl + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.SHARED); + properties.setInherits(Boolean.TRUE); + properties.setVersioned(acl.isVersioned()); + Long sharedId = createAcl(properties, null, null).getId(); + getWritable(sharedId, id, null, null, id, true, changes, WriteMode.ADD_INHERITED); + acl.setInheritedAcl(sharedId); + inheritedAclId = sharedId; + } + else + { + acl.setInheritedAcl(acl.getId()); + inheritedAclId = acl.getId(); + } + + aclCrudDAO.updateAcl(acl); + return inheritedAclId; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#mergeInheritedAccessControlList(java.lang.Long, java.lang.Long) + */ + public List mergeInheritedAccessControlList(Long inherited, Long target) + { + // TODO: For now we do a replace - we could do an insert if both inherit from the same acl + + List changes = new ArrayList(); + + Acl targetAcl = aclCrudDAO.getAcl(target); + + Acl inheritedAcl = null; + if (inherited != null) + { + inheritedAcl = aclCrudDAO.getAcl(inherited); + } + else + { + // Assume we are just resetting it to inherit as before + if (targetAcl.getInheritsFrom() != null) + { + inheritedAcl = aclCrudDAO.getAcl(targetAcl.getInheritsFrom()); + if (inheritedAcl == null) + { + // TODO: Try previous versions + throw new IllegalStateException("No old inheritance definition to use"); + } + else + { + // find the latest version of the acl + if (!inheritedAcl.isLatest()) + { + final String searchAclId = inheritedAcl.getAclId(); + + Long actualInheritor = (Long)aclCrudDAO.getLatestAclByGuid(searchAclId); + + inheritedAcl = aclCrudDAO.getAcl(actualInheritor); + if (inheritedAcl == null) + { + // TODO: Try previous versions + throw new IllegalStateException("No ACL found"); + } + } + } + } + else + { + // There is no inheritance to set + return changes; + } + } + + // recursion test + // if inherited already inherits from the target + + Acl test = inheritedAcl; + while (test != null) + { + if (test.getId() == target) + { + throw new IllegalStateException("Cyclical ACL detected"); + } + Long parent = test.getInheritsFrom(); + if ((parent == null) || (parent == -1l)) + { + test = null; + } + else + { + test = aclCrudDAO.getAcl(test.getInheritsFrom()); + } + } + + if ((targetAcl.getAclType() != ACLType.DEFINING) && (targetAcl.getAclType() != ACLType.LAYERED)) + { + throw new IllegalArgumentException("Only defining ACLs can have their inheritance set"); + } + + if (!targetAcl.getInherits()) + { + return changes; + } + + Long actualInheritedId = inheritedAcl.getId(); + + if ((inheritedAcl.getAclType() == ACLType.DEFINING) || (inheritedAcl.getAclType() == ACLType.LAYERED)) + { + actualInheritedId = getInheritedAccessControlList(actualInheritedId); + } + // Will remove from the cache + getWritable(target, actualInheritedId, null, null, actualInheritedId, true, changes, WriteMode.CHANGE_INHERITED); + + return changes; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#setAccessControlEntry(java.lang.Long, org.alfresco.repo.security.permissions.AccessControlEntry) + */ + public List setAccessControlEntry(final Long id, final AccessControlEntry ace) + { + Acl target = aclCrudDAO.getAcl(id); + if (target.getAclType() == ACLType.SHARED) + { + throw new IllegalArgumentException("Shared ACLs are immutable"); + } + + List changes = new ArrayList(); + + if ((ace.getPosition() != null) && (ace.getPosition() != 0)) + { + throw new IllegalArgumentException("Invalid position"); + } + + // Find authority + Authority authority = aclCrudDAO.getOrCreateAuthority(ace.getAuthority()); + Permission permission = aclCrudDAO.getOrCreatePermission(ace.getPermission()); + + // Find context + if (ace.getContext() != null) + { + throw new UnsupportedOperationException(); + } + + // Find ACE + Ace entry = aclCrudDAO.getOrCreateAce(permission, authority, ace.getAceType(), ace.getAccessStatus()); + + // Wire up + // COW and remove any existing matches + + SimpleAccessControlEntry exclude = new SimpleAccessControlEntry(); + // match any access status + exclude.setAceType(ace.getAceType()); + exclude.setAuthority(ace.getAuthority()); + exclude.setPermission(ace.getPermission()); + exclude.setPosition(0); + List toAdd = new ArrayList(1); + toAdd.add(entry); + // Will remove from the cache + getWritable(id, null, Collections.singletonList(exclude), toAdd, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT); + + return changes; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#enableInheritance(java.lang.Long, java.lang.Long) + */ + public List enableInheritance(Long id, Long parent) + { + List changes = new ArrayList(); + + AclEntity acl = aclCrudDAO.getAclForUpdate(id); + + switch (acl.getAclType()) + { + case FIXED: + case GLOBAL: + throw new IllegalArgumentException("Fixed and global permissions can not inherit"); + case OLD: + acl.setInherits(Boolean.TRUE); + aclCrudDAO.updateAcl(acl); + aclCache.remove(id); + changes.add(new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType())); + return changes; + case SHARED: + // TODO support a list of children and casacade if given + throw new IllegalArgumentException( + "Shared acls should be replace by creating a definig ACL, wiring it up for inhertitance, and then applying inheritance to any children. It can not be done by magic "); + case DEFINING: + case LAYERED: + default: + if (!acl.getInherits()) + { + // Will remove from the cache + getWritable(id, null, null, null, null, false, changes, WriteMode.COPY_ONLY); + acl = aclCrudDAO.getAclForUpdate(changes.get(0).getAfter()); + acl.setInherits(Boolean.TRUE); + aclCrudDAO.updateAcl(acl); + } + else + { + // Will remove from the cache + getWritable(id, null, null, null, null, false, changes, WriteMode.COPY_ONLY); + } + + List merged = mergeInheritedAccessControlList(parent, changes.get(0).getAfter()); + changes.addAll(merged); + return changes; + } + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#disableInheritance(java.lang.Long, boolean) + */ + public List disableInheritance(Long id, boolean setInheritedOnAcl) + { + AclEntity acl = aclCrudDAO.getAclForUpdate(id); + List changes = new ArrayList(1); + switch (acl.getAclType()) + { + case FIXED: + case GLOBAL: + return Collections. singletonList(new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType())); + case OLD: + acl.setInherits(Boolean.FALSE); + aclCrudDAO.updateAcl(acl); + aclCache.remove(id); + changes.add(new AclChangeImpl(id, id, acl.getAclType(), acl.getAclType())); + return changes; + case SHARED: + // TODO support a list of children and casacade if given + throw new IllegalArgumentException("Shared ACL must inherit"); + case DEFINING: + case LAYERED: + default: + return disableInheritanceImpl(id, setInheritedOnAcl, acl); + } + } + + private Long getCopy(Long toCopy, Long toInheritFrom, ACLCopyMode mode) + { + AclEntity aclToCopy; + Long inheritedId; + Acl aclToInheritFrom; + switch (mode) + { + case INHERIT: + if (toCopy.equals(toInheritFrom)) + { + return getInheritedAccessControlList(toCopy); + } + else + { + throw new UnsupportedOperationException(); + } + case COW: + aclToCopy = aclCrudDAO.getAclForUpdate(toCopy); + aclToCopy.setRequiresVersion(true); + aclCrudDAO.updateAcl(aclToCopy); + aclCache.remove(toCopy); + inheritedId = getInheritedAccessControlList(toCopy); + if ((inheritedId != null) && (!inheritedId.equals(toCopy))) + { + AclEntity inheritedAcl = aclCrudDAO.getAclForUpdate(inheritedId); + inheritedAcl.setRequiresVersion(true); + aclCrudDAO.updateAcl(inheritedAcl); + aclCache.remove(inheritedId); + } + return toCopy; + case REDIRECT: + if ((toInheritFrom != null) && (toInheritFrom == toCopy)) + { + return getInheritedAccessControlList(toInheritFrom); + } + aclToCopy = aclCrudDAO.getAclForUpdate(toCopy); + aclToInheritFrom = null; + if (toInheritFrom != null) + { + aclToInheritFrom = aclCrudDAO.getAcl(toInheritFrom); + } + + switch (aclToCopy.getAclType()) + { + case DEFINING: + // This is not called on the redirecting node as only LAYERED change permissions when redirected + // So this needs to make a copy in the same way layered does + case LAYERED: + if (toInheritFrom == null) + { + return toCopy; + } + // manages cache clearing beneath + List changes = mergeInheritedAccessControlList(toInheritFrom, toCopy); + for (AclChange change : changes) + { + if (change.getBefore().equals(toCopy)) + { + return change.getAfter(); + } + } + throw new UnsupportedOperationException(); + case SHARED: + if (aclToInheritFrom != null) + { + return getInheritedAccessControlList(toInheritFrom); + } + else + { + throw new UnsupportedOperationException(); + } + case FIXED: + case GLOBAL: + case OLD: + return toCopy; + default: + throw new UnsupportedOperationException(); + } + case COPY: + aclToCopy = aclCrudDAO.getAclForUpdate(toCopy); + aclToInheritFrom = null; + if (toInheritFrom != null) + { + aclToInheritFrom = aclCrudDAO.getAcl(toInheritFrom); + } + + switch (aclToCopy.getAclType()) + { + case DEFINING: + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + properties.setInherits(aclToCopy.getInherits()); + properties.setVersioned(true); + + Long id = createAccessControlList(properties); + + AccessControlList indirectAcl = getAccessControlList(toCopy); + for (AccessControlEntry entry : indirectAcl.getEntries()) + { + if (entry.getPosition() == 0) + { + setAccessControlEntry(id, entry); + } + } + if (aclToInheritFrom != null) + { + mergeInheritedAccessControlList(toInheritFrom, id); + } + return id; + case SHARED: + if (aclToInheritFrom != null) + { + return getInheritedAccessControlList(toInheritFrom); + } + else + { + return null; + } + case FIXED: + case GLOBAL: + case LAYERED: + case OLD: + return toCopy; + default: + throw new UnsupportedOperationException(); + } + default: + throw new UnsupportedOperationException(); + } + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#getDbAccessControlListCopy(java.lang.Long, java.lang.Long, org.alfresco.repo.security.permissions.ACLCopyMode) + */ + public DbAccessControlList getDbAccessControlListCopy(Long toCopy, Long toInheritFrom, ACLCopyMode mode) + { + return (DbAccessControlList)getAclEntityCopy(toCopy, toInheritFrom, mode); + } + + private Acl getAclEntityCopy(Long toCopy, Long toInheritFrom, ACLCopyMode mode) + { + Long id = getCopy(toCopy, toInheritFrom, mode); + if (id == null) + { + return null; + } + return aclCrudDAO.getAcl(id); + } + + public List getAVMNodesByAcl(long aclEntityId, int maxResults) + { + return aclCrudDAO.getAVMNodesByAcl(aclEntityId, maxResults); + } + + public List getADMNodesByAcl(long aclEntityId, int maxResults) + { + return aclCrudDAO.getADMNodesByAcl(aclEntityId, maxResults); + } + + public DbAccessControlList createLayeredAcl(Long indirectedAcl) + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.LAYERED); + + DbAccessControlList acl = createDbAccessControlList(properties); + long id = acl.getId(); + + if (indirectedAcl != null) + { + mergeInheritedAccessControlList(indirectedAcl, id); + } + return acl; + } + + private List disableInheritanceImpl(Long id, boolean setInheritedOnAcl, AclEntity acl) + { + List changes = new ArrayList(); + + if (!acl.getInherits()) + { + return Collections. emptyList(); + } + + // Manages caching + getWritable(id, null, null, null, null, false, changes, WriteMode.COPY_ONLY); + acl = aclCrudDAO.getAclForUpdate(changes.get(0).getAfter()); + final Long inheritsFrom = acl.getInheritsFrom(); + acl.setInherits(Boolean.FALSE); + aclCrudDAO.updateAcl(acl); + + // Keep inherits from so we can reinstate if required + // acl.setInheritsFrom(-1l); + + // Manages caching + getWritable(acl.getId(), null, null, null, null, true, changes, WriteMode.TRUNCATE_INHERITED); + + // set Inherited - TODO: UNTESTED + + if ((inheritsFrom != null) && (inheritsFrom != -1) && setInheritedOnAcl) + { + // get aces for acl (via acl member) + List members = aclCrudDAO.getAclMembersByAcl(inheritsFrom); + + for (AclMember member : members) + { + // TODO optimise + Ace ace = aclCrudDAO.getAce(member.getAceId()); + Authority authority = aclCrudDAO.getAuthority(ace.getAuthorityId()); + + SimpleAccessControlEntry entry = new SimpleAccessControlEntry(); + entry.setAccessStatus(ace.isAllowed() ? AccessStatus.ALLOWED : AccessStatus.DENIED); + entry.setAceType(ace.getAceType()); + entry.setAuthority(authority.getAuthority()); + + /* NOTE: currently unused - intended for possible future enhancement + if (ace.getContextId() != null) + { + AceContext aceContext = aclCrudDAO.getAceContext(ace.getContextId()); + + SimpleAccessControlEntryContext context = new SimpleAccessControlEntryContext(); + context.setClassContext(aceContext.getClassContext()); + context.setKVPContext(aceContext.getKvpContext()); + context.setPropertyContext(aceContext.getPropertyContext()); + entry.setContext(context); + } + */ + + Permission perm = aclCrudDAO.getPermission(ace.getPermissionId()); + QName permTypeQName = qnameDAO.getQName(perm.getTypeQNameId()).getSecond(); // Has an ID so must exist + SimplePermissionReference permissionRefernce = SimplePermissionReference.getPermissionReference(permTypeQName, perm.getName()); + entry.setPermission(permissionRefernce); + entry.setPosition(Integer.valueOf(0)); + + setAccessControlEntry(id, entry); + } + } + return changes; + } + + private static final String RESOURCE_KEY_ACL_CHANGE_SET_ID = "acl.change.set.id"; + + /** + * Support to get the current ACL change set and bind this to the transaction. So we only make one new version of an + * ACL per change set. If something is in the current change set we can update it. + */ + private long getCurrentChangeSetId() + { + Long changeSetId = (Long)AlfrescoTransactionSupport.getResource(RESOURCE_KEY_ACL_CHANGE_SET_ID); + if (changeSetId == null) + { + changeSetId = aclCrudDAO.createAclChangeSet(); + + // bind the id + AlfrescoTransactionSupport.bindResource(RESOURCE_KEY_ACL_CHANGE_SET_ID, changeSetId); + if (logger.isDebugEnabled()) + { + logger.debug("New change set = " + changeSetId); + } + } + else + { + /* + AclChangeSetEntity changeSet = aclCrudDAO.getAclChangeSet((Long)changeSetId); + if (changeSet == null) + { + throw new AlfrescoRuntimeException("Unexpected: missing change set "+changeSetId); + } + + if (logger.isDebugEnabled()) + { + logger.debug("Existing change set = " + changeSetId); + } + */ + } + return changeSetId; + } + + private static class AcePatternMatcher + { + private List patterns; + + AcePatternMatcher(List patterns) + { + this.patterns = patterns; + } + + boolean matches(AclCrudDAO aclCrudDAO, Map result, int position) + { + if (patterns == null) + { + return true; + } + + for (AccessControlEntry pattern : patterns) + { + if (checkPattern(aclCrudDAO, result, position, pattern)) + { + return true; + } + } + return false; + } + + private boolean checkPattern(AclCrudDAO aclCrudDAO, Map result, int position, AccessControlEntry pattern) + { + Boolean result_aceIsAllowed = (Boolean) result.get("allowed"); + Integer result_aceType = (Integer) result.get("applies"); + String result_authority = (String) result.get("authority"); + Long result_permissionId = (Long) result.get("permissionId"); + Integer result_position = (Integer) result.get("pos"); + //Long result_aclmemId = (Long) result.get("aclmemId"); // not used + + if (pattern.getAccessStatus() != null) + { + if (pattern.getAccessStatus() != (result_aceIsAllowed ? AccessStatus.ALLOWED : AccessStatus.DENIED)) + { + return false; + } + } + + if (pattern.getAceType() != null) + { + if (pattern.getAceType() != ACEType.getACETypeFromId(result_aceType)) + { + return false; + } + } + + if (pattern.getAuthority() != null) + { + if ((pattern.getAuthorityType() != AuthorityType.WILDCARD) && !pattern.getAuthority().equals(result_authority)) + { + return false; + } + } + + if (pattern.getContext() != null) + { + throw new IllegalArgumentException("Context not yet supported"); + } + + if (pattern.getPermission() != null) + { + Long permId = aclCrudDAO.getPermission(pattern.getPermission()).getId(); + if (!permId.equals(result_permissionId)) + { + return false; + } + } + + if (pattern.getPosition() != null) + { + if (pattern.getPosition().intValue() >= 0) + { + if (result_position != position) + { + return false; + } + } + else if (pattern.getPosition().intValue() == -1) + { + if (result_position <= position) + { + return false; + } + } + } + + return true; + } + } + + static class AclChangeImpl implements AclChange + { + private Long before; + private Long after; + private ACLType typeBefore; + private ACLType typeAfter; + + public AclChangeImpl(Long before, Long after, ACLType typeBefore, ACLType typeAfter) + { + this.before = before; + this.after = after; + this.typeAfter = typeAfter; + this.typeBefore = typeBefore; + } + + public Long getAfter() + { + return after; + } + + public Long getBefore() + { + return before; + } + + /** + * @param after + */ + public void setAfter(Long after) + { + this.after = after; + } + + /** + * @param before + */ + public void setBefore(Long before) + { + this.before = before; + } + + public ACLType getTypeAfter() + { + return typeAfter; + } + + /** + * @param typeAfter + */ + public void setTypeAfter(ACLType typeAfter) + { + this.typeAfter = typeAfter; + } + + public ACLType getTypeBefore() + { + return typeBefore; + } + + /** + * @param typeBefore + */ + public void setTypeBefore(ACLType typeBefore) + { + this.typeBefore = typeBefore; + } + + @Override + public String toString() + { + StringBuilder builder = new StringBuilder(); + builder.append("(").append(getBefore()).append(",").append(getTypeBefore()).append(")"); + builder.append(" - > "); + builder.append("(").append(getAfter()).append(",").append(getTypeAfter()).append(")"); + return builder.toString(); + } + } + + /* (non-Javadoc) + * @see org.alfresco.repo.domain.permissions.AclDAO#renameAuthority(java.lang.String, java.lang.String) + */ + public void renameAuthority(String before, String after) + { + aclCrudDAO.renameAuthority(before, after); + aclCache.clear(); + } +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AclEntity.java b/source/java/org/alfresco/repo/domain/permissions/AclEntity.java new file mode 100644 index 0000000000..8076190d54 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AclEntity.java @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.security.permissions.ACLType; +import org.alfresco.util.EqualsHelper; + + +/** + * Entity for alf_acess_control_list persistence. + * + * @author janv + * @since 3.4 + */ +public class AclEntity implements Acl, DbAccessControlList +{ + private Long id; + private Long version; + private String aclId; + private boolean latest; + private Long aclVersion; + private boolean inherits; + private Long inheritsFrom; + private Integer type; + private Long inheritedAcl; + private boolean isVersioned; + private boolean requiresVersion; + private Long aclChangeSet; + + /** + * Default constructor + */ + public AclEntity() + { + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + public void incrementVersion() + { + if (this.version >= Long.MAX_VALUE) + { + this.version = 0L; + } + else + { + this.version++; + } + } + + public String getAclId() + { + return aclId; + } + + public void setAclId(String aclId) + { + this.aclId = aclId; + } + + public Boolean isLatest() + { + return latest; + } + + public void setLatest(boolean latest) + { + this.latest = latest; + } + + public Long getAclVersion() + { + return aclVersion; + } + + public void setAclVersion(Long aclVersion) + { + this.aclVersion = aclVersion; + } + + public Boolean getInherits() + { + return inherits; + } + + public void setInherits(boolean inherits) + { + this.inherits = inherits; + } + + public Long getInheritsFrom() + { + return inheritsFrom; + } + + public void setInheritsFrom(Long inheritsFrom) + { + this.inheritsFrom = inheritsFrom; + } + + public Integer getType() + { + return type; + } + + public void setType(Integer type) + { + this.type = type; + } + + public Long getInheritedAcl() + { + return inheritedAcl; + } + + public void setInheritedAcl(Long inheritedAcl) + { + this.inheritedAcl = inheritedAcl; + } + + public Boolean isVersioned() + { + return isVersioned; + } + + public void setVersioned(boolean isVersioned) + { + this.isVersioned = isVersioned; + } + + public Boolean getRequiresVersion() + { + return requiresVersion; + } + + public void setRequiresVersion(boolean requiresVersion) + { + this.requiresVersion = requiresVersion; + } + + public Long getAclChangeSetId() + { + return aclChangeSet; + } + + public void setAclChangeSetId(Long aclChangeSet) + { + this.aclChangeSet = aclChangeSet; + } + + public ACLType getAclType() + { + return ACLType.getACLTypeFromId(type); + } + + public void setAclType(ACLType type) + { + this.type = type.getId(); + } + + @Override + public int hashCode() + { + return (id == null ? 0 : id.hashCode()); + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + else if (obj instanceof AclEntity) + { + AclEntity that = (AclEntity)obj; + return (EqualsHelper.nullSafeEquals(this.id, that.id)); + } + else + { + return false; + } + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("AclEntity") + .append("[ ID=").append(id) + .append(", version=").append(version) + .append(", aclId=").append(aclId) + .append(", isLatest=").append(latest) + .append(", aclVersion=").append(aclVersion) + .append(", inherits=").append(inherits) + .append(", inheritsFrom=").append(inheritsFrom) + .append(", type=").append(type) + .append(", inheritedAcl=").append(inheritedAcl) + .append(", isVersioned=").append(isVersioned) + .append(", requiresVersion=").append(requiresVersion) + .append(", aclChangeSet=").append(aclChangeSet) + .append("]"); + return sb.toString(); + } +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AclMember.java b/source/java/org/alfresco/repo/domain/permissions/AclMember.java new file mode 100644 index 0000000000..27f792bdc2 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AclMember.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + + +/** + * Entity for alf_access_control_member persistence. + * + * Relates an ACE to an ACL with a position + * + * @author janv + * @since 3.4 + */ +public interface AclMember +{ + public Long getId(); + + /** + * Get the ACL to which the ACE belongs + * + * @return - the acl id + */ + public Long getAclId(); + + /** + * Get the ACE included in the ACL + * + * @return - the ace id + */ + public Long getAceId(); + + /** + * Get the position group for this member in the ACL + * + * 0 - implies the ACE is on the object + * >0 - that it is inherited in some way + * + * The lower values are checked first so take precedence. + * + * @return - the position of the ace in the acl + */ + public Integer getPos(); +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AclMemberEntity.java b/source/java/org/alfresco/repo/domain/permissions/AclMemberEntity.java new file mode 100644 index 0000000000..f439174d75 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AclMemberEntity.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + +import org.alfresco.util.EqualsHelper; + + +/** + * Entity for alf_access_control_member persistence. + * + * Relates an ACE to an ACL with a position + * + * @author janv + * @since 3.4 + */ +public class AclMemberEntity implements AclMember +{ + private Long id; + private Long version; + private Long aclId; + private Long aceId; + private Integer pos; + + /** + * Default constructor + */ + public AclMemberEntity() + { + } + + public AclMemberEntity(long aclId, long aceId, int pos) + { + this.aclId = aclId; + this.aceId = aceId; + this.pos = pos; + } + + /** + * Get the ID for this ACL member + * + * @return - the id + */ + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + /** + * Get the version for this ACL member - for optimistic locking + * + * @return - the version + */ + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + public void incrementVersion() + { + if (this.version >= Long.MAX_VALUE) + { + this.version = 0L; + } + else + { + this.version++; + } + } + + /** + * Get the ACL to which the ACE belongs + * + * @return - the acl id + */ + public Long getAclId() + { + return aclId; + } + + public void setAclId(Long aclId) + { + this.aclId = aclId; + } + + /** + * Get the ACE included in the ACL + * + * @return - the ace id + */ + public Long getAceId() + { + return aceId; + } + + public void setAceId(Long aceId) + { + this.aceId = aceId; + } + + /** + * Get the position group for this member in the ACL + * + * 0 - implies the ACE is on the object + * >0 - that it is inherited in some way + * + * The lower values are checked first so take precedence. + * + * @return - the position of the ace in the acl + */ + public Integer getPos() + { + return pos; + } + + /** + * Set the position for the ACL-ACE relationship + * + * @param position + */ + public void setPos(Integer pos) + { + this.pos = pos; + } + + @Override + public int hashCode() + { + return (id == null ? 0 : id.hashCode()); + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + else if (obj instanceof AclMemberEntity) + { + AclMemberEntity that = (AclMemberEntity)obj; + return (EqualsHelper.nullSafeEquals(this.id, that.id)); + } + else + { + return false; + } + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("AclMemberEntity") + .append("[ ID=").append(id) + .append(", version=").append(version) + .append(", aclId=").append(aclId) + .append(", aceId=").append(aceId) + .append(", pos=").append(pos) + .append("]"); + return sb.toString(); + } +} diff --git a/source/java/org/alfresco/repo/domain/permissions/Authority.java b/source/java/org/alfresco/repo/domain/permissions/Authority.java new file mode 100644 index 0000000000..c02d67e27f --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/Authority.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + + +/** + * Entity for alf_authority persistence. + * + * @author janv + * @since 3.4 + */ +public interface Authority +{ + public Long getId(); + public String getAuthority(); + public Long getCrc(); +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AuthorityAlias.java b/source/java/org/alfresco/repo/domain/permissions/AuthorityAlias.java new file mode 100644 index 0000000000..02858cb7b4 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AuthorityAlias.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + + +/** + * Entity for alf_authority_alias persistence. + * + * @author janv + * @since 3.4 + */ +public interface AuthorityAlias +{ + public Long getId(); + public Long getAuthId(); + public Long getAliasId(); +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AuthorityAliasEntity.java b/source/java/org/alfresco/repo/domain/permissions/AuthorityAliasEntity.java new file mode 100644 index 0000000000..a3aa109a97 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AuthorityAliasEntity.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + +import org.alfresco.util.EqualsHelper; + + +/** + * Entity for alf_authority_alias persistence. + * + * @author janv + * @since 3.4 + */ +public class AuthorityAliasEntity implements AuthorityAlias +{ + private Long id; + private Long version; + private Long authId; + private Long aliasId; + + /** + * Default constructor + */ + public AuthorityAliasEntity() + { + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + public Long getAuthId() + { + return authId; + } + + public void setAuthId(Long authId) + { + this.authId = authId; + } + + public Long getAliasId() + { + return aliasId; + } + + public void setAliasId(Long aliasId) + { + this.aliasId = aliasId; + } + + @Override + public int hashCode() + { + return (id == null ? 0 : id.hashCode()); + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + else if (obj instanceof AuthorityAliasEntity) + { + AuthorityAliasEntity that = (AuthorityAliasEntity)obj; + return (EqualsHelper.nullSafeEquals(this.id, that.id)); + } + else + { + return false; + } + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("AuthorityAliasEntity") + .append("[ ID=").append(id) + .append(", version=").append(version) + .append(", authId=").append(authId) + .append(", aliasId=").append(aliasId) + .append("]"); + return sb.toString(); + } +} diff --git a/source/java/org/alfresco/repo/domain/permissions/AuthorityEntity.java b/source/java/org/alfresco/repo/domain/permissions/AuthorityEntity.java new file mode 100644 index 0000000000..187ce6579a --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/AuthorityEntity.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + + +/** + * Entity for alf_authority persistence. + * + * @author janv + * @since 3.4 + */ +public class AuthorityEntity implements Authority +{ + private Long id; + private Long version; + private String authority; + private Long crc; + + /** + * Default constructor + */ + public AuthorityEntity() + { + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + public void incrementVersion() + { + if (this.version >= Long.MAX_VALUE) + { + this.version = 0L; + } + else + { + this.version++; + } + } + + public String getAuthority() + { + return authority; + } + + public void setAuthority(String authority) + { + this.authority = authority; + } + + public Long getCrc() + { + return crc; + } + + public void setCrc(Long crc) + { + this.crc = crc; + } + + @Override + public int hashCode() + { + return getAuthority().hashCode(); + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + else if (obj instanceof AuthorityEntity) + { + AuthorityEntity that = (AuthorityEntity)obj; + return (this.getAuthority().equals(that.getAuthority())); + } + else + { + return false; + } + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("AuthorityEntity") + .append("[ ID=").append(id) + .append(", version=").append(version) + .append(", authority=").append(authority) + .append(", crc=").append(crc) + .append("]"); + return sb.toString(); + } +} diff --git a/source/java/org/alfresco/repo/domain/permissions/Permission.java b/source/java/org/alfresco/repo/domain/permissions/Permission.java new file mode 100644 index 0000000000..1ff14bf97b --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/Permission.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + + +/** + * Entity for alf_permission persistence. + * + * @author janv + * @since 3.4 + */ +public interface Permission +{ + public Long getId(); + public Long getTypeQNameId(); + public String getName(); +} diff --git a/source/java/org/alfresco/repo/domain/permissions/PermissionEntity.java b/source/java/org/alfresco/repo/domain/permissions/PermissionEntity.java new file mode 100644 index 0000000000..d1a6e9ce32 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/PermissionEntity.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * aLong with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions; + +import java.io.Serializable; + +import org.alfresco.util.EqualsHelper; + + +/** + * Entity for alf_permission persistence. + * + * @author janv + * @since 3.4 + */ +public class PermissionEntity implements Permission, Serializable +{ + private static final long serialVersionUID = 8219087288749688965L; + + private Long id; + private Long version; + private Long qnameId; + private String name; + + /** + * Default constructor + */ + public PermissionEntity() + { + } + + public PermissionEntity(Long qnameId, String name) + { + this.qnameId = qnameId; + this.name = name; + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + public void incrementVersion() + { + if (this.version >= Long.MAX_VALUE) + { + this.version = 0L; + } + else + { + this.version++; + } + } + + public Long getTypeQNameId() + { + return qnameId; + } + + public void setTypeQNameId(Long qnameId) + { + this.qnameId = qnameId; + } + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + @Override + public int hashCode() + { + return qnameId.hashCode() + (37 * name.hashCode()); + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + else if (obj instanceof PermissionEntity) + { + PermissionEntity that = (PermissionEntity)obj; + return (EqualsHelper.nullSafeEquals(this.qnameId, that.qnameId) && + EqualsHelper.nullSafeEquals(this.name, that.name)); + } + else + { + return false; + } + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(512); + sb.append("PermissionEntity") + .append("[ ID=").append(id) + .append(", version=").append(version) + .append(", qnameId=").append(qnameId) + .append(", name=").append(name) + .append("]"); + return sb.toString(); + } +} diff --git a/source/java/org/alfresco/repo/domain/permissions/ibatis/AclCrudDAOImpl.java b/source/java/org/alfresco/repo/domain/permissions/ibatis/AclCrudDAOImpl.java new file mode 100644 index 0000000000..ada70fd0f0 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/permissions/ibatis/AclCrudDAOImpl.java @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.permissions.ibatis; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.repo.domain.permissions.AbstractAclCrudDAOImpl; +import org.alfresco.repo.domain.permissions.Ace; +import org.alfresco.repo.domain.permissions.AceContextEntity; +import org.alfresco.repo.domain.permissions.AceEntity; +import org.alfresco.repo.domain.permissions.AclChangeSetEntity; +import org.alfresco.repo.domain.permissions.AclEntity; +import org.alfresco.repo.domain.permissions.AclMemberEntity; +import org.alfresco.repo.domain.permissions.AuthorityAliasEntity; +import org.alfresco.repo.domain.permissions.AuthorityEntity; +import org.alfresco.repo.domain.permissions.PermissionEntity; +import org.alfresco.repo.security.permissions.ACEType; +import org.springframework.orm.ibatis.SqlMapClientTemplate; + +import com.ibatis.sqlmap.engine.execution.SqlExecutor; + +/** + * iBatis-specific implementation of the ACL Crud DAO. + * + * @author janv + * @since 3.4 + */ +public class AclCrudDAOImpl extends AbstractAclCrudDAOImpl +{ + private static final String INSERT_ACL = "alfresco.permissions.insert_Acl"; + private static final String SELECT_ACL_BY_ID = "alfresco.permissions.select_AclById"; + private static final String SELECT_ACLS_THAT_INHERIT_FROM_ACL = "alfresco.permissions.select_AclsThatInheritFromAcl"; + private static final String SELECT_LATEST_ACL_BY_GUID = "alfresco.permissions.select_LatestAclByGuid"; + private static final String SELECT_ADM_NODES_BY_ACL = "alfresco.permissions.select_ADMNodesByAclId"; + private static final String SELECT_AVM_NODES_BY_ACL = "alfresco.permissions.select_AVMNodesByAclId"; + private static final String UPDATE_ACL = "alfresco.permissions.update_Acl"; + private static final String DELETE_ACL = "alfresco.permissions.delete_Acl"; + + private static final String INSERT_ACL_MEMBER = "alfresco.permissions.insert_AclMember"; + private static final String SELECT_ACL_MEMBERS_BY_ACL = "alfresco.permissions.select_AclMembersByAclId"; + private static final String SELECT_ACL_MEMBERS_BY_AUTHORITY = "alfresco.permissions.select_AclMembersByAuthorityName"; + private static final String UPDATE_ACL_MEMBER = "alfresco.permissions.update_AclMember"; + private static final String DELETE_ACL_MEMBERS_LIST = "alfresco.permissions.delete_AclMembersList"; + private static final String DELETE_ACL_MEMBERS_BY_ACL = "alfresco.permissions.delete_AclMembersByAclId"; + + private static final String INSERT_ACL_CHANGESET = "alfresco.permissions.insert_AclChangeSet"; + private static final String SELECT_ACL_CHANGESET_BY_ID = "alfresco.permissions.select_AclChangeSetById"; + private static final String DELETE_ACL_CHANGESET = "alfresco.permissions.delete_AclChangeSet"; + + private static final String INSERT_ACE = "alfresco.permissions.insert_Ace"; + private static final String SELECT_ACE_BY_ID = "alfresco.permissions.select_AceById"; + private static final String SELECT_ACES_BY_AUTHORITY = "alfresco.permissions.select_AcesByAuthorityId"; + private static final String SELECT_ACES_AND_AUTHORIES_BY_ACL = "alfresco.permissions.select_AcesAndAuthoritiesByAclId"; + private static final String SELECT_ACE_WITH_NO_CONTEXT = "alfresco.permissions.select_AceWithNoContext"; + private static final String DELETE_ACES_LIST = "alfresco.permissions.delete_AcesList"; + + private static final String INSERT_ACE_CONTEXT = "alfresco.permissions.insert_AceContext"; + private static final String SELECT_ACE_CONTEXT_BY_ID = "alfresco.permissions.select_AceContextById"; + private static final String DELETE_ACE_CONTEXT = "alfresco.permissions.delete_AceContext"; + + private static final String INSERT_PERMISSION = "alfresco.permissions.insert_Permission"; + private static final String SELECT_PERMISSION_BY_ID = "alfresco.permissions.select_PermissionById"; + private static final String SELECT_PERMISSION_BY_TYPE_AND_NAME = "alfresco.permissions.select_PermissionByTypeAndName"; + private static final String UPDATE_PERMISSION = "alfresco.permissions.update_Permission"; + private static final String DELETE_PERMISSION = "alfresco.permissions.delete_Permission"; + + private static final String INSERT_AUTHORITY = "alfresco.permissions.insert_Authority"; + private static final String SELECT_AUTHORITY_BY_ID = "alfresco.permissions.select_AuthorityById"; + private static final String SELECT_AUTHORITY_BY_NAME = "alfresco.permissions.select_AuthorityByName"; + private static final String UPDATE_AUTHORITY = "alfresco.permissions.update_Authority"; + private static final String DELETE_AUTHORITY = "alfresco.permissions.delete_Authority"; + + private static final String INSERT_AUTHORITY_ALIAS = "alfresco.permissions.insert_AuthorityAlias"; + private static final String DELETE_AUTHORITY_ALIAS = "alfresco.permissions.delete_AuthorityAlias"; + + + private SqlMapClientTemplate template; + + public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) + { + this.template = sqlMapClientTemplate; + } + + @Override + protected AclEntity createAclEntity(AclEntity entity) + { + entity.setVersion(0L); + Long id = (Long)template.insert(INSERT_ACL, entity); + entity.setId(id); + return entity; + } + + @Override + protected AclEntity getAclEntity(long aclEntityId) + { + Map params = new HashMap(1); + params.put("id", aclEntityId); + + return (AclEntity)template.queryForObject(SELECT_ACL_BY_ID, params); + } + + @SuppressWarnings("unchecked") + @Override + protected List getAclEntitiesThatInheritFromAcl(long aclEntityId) + { + Map params = new HashMap(2); + params.put("id", aclEntityId); + params.put("bool", true); + + return (List)template.queryForList(SELECT_ACLS_THAT_INHERIT_FROM_ACL, params); + } + + @Override + protected Long getLatestAclEntityByGuid(String aclGuid) + { + Map params = new HashMap(2); + params.put("name", aclGuid); + params.put("bool", true); + + return (Long)template.queryForObject(SELECT_LATEST_ACL_BY_GUID, params); + } + + @SuppressWarnings("unchecked") + @Override + protected List getADMNodeEntityIdsByAcl(long aclEntityId, int maxResults) + { + if (maxResults < 0) + { + maxResults = SqlExecutor.NO_MAXIMUM_RESULTS; + } + + Map params = new HashMap(1); + params.put("id", aclEntityId); + + return (List)template.queryForList(SELECT_ADM_NODES_BY_ACL, params, 0 , maxResults); + } + + @SuppressWarnings("unchecked") + @Override + protected List getAVMNodeEntityIdsByAcl(long aclEntityId, int maxResults) + { + if (maxResults < 0) + { + maxResults = SqlExecutor.NO_MAXIMUM_RESULTS; + } + + Map params = new HashMap(1); + params.put("id", aclEntityId); + + return (List)template.queryForList(SELECT_AVM_NODES_BY_ACL, params, 0 , maxResults); + } + + @Override + protected int updateAclEntity(AclEntity updatedAclEntity) + { + updatedAclEntity.incrementVersion(); + + return template.update(UPDATE_ACL, updatedAclEntity); + } + + @Override + protected int deleteAclEntity(long aclEntityId) + { + Map params = new HashMap(1); + params.put("id", aclEntityId); + + return template.delete(DELETE_ACL, params); + } + + @Override + protected AclMemberEntity createAclMemberEntity(AclMemberEntity entity) + { + entity.setVersion(0L); + Long id = (Long)template.insert(INSERT_ACL_MEMBER, entity); + entity.setId(id); + return entity; + } + + @SuppressWarnings("unchecked") + @Override + protected List getAclMemberEntitiesByAcl(long aclEntityId) + { + Map params = new HashMap(1); + params.put("id", aclEntityId); + + return (List) template.queryForList(SELECT_ACL_MEMBERS_BY_ACL, params); + } + + @SuppressWarnings("unchecked") + @Override + protected List getAclMemberEntitiesByAuthority(String authorityName) + { + Map params = new HashMap(1); + params.put("name", authorityName); + + return (List) template.queryForList(SELECT_ACL_MEMBERS_BY_AUTHORITY, params); + } + + @Override + protected int updateAclMemberEntity(AclMemberEntity updatedAclMemberEntity) + { + updatedAclMemberEntity.incrementVersion(); + + return template.update(UPDATE_ACL_MEMBER, updatedAclMemberEntity); + } + + @Override + protected int deleteAclMemberEntities(List aclMemberEntityIds) + { + return template.delete(DELETE_ACL_MEMBERS_LIST, aclMemberEntityIds); + } + + @Override + protected int deleteAclMemberEntitiesByAcl(long aclEntityId) + { + Map params = new HashMap(1); + params.put("id", aclEntityId); + + return template.delete(DELETE_ACL_MEMBERS_BY_ACL, params); + } + + @Override + protected long createAclChangeSetEntity() + { + AclChangeSetEntity entity = new AclChangeSetEntity(); + entity.setVersion(0L); + return (Long)template.insert(INSERT_ACL_CHANGESET, entity); + } + + @Override + protected AclChangeSetEntity getAclChangeSetEntity(long aclChangeSetEntityId) + { + Map params = new HashMap(1); + params.put("id", aclChangeSetEntityId); + + return (AclChangeSetEntity)template.queryForObject(SELECT_ACL_CHANGESET_BY_ID, params); + } + + @Override + protected int deleteAclChangeSetEntity(long aclChangeSetEntityId) + { + Map params = new HashMap(1); + params.put("id", aclChangeSetEntityId); + + return template.delete(DELETE_ACL_CHANGESET, params); + } + + @Override + protected long createAceEntity(AceEntity entity) + { + entity.setVersion(0L); + return (Long)template.insert(INSERT_ACE, entity); + } + + @Override + protected AceEntity getAceEntity(long aceEntityId) + { + Map params = new HashMap(1); + params.put("id", aceEntityId); + + return (AceEntity)template.queryForObject(SELECT_ACE_BY_ID, params); + } + + @Override + protected AceEntity getAceEntity(long permissionId, long authorityId, boolean allowed, ACEType type) + { + Map params = new HashMap(4); + params.put("id1", permissionId); + params.put("id2", authorityId); + params.put("bool", allowed); + params.put("int", type.getId()); + + return (AceEntity)template.queryForObject(SELECT_ACE_WITH_NO_CONTEXT, params); + } + + @SuppressWarnings("unchecked") + @Override + protected List getAceEntitiesByAuthority(long authorityEntityId) + { + Map params = new HashMap(1); + params.put("id", authorityEntityId); + + return (List) template.queryForList(SELECT_ACES_BY_AUTHORITY, params); + } + + @SuppressWarnings("unchecked") + @Override + protected List> getAceAndAuthorityEntitiesByAcl(long aclEntityId) + { + Map params = new HashMap(1); + params.put("id", aclEntityId); + + return (List>) template.queryForList(SELECT_ACES_AND_AUTHORIES_BY_ACL, params); + } + + @Override + protected int deleteAceEntities(List aceEntityIds) + { + return template.delete(DELETE_ACES_LIST, aceEntityIds); + } + + @Override + protected long createAceContextEntity(AceContextEntity entity) + { + entity.setVersion(0L); + return (Long)template.insert(INSERT_ACE_CONTEXT, entity); + } + + @Override + protected AceContextEntity getAceContextEntity(long aceContextEntityId) + { + Map params = new HashMap(1); + params.put("id", aceContextEntityId); + + return (AceContextEntity)template.queryForObject(SELECT_ACE_CONTEXT_BY_ID, params); + } + + @Override + protected int deleteAceContextEntity(long aceContextEntityId) + { + Map params = new HashMap(1); + params.put("id", aceContextEntityId); + + return template.delete(DELETE_ACE_CONTEXT, params); + } + + @Override + protected PermissionEntity createPermissionEntity(PermissionEntity entity) + { + entity.setVersion(0L); + Long id = (Long)template.insert(INSERT_PERMISSION, entity); + entity.setId(id); + return entity; + } + + @Override + protected PermissionEntity getPermissionEntity(long permissionEntityId) + { + Map params = new HashMap(1); + params.put("id", permissionEntityId); + + return (PermissionEntity)template.queryForObject(SELECT_PERMISSION_BY_ID, params); + } + + @Override + protected PermissionEntity getPermissionEntity(long qnameId, String name) + { + Map params = new HashMap(2); + params.put("id", qnameId); + params.put("name", name); + + return (PermissionEntity)template.queryForObject(SELECT_PERMISSION_BY_TYPE_AND_NAME, params); + } + + @Override + protected int updatePermissionEntity(PermissionEntity permissionEntity) + { + permissionEntity.incrementVersion(); + + return template.update(UPDATE_PERMISSION, permissionEntity); + } + + @Override + protected int deletePermissionEntity(long permissionEntityId) + { + Map params = new HashMap(1); + params.put("id", permissionEntityId); + + return template.delete(DELETE_PERMISSION, params); + } + + @Override + protected AuthorityEntity createAuthorityEntity(AuthorityEntity entity) + { + entity.setVersion(0L); + Long id = (Long)template.insert(INSERT_AUTHORITY, entity); + entity.setId(id); + return entity; + } + + @Override + protected AuthorityEntity getAuthorityEntity(long authorityEntityId) + { + Map params = new HashMap(1); + params.put("id", authorityEntityId); + + return (AuthorityEntity)template.queryForObject(SELECT_AUTHORITY_BY_ID, params); + } + + @SuppressWarnings("unchecked") + @Override + + protected AuthorityEntity getAuthorityEntity(String authorityName) + { + Map params = new HashMap(1); + params.put("name", authorityName); + + // note: allow for list (non-unique name) in case of upgrade of old schemas + AuthorityEntity result = null; + List authorities = (List)template.queryForList(SELECT_AUTHORITY_BY_NAME, params); + for (AuthorityEntity found : authorities) + { + if (found.getAuthority().equals(authorityName)) + { + result = found; + break; + } + } + return result; + } + + @Override + protected int updateAuthorityEntity(AuthorityEntity authorityEntity) + { + authorityEntity.incrementVersion(); + + return template.update(UPDATE_AUTHORITY, authorityEntity); + } + + @Override + protected int deleteAuthorityEntity(long authorityEntityId) + { + Map params = new HashMap(1); + params.put("id", authorityEntityId); + + return template.delete(DELETE_AUTHORITY, params); + } + + @Override + protected long createAuthorityAliasEntity(AuthorityAliasEntity entity) + { + entity.setVersion(0L); + return (Long)template.insert(INSERT_AUTHORITY_ALIAS, entity); + } + + @Override + protected int deleteAuthorityAliasEntity(long authorityAliasEntityId) + { + Map params = new HashMap(1); + params.put("id", authorityAliasEntityId); + + return template.delete(DELETE_AUTHORITY_ALIAS, params); + } +} diff --git a/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java b/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java index c15bd49caf..784283cbe0 100644 --- a/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java @@ -19,6 +19,7 @@ package org.alfresco.repo.domain.propval; import java.io.Serializable; +import java.sql.Savepoint; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -33,9 +34,9 @@ import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.cache.lookup.EntityLookupCache; import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAOAdaptor; import org.alfresco.repo.domain.CrcHelper; +import org.alfresco.repo.domain.control.ControlDAO; import org.alfresco.repo.domain.propval.PropertyValueEntity.PersistedType; import org.alfresco.repo.domain.schema.SchemaBootstrap; -import org.alfresco.repo.props.PropertyUniqueConstraintViolation; import org.alfresco.util.Pair; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -63,6 +64,7 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO protected final Log logger = LogFactory.getLog(getClass()); protected PropertyTypeConverter converter; + protected ControlDAO controlDAO; private final PropertyClassCallbackDAO propertyClassDaoCallback; private final PropertyDateValueCallbackDAO propertyDateValueCallback; @@ -154,6 +156,14 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO this.converter = converter; } + /** + * @param controlDAO the DAO that provides connection control + */ + public void setControlDAO(ControlDAO controlDAO) + { + this.controlDAO = controlDAO; + } + /** * Set the cache to use for alf_prop_class lookups (optional). * @@ -858,8 +868,10 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO } /** - * No-op. This is implemented as we just want to update the cache. - * @return Returns 0 always + * Updates a property. The alf_prop_root entity is updated + * to ensure concurrent modification is detected. + * + * @return Returns 1 always */ @Override public int updateValue(Long key, Serializable value) @@ -1073,15 +1085,29 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO // 'alf_prop_unique_ctx' accessors //================================ - public Long createPropertyUniqueContext(Serializable value1, Serializable value2, Serializable value3) + public Pair createPropertyUniqueContext( + Serializable value1, Serializable value2, Serializable value3, + Serializable propertyValue1) { + /* + * Use savepoints so that the PropertyUniqueConstraintViolation can be caught and handled in-transactioin + */ + // Translate the properties. Null values are acceptable Long id1 = getOrCreatePropertyValue(value1).getFirst(); Long id2 = getOrCreatePropertyValue(value2).getFirst(); Long id3 = getOrCreatePropertyValue(value3).getFirst(); + Long property1Id = null; + if (propertyValue1 != null) + { + property1Id = createProperty(propertyValue1); + } + + Savepoint savepoint = controlDAO.createSavepoint("createPropertyUniqueContext"); try { - PropertyUniqueContextEntity entity = createPropertyUniqueContext(id1, id2, id3); + PropertyUniqueContextEntity entity = createPropertyUniqueContext(id1, id2, id3, property1Id); + controlDAO.releaseSavepoint(savepoint); if (logger.isDebugEnabled()) { logger.debug( @@ -1089,25 +1115,26 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO " Values: " + value1 + "-" + value2 + "-" + value3 + "\n" + " Result: " + entity); } - return entity.getId(); + return new Pair(entity.getId(), property1Id); } catch (Throwable e) { - throw new PropertyUniqueConstraintViolation(value1, value2, value3); + controlDAO.rollbackToSavepoint(savepoint); + throw new PropertyUniqueConstraintViolation(value1, value2, value3, e); } } - - public Long getPropertyUniqueContext(Serializable value1, Serializable value2, Serializable value3) + + public Pair getPropertyUniqueContext(Serializable value1, Serializable value2, Serializable value3) { // Translate the properties. Null values are quite acceptable Pair pair1 = getPropertyValue(value1); Pair pair2 = getPropertyValue(value2); Pair pair3 = getPropertyValue(value3); if (pair1 == null || pair2 == null || pair3 == null) - { + { // None of the values exist so no unique context values can exist - return null; - } + return null; + } Long id1 = pair1.getFirst(); Long id2 = pair2.getFirst(); Long id3 = pair3.getFirst(); @@ -1120,15 +1147,48 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO " Values: " + value1 + "-" + value2 + "-" + value3 + "\n" + " Result: " + entity); } - return entity == null ? null : entity.getId(); + return entity == null ? null : new Pair(entity.getId(), entity.getPropertyId()); + } + + public void getPropertyUniqueContext(PropertyUniqueContextCallback callback, Serializable... values) + { + if (values.length < 1 || values.length > 3) + { + throw new IllegalArgumentException("Get of unique property sets must have 1, 2 or 3 values"); + } + Long[] valueIds = new Long[values.length]; + for (int i = 0; i < values.length; i++) + { + Pair valuePair = getPropertyValue(values[i]); + if (valuePair == null) + { + // No such value, so no need to get + return; + } + valueIds[i] = valuePair.getFirst(); + } + getPropertyUniqueContextByValues(callback, valueIds); + // Done + if (logger.isDebugEnabled()) + { + logger.debug( + "Searched for unique property context: \n" + + " Values: " + values); + } } public void updatePropertyUniqueContext(Long id, Serializable value1, Serializable value2, Serializable value3) { + /* + * Use savepoints so that the PropertyUniqueConstraintViolation can be caught and handled in-transactioin + */ + // Translate the properties. Null values are acceptable Long id1 = getOrCreatePropertyValue(value1).getFirst(); Long id2 = getOrCreatePropertyValue(value2).getFirst(); Long id3 = getOrCreatePropertyValue(value3).getFirst(); + + Savepoint savepoint = controlDAO.createSavepoint("updatePropertyUniqueContext"); try { PropertyUniqueContextEntity entity = getPropertyUniqueContextById(id); @@ -1140,6 +1200,7 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO entity.setValue2PropId(id2); entity.setValue3PropId(id3); updatePropertyUniqueContext(entity); + controlDAO.releaseSavepoint(savepoint); // Done if (logger.isDebugEnabled()) { @@ -1152,10 +1213,46 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO } catch (Throwable e) { + controlDAO.rollbackToSavepoint(savepoint); throw new PropertyUniqueConstraintViolation(value1, value2, value3, e); } } + public void updatePropertyUniqueContext(Long id, Serializable propertyValue) + { + PropertyUniqueContextEntity entity = getPropertyUniqueContextById(id); + if (entity == null) + { + throw new DataIntegrityViolationException("No unique property context exists for id: " + id); + } + Long propertyIdToDelete = entity.getPropertyId(); + + Long propertyId = null; + if (propertyValue != null) + { + propertyId = createProperty(propertyValue); + } + + // Create a new property + entity.setPropertyId(propertyId); + updatePropertyUniqueContext(entity); + + // Clean up the previous property, if present + if (propertyIdToDelete != null) + { + deleteProperty(propertyIdToDelete); + } + + // Done + if (logger.isDebugEnabled()) + { + logger.debug( + "Updated unique property context: \n" + + " ID: " + id + "\n" + + " Property: " + propertyId); + } + } + public int deletePropertyUniqueContext(Serializable... values) { if (values.length < 1 || values.length > 3) @@ -1185,9 +1282,10 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO return deleted; } - protected abstract PropertyUniqueContextEntity createPropertyUniqueContext(Long valueId1, Long valueId2, Long valueId3); + protected abstract PropertyUniqueContextEntity createPropertyUniqueContext(Long valueId1, Long valueId2, Long valueId3, Long propertyId); protected abstract PropertyUniqueContextEntity getPropertyUniqueContextById(Long id); protected abstract PropertyUniqueContextEntity getPropertyUniqueContextByValues(Long valueId1, Long valueId2, Long valueId3); + protected abstract void getPropertyUniqueContextByValues(PropertyUniqueContextCallback callback, Long... valueIds); protected abstract PropertyUniqueContextEntity updatePropertyUniqueContext(PropertyUniqueContextEntity entity); protected abstract int deletePropertyUniqueContexts(Long ... valueIds); diff --git a/source/java/org/alfresco/repo/domain/propval/DefaultPropertyTypeConverter.java b/source/java/org/alfresco/repo/domain/propval/DefaultPropertyTypeConverter.java index edd7bc879d..9969dc2be2 100644 --- a/source/java/org/alfresco/repo/domain/propval/DefaultPropertyTypeConverter.java +++ b/source/java/org/alfresco/repo/domain/propval/DefaultPropertyTypeConverter.java @@ -185,6 +185,10 @@ public class DefaultPropertyTypeConverter implements PropertyTypeConverter // It'll just be given back as a class name i.e. a CONSTRUCTABLE return PersistedType.CONSTRUCTABLE; } + else if (value instanceof Enum) + { + return PersistedType.ENUM; + } else { // Check if there are converters to and from well-known types, just in case @@ -204,10 +208,20 @@ public class DefaultPropertyTypeConverter implements PropertyTypeConverter } /** - * Performs the conversion + * Performs the conversion using {@link DefaultTypeConverter} but also adds + * special handling for {@link Enum enum types}. */ + @SuppressWarnings("unchecked") public T convert(Class targetClass, Serializable value) { - return DefaultTypeConverter.INSTANCE.convert(targetClass, value); + if (targetClass.isEnum() && value != null && value instanceof String) + { + Class enumClazz = (Class) targetClass; + return (T) Enum.valueOf(enumClazz, (String) value); + } + else + { + return DefaultTypeConverter.INSTANCE.convert(targetClass, value); + } } } diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyTypeConverter.java b/source/java/org/alfresco/repo/domain/propval/PropertyTypeConverter.java index ed445a83d6..b5ef4cb9fc 100644 --- a/source/java/org/alfresco/repo/domain/propval/PropertyTypeConverter.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyTypeConverter.java @@ -59,6 +59,7 @@ public interface PropertyTypeConverter /** * Convert a value to a given type. * + * @param targetClass the desired type to convert to * @param value the value to convert * @return Returns the persisted type and value to persist */ diff --git a/source/java/org/alfresco/repo/props/PropertyUniqueConstraintViolation.java b/source/java/org/alfresco/repo/domain/propval/PropertyUniqueConstraintViolation.java similarity index 83% rename from source/java/org/alfresco/repo/props/PropertyUniqueConstraintViolation.java rename to source/java/org/alfresco/repo/domain/propval/PropertyUniqueConstraintViolation.java index 5f5d692071..12ffa49cda 100644 --- a/source/java/org/alfresco/repo/props/PropertyUniqueConstraintViolation.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyUniqueConstraintViolation.java @@ -1,69 +1,61 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.props; - -import java.io.Serializable; - -import org.alfresco.error.AlfrescoRuntimeException; - -/** - * Exception generated when the {@link PropertyValueDAO} - * - * @author Derek Hulley - * @since 3.2 - */ -public class PropertyUniqueConstraintViolation extends AlfrescoRuntimeException -{ - private static final long serialVersionUID = -7792036870731759068L; - - private final Serializable value1; - private final Serializable value2; - private final Serializable value3; - - public PropertyUniqueConstraintViolation(Serializable value1, Serializable value2, Serializable value3) - { - super("Non-unique values for unique constraint: " + value1 + "-" + value2 + "-" + value3); - this.value1 = value1; - this.value2 = value2; - this.value3 = value3; - } - - public PropertyUniqueConstraintViolation(Serializable value1, Serializable value2, Serializable value3, Throwable cause) - { - super("Non-unique values for unique constraint: " + value1 + "-" + value2 + "-" + value3, cause); - this.value1 = value1; - this.value2 = value2; - this.value3 = value3; - } - - public Serializable getValue1() - { - return value1; - } - - public Serializable getValue2() - { - return value2; - } - - public Serializable getValue3() - { - return value3; - } -} +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.domain.propval; + +import java.io.Serializable; + +import org.alfresco.error.AlfrescoRuntimeException; + +/** + * Exception generated when the {@link PropertyValueDAO} + * + * @author Derek Hulley + * @since 3.2 + */ +public class PropertyUniqueConstraintViolation extends AlfrescoRuntimeException +{ + private static final long serialVersionUID = -7792036870731759068L; + + private final Serializable value1; + private final Serializable value2; + private final Serializable value3; + + public PropertyUniqueConstraintViolation(Serializable value1, Serializable value2, Serializable value3, Throwable cause) + { + super("Non-unique values for unique constraint: " + value1 + "-" + value2 + "-" + value3, cause); + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + } + + public Serializable getValue1() + { + return value1; + } + + public Serializable getValue2() + { + return value2; + } + + public Serializable getValue3() + { + return value3; + } +} diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyUniqueContextEntity.java b/source/java/org/alfresco/repo/domain/propval/PropertyUniqueContextEntity.java index 3ef90d4ad4..b9de9ecb12 100644 --- a/source/java/org/alfresco/repo/domain/propval/PropertyUniqueContextEntity.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyUniqueContextEntity.java @@ -31,6 +31,7 @@ public class PropertyUniqueContextEntity private Long value1PropId; private Long value2PropId; private Long value3PropId; + private Long propertyId; public PropertyUniqueContextEntity() { @@ -46,6 +47,7 @@ public class PropertyUniqueContextEntity .append(", value1PropId=").append(value1PropId) .append(", value2PropId=").append(value2PropId) .append(", value3PropId=").append(value3PropId) + .append(", propertyId=").append(propertyId) .append("]"); return sb.toString(); } @@ -111,4 +113,14 @@ public class PropertyUniqueContextEntity { this.value3PropId = value3PropId; } + + public Long getPropertyId() + { + return propertyId; + } + + public void setPropertyId(Long propId) + { + this.propertyId = propId; + } } diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java index 5f41c9a29e..3920a78471 100644 --- a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java @@ -23,7 +23,6 @@ import java.util.Date; import java.util.List; import org.alfresco.repo.domain.CrcHelper; -import org.alfresco.repo.props.PropertyUniqueConstraintViolation; import org.alfresco.util.Pair; import org.springframework.dao.DataIntegrityViolationException; @@ -273,23 +272,70 @@ public interface PropertyValueDAO // 'alf_prop_unique_ctx' accessors //================================ /** - * alf_prop_unique_ctx accessor: find an existing unique context. + * alf_prop_unique_ctx accessor: create a unique context with an optional + * associated value. *

* The DAO ensures that the region-context-value combination will be globally unique. * + * @param value1 a simple key value (not a collection) (may be null) + * @param value2 a simple key value (not a collection) (may be null) + * @param value3 a simple key value (not a collection) (may be null) + * @param propertyValue1 a value to store against the key (may be null) + * @return Returns the ID-valueId pair of the context + * * @throws PropertyUniqueConstraintViolation if the combination is not unique */ - Long createPropertyUniqueContext(Serializable value1, Serializable value2, Serializable value3); + Pair createPropertyUniqueContext( + Serializable value1, Serializable value2, Serializable value3, + Serializable propertyValue1); /** - * @see #createPropertyUniqueContext(Serializable, Serializable, Serializable) + * Get the unique context ID and associated shared property ID, or null if no + * such context exists. The associated property may be null even if the unique + * context exists. + * + * @param values a combination of one to three values in order + * @return Returns the ID-valueId pair or null if the context + * doesn't exist. + * + * @see #createPropertyUniqueContext(Serializable, Serializable, Serializable, Serializable) */ - Long getPropertyUniqueContext(Serializable value1, Serializable value2, Serializable value3); + Pair getPropertyUniqueContext(Serializable value1, Serializable value2, Serializable value3); + /** - * @see #createPropertyUniqueContext(Serializable, Serializable, Serializable) + * A callback for handling return property unique contexts */ - void updatePropertyUniqueContext(Long id, Serializable value1, Serializable value2, Serializable value3); + public interface PropertyUniqueContextCallback + { + public void handle(Long id, Long propId, Serializable[] keys); + } + /** - * @see #createPropertyUniqueContext(Serializable, Serializable, Serializable) + * Get unique contexts (unique context ID and associated shared property ID), if any, based on one, two or three context values. + * The associated property may be null even if the unique context exists. + * + * @param values a combination of one to three values in order + * + * @see #createPropertyUniqueContext(Serializable, Serializable, Serializable, Serializable) + */ + void getPropertyUniqueContext(PropertyUniqueContextCallback callback, Serializable ... values); + /** + * Update the unique context, preserving any associated property. + * + * @throws PropertyUniqueConstraintViolation if the combination is not unique + * + * @see #createPropertyUniqueContext(Serializable, Serializable, Serializable, Serializable) + */ + void updatePropertyUniqueContext( + Long id, + Serializable value1, Serializable value2, Serializable value3); + /** + * Update the property associated with a unique context. + * + * @see #createPropertyUniqueContext(Serializable, Serializable, Serializable, Serializable) + */ + void updatePropertyUniqueContext(Long id, Serializable propertyValue1); + /** + * @see #createPropertyUniqueContext(Serializable, Serializable, Serializable, Serializable) */ void deletePropertyUniqueContext(Long id); /** @@ -299,7 +345,7 @@ public interface PropertyValueDAO * @return Returns the number of unique contexts deleted */ int deletePropertyUniqueContext(Serializable ... values); - + //================================ // Utility methods //================================ diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java index 1ba93818ec..1d4e67d69a 100644 --- a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAOTest.java @@ -33,17 +33,16 @@ import javax.naming.CompositeName; import junit.framework.TestCase; import org.alfresco.repo.domain.propval.PropertyValueDAO.PropertyFinderCallback; -import org.alfresco.repo.props.PropertyUniqueConstraintViolation; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.GUID; -import org.springframework.extensions.surf.util.ISO8601DateFormat; import org.alfresco.util.Pair; import org.bouncycastle.util.Arrays; import org.springframework.context.ApplicationContext; +import org.springframework.extensions.surf.util.ISO8601DateFormat; /** * @see PropertyValueDAO @@ -441,6 +440,20 @@ public class PropertyValueDAOTest extends TestCase } } + private static enum TEST_NUMBERS + { + ONE, TWO, THREE; + } + + public void testPropertyValue_Enum() throws Exception + { + for (int i = 0; i < 3; i++) + { + TEST_NUMBERS n = TEST_NUMBERS.values()[i]; + runPropertyValueTest(n); + } + } + public void testPropertyValue_EmptyHashMap() throws Exception { final HashMap map = new HashMap(15); @@ -712,16 +725,16 @@ public class PropertyValueDAOTest extends TestCase public Void execute() throws Throwable { // Get the ID for nulls - Long nullId = propertyValueDAO.getPropertyUniqueContext(null, null, null); - if (nullId != null) + Pair nullPair = propertyValueDAO.getPropertyUniqueContext(null, null, null); + if (nullPair != null) { - propertyValueDAO.deletePropertyUniqueContext(nullId); + propertyValueDAO.deletePropertyUniqueContext(nullPair.getFirst()); } // Check nulls - propertyValueDAO.createPropertyUniqueContext(null, null, null); + propertyValueDAO.createPropertyUniqueContext(null, null, null, "A VALUE"); try { - propertyValueDAO.createPropertyUniqueContext(null, null, null); + propertyValueDAO.createPropertyUniqueContext(null, null, null, "A VALUE"); fail("Failed to throw exception creating duplicate property unique context"); } catch (PropertyUniqueConstraintViolation e) @@ -736,7 +749,7 @@ public class PropertyValueDAOTest extends TestCase { public Long execute() throws Throwable { - return propertyValueDAO.createPropertyUniqueContext("A", "AA", aaa); + return propertyValueDAO.createPropertyUniqueContext("A", "AA", aaa, null).getFirst(); } }, false); // Check that duplicates are disallowed @@ -746,7 +759,7 @@ public class PropertyValueDAOTest extends TestCase { public Void execute() throws Throwable { - propertyValueDAO.createPropertyUniqueContext("A", "AA", aaa); + propertyValueDAO.createPropertyUniqueContext("A", "AA", aaa, null); return null; } }, false); @@ -766,9 +779,9 @@ public class PropertyValueDAOTest extends TestCase // Now update it propertyValueDAO.updatePropertyUniqueContext(id, "A", "AA", bbb); // Should be able to create the previous one ... - propertyValueDAO.createPropertyUniqueContext("A", "AA", aaa); + propertyValueDAO.createPropertyUniqueContext("A", "AA", aaa, null); // ... and fail to create the second one - propertyValueDAO.createPropertyUniqueContext("A", "AA", bbb); + propertyValueDAO.createPropertyUniqueContext("A", "AA", bbb, null); return null; } }, false); @@ -784,10 +797,78 @@ public class PropertyValueDAOTest extends TestCase { // Delete propertyValueDAO.deletePropertyUniqueContext(id); - propertyValueDAO.createPropertyUniqueContext("A", "AA", bbb); + propertyValueDAO.createPropertyUniqueContext("A", "AA", bbb, null); return null; } }, false); } + + public void testPropertyUniqueContextValue() throws Exception + { + final String aaa = GUID.generate(); + final String bbb = GUID.generate(); + final String ccc = GUID.generate(); + + final String v1 = GUID.generate(); + final String v2 = GUID.generate(); + + // Create a well-known context ID + final Long id = txnHelper.doInTransaction(new RetryingTransactionCallback() + { + public Long execute() throws Throwable + { + return propertyValueDAO.createPropertyUniqueContext(aaa, bbb, ccc, null).getFirst(); + } + }, false); + Pair v0Pair = new Pair(id, null); + Pair v1Pair = new Pair(id, v1); + Pair v2Pair = new Pair(id, v2); + + // Check, assign value and recheck + Pair pair = null; + + // Check that the property is correct + pair = txnHelper.doInTransaction(new RetryingTransactionCallback>() + { + public Pair execute() throws Throwable + { + Pair pair = propertyValueDAO.getPropertyUniqueContext(aaa, bbb, ccc); + if (pair.getSecond() == null) + { + return new Pair(pair.getFirst(), null); + } + else + { + Serializable value = propertyValueDAO.getPropertyById(pair.getSecond()); + return new Pair(pair.getFirst(), value); + } + } + }, true); + assertEquals("ID-value pair incorrect", v0Pair, pair); + + pair = txnHelper.doInTransaction(new RetryingTransactionCallback>() + { + public Pair execute() throws Throwable + { + propertyValueDAO.updatePropertyUniqueContext(id, v1); + Pair pair = propertyValueDAO.getPropertyUniqueContext(aaa, bbb, ccc); + Serializable value = propertyValueDAO.getPropertyById(pair.getSecond()); + return new Pair(pair.getFirst(), value); + } + }, false); + assertEquals("ID-value pair incorrect", v1Pair, pair); + + pair = txnHelper.doInTransaction(new RetryingTransactionCallback>() + { + public Pair execute() throws Throwable + { + propertyValueDAO.updatePropertyUniqueContext(id, v2); + Pair pair = propertyValueDAO.getPropertyUniqueContext(aaa, bbb, ccc); + Serializable value = propertyValueDAO.getPropertyById(pair.getSecond()); + return new Pair(pair.getFirst(), value); + } + }, false); + assertEquals("ID-value pair incorrect", v2Pair, pair); + } } diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java b/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java index 24e5b828b2..6bcf0e4c3f 100644 --- a/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyValueEntity.java @@ -49,6 +49,7 @@ public class PropertyValueEntity public static final Short ORDINAL_STRING = 3; public static final Short ORDINAL_SERIALIZABLE = 4; public static final Short ORDINAL_CONSTRUCTABLE = 5; + public static final Short ORDINAL_ENUM = 6; /** * Enumeration of persisted types for alf_prop_value.persisted_type. @@ -138,6 +139,19 @@ public class PropertyValueEntity { return Class.class; } + }, + ENUM + { + @Override + public Short getOrdinalNumber() + { + return ORDINAL_ENUM; + } + @Override + public Class getAssociatedClass() + { + return Enum.class; + } }; /** @@ -262,6 +276,9 @@ public class PropertyValueEntity case CONSTRUCTABLE: // Construct an instance using the converter (it knows best!) return converter.constructInstance(stringValue); + case ENUM: + // The converter should handle enumeration types + return converter.convert(actualType, stringValue); default: throw new IllegalStateException("Should not be able to get through switch"); } @@ -309,6 +326,10 @@ public class PropertyValueEntity // A special case. There is no conversion, so just Store the name of the class. stringValue = value.getClass().getName(); break; + case ENUM: + // A special case. Store the string-equivalent representation + stringValue = converter.convert(String.class, value); + break; case SERIALIZABLE: serializableValue = value; break; diff --git a/source/java/org/alfresco/repo/domain/propval/ibatis/PropertyValueDAOImpl.java b/source/java/org/alfresco/repo/domain/propval/ibatis/PropertyValueDAOImpl.java index 6b5a0cc947..6503ca98ef 100644 --- a/source/java/org/alfresco/repo/domain/propval/ibatis/PropertyValueDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/propval/ibatis/PropertyValueDAOImpl.java @@ -366,6 +366,8 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl break; case CONSTRUCTABLE: // The string value is the name of the class (e.g. 'java.util.HashMap') + case ENUM: + // The string-equivalent representation case STRING: // It's best to query using the CRC and short end-value query = SELECT_PROPERTY_VALUE_BY_STRING_VALUE; @@ -416,6 +418,7 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl break; case STRING: case CONSTRUCTABLE: + case ENUM: String stringValue = insertEntity.getStringValue(); Pair insertStringPair = getOrCreatePropertyStringValue(stringValue); insertEntity.setLongValue(insertStringPair.getFirst()); @@ -518,12 +521,15 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl } @Override - protected PropertyUniqueContextEntity createPropertyUniqueContext(Long valueId1, Long valueId2, Long valueId3) + protected PropertyUniqueContextEntity createPropertyUniqueContext( + Long valueId1, Long valueId2, Long valueId3, + Long propertyId) { PropertyUniqueContextEntity entity = new PropertyUniqueContextEntity(); entity.setValue1PropId(valueId1); entity.setValue2PropId(valueId2); entity.setValue3PropId(valueId3); + entity.setPropertyId(propertyId); Long id = (Long) template.insert(INSERT_PROPERTY_UNIQUE_CTX, entity); entity.setId(id); return entity; @@ -548,6 +554,49 @@ public class PropertyValueDAOImpl extends AbstractPropertyValueDAOImpl entity = (PropertyUniqueContextEntity) template.queryForObject(SELECT_PROPERTY_UNIQUE_CTX_BY_VALUES, entity); return entity; } + + @Override + protected void getPropertyUniqueContextByValues(final PropertyUniqueContextCallback callback, Long... valueIds) + { + PropertyUniqueContextEntity entity = new PropertyUniqueContextEntity(); + for (int i = 0; i < valueIds.length; i++) + { + switch (i) + { + case 0: + entity.setValue1PropId(valueIds[i]); + break; + case 1: + entity.setValue2PropId(valueIds[i]); + break; + case 2: + entity.setValue3PropId(valueIds[i]); + break; + default: + throw new IllegalArgumentException("Only 3 ids allowed"); + } + } + + RowHandler valueRowHandler = new RowHandler() + { + public void handleRow(Object valueObject) + { + PropertyUniqueContextEntity result = (PropertyUniqueContextEntity) valueObject; + + Long id = result.getId(); + Long propId = result.getPropertyId(); + Serializable[] keys = new Serializable[3]; + keys[0] = result.getValue1PropId(); + keys[1] = result.getValue2PropId(); + keys[2] = result.getValue3PropId(); + + callback.handle(id, propId, keys); + } + }; + + template.queryWithRowHandler(SELECT_PROPERTY_UNIQUE_CTX_BY_VALUES, entity, valueRowHandler); + // Done + } @Override protected PropertyUniqueContextEntity updatePropertyUniqueContext(PropertyUniqueContextEntity entity) diff --git a/source/java/org/alfresco/repo/domain/qname/AbstractQNameDAOImpl.java b/source/java/org/alfresco/repo/domain/qname/AbstractQNameDAOImpl.java index c4e8e377b5..7910c9d90c 100644 --- a/source/java/org/alfresco/repo/domain/qname/AbstractQNameDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/qname/AbstractQNameDAOImpl.java @@ -36,7 +36,7 @@ import org.springframework.extensions.surf.util.ParameterCheck; * Abstract implementation of the QName and Namespace DAO interface. * * @author Derek Hulley - * @since 3.3 + * @since 3.4 */ public abstract class AbstractQNameDAOImpl implements QNameDAO { diff --git a/source/java/org/alfresco/repo/domain/qname/NamespaceEntity.java b/source/java/org/alfresco/repo/domain/qname/NamespaceEntity.java index 9d21277041..97e6c8cf81 100644 --- a/source/java/org/alfresco/repo/domain/qname/NamespaceEntity.java +++ b/source/java/org/alfresco/repo/domain/qname/NamespaceEntity.java @@ -24,7 +24,7 @@ import org.alfresco.util.EqualsHelper; * Entity for alf_namespace persistence. * * @author Derek Hulley - * @since 3.3 + * @since 3.4 */ public class NamespaceEntity { diff --git a/source/java/org/alfresco/repo/domain/qname/QNameDAO.java b/source/java/org/alfresco/repo/domain/qname/QNameDAO.java index 99e117ca65..b286a7e25d 100644 --- a/source/java/org/alfresco/repo/domain/qname/QNameDAO.java +++ b/source/java/org/alfresco/repo/domain/qname/QNameDAO.java @@ -29,7 +29,7 @@ import org.alfresco.util.Pair; * Data abstraction layer for QName and Namespace entities. * * @author Derek Hulley - * @since 3.3 + * @since 3.4 */ public interface QNameDAO { diff --git a/source/java/org/alfresco/repo/domain/qname/QNameDAOTest.java b/source/java/org/alfresco/repo/domain/qname/QNameDAOTest.java index 1e90da186d..46eadb146c 100644 --- a/source/java/org/alfresco/repo/domain/qname/QNameDAOTest.java +++ b/source/java/org/alfresco/repo/domain/qname/QNameDAOTest.java @@ -34,7 +34,7 @@ import org.springframework.context.ApplicationContext; * @see QNameDAO * * @author Derek Hulley - * @since 3.3 + * @since 3.4 */ public class QNameDAOTest extends TestCase { diff --git a/source/java/org/alfresco/repo/domain/qname/QNameEntity.java b/source/java/org/alfresco/repo/domain/qname/QNameEntity.java index d04a05d1e4..07eb504972 100644 --- a/source/java/org/alfresco/repo/domain/qname/QNameEntity.java +++ b/source/java/org/alfresco/repo/domain/qname/QNameEntity.java @@ -24,7 +24,7 @@ import org.alfresco.util.EqualsHelper; * Entity for alf_qname persistence. * * @author Derek Hulley - * @since 3.3 + * @since 3.4 */ public class QNameEntity { diff --git a/source/java/org/alfresco/repo/domain/qname/ibatis/QNameDAOImpl.java b/source/java/org/alfresco/repo/domain/qname/ibatis/QNameDAOImpl.java index dedceb35d6..8c05ff579b 100644 --- a/source/java/org/alfresco/repo/domain/qname/ibatis/QNameDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/qname/ibatis/QNameDAOImpl.java @@ -27,7 +27,7 @@ import org.springframework.orm.ibatis.SqlMapClientTemplate; * iBatis-specific extension of the QName and Namespace abstract DAO * * @author Derek Hulley - * @since 3.3 + * @since 3.4 */ public class QNameDAOImpl extends AbstractQNameDAOImpl { diff --git a/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java b/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java index 3298cbde95..052380b483 100644 --- a/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java +++ b/source/java/org/alfresco/repo/domain/schema/SchemaBootstrap.java @@ -714,11 +714,33 @@ public class SchemaBootstrap extends AbstractLifecycleBean { executeScriptUrl(cfg, connection, scriptUrl); } - // 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("AlfrescoSchema-" + dialectStr + "-Update-", ".sql"); - SchemaBootstrap.dumpSchemaCreate(cfg, tempFile); - executeScriptFile(cfg, connection, tempFile, null); + // Build and execute changes generated by Hibernate + 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("AlfrescoSchema-" + dialectStr + "-Update-", ".sql"); + writer = new BufferedWriter(new FileWriter(tempFile)); + for (String sql : sqls) + { + writer.append(sql); + writer.append(";\n"); + } + try {writer.close();} catch (Throwable e) {} + executeScriptFile(cfg, connection, tempFile, null); + } + } + finally + { + if (writer != null) + { + try {writer.close();} catch (Throwable e) {} + } + } // execute post-create scripts (not patches) for (String scriptUrl : this.postCreateScriptUrls) { diff --git a/source/java/org/alfresco/repo/domain/usage/AbstractUsageDAOImpl.java b/source/java/org/alfresco/repo/domain/usage/AbstractUsageDAOImpl.java new file mode 100644 index 0000000000..7a7f93ddcf --- /dev/null +++ b/source/java/org/alfresco/repo/domain/usage/AbstractUsageDAOImpl.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.usage; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.service.cmr.repository.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.util.Pair; +import org.springframework.dao.ConcurrencyFailureException; +import org.springframework.extensions.surf.util.ParameterCheck; + + +/** + * Abstract implementation for Usage DAO. + *

+ * This provides basic services such as caching, but defers to the underlying implementation + * for CRUD operations for: + * + * alf_usage_delta + * + * @author janv + * @since 3.4 + */ +public abstract class AbstractUsageDAOImpl implements UsageDAO +{ + private NodeDAO nodeDAO; + + public void setNodeDAO(NodeDAO nodeDAO) + { + this.nodeDAO = nodeDAO; + } + + private long getNodeIdNotNull(NodeRef nodeRef) + { + ParameterCheck.mandatory("nodeRef", nodeRef); + + Pair nodePair = nodeDAO.getNodePair(nodeRef); + if (nodePair == null) + { + throw new InvalidNodeRefException("Node does not exist: " + nodeRef, nodeRef); + } + return nodePair.getFirst(); + } + + private NodeRef getNodeRefNotNull(long nodeId) + { + Pair nodePair = nodeDAO.getNodePair(nodeId); + if (nodePair == null) + { + throw new AlfrescoRuntimeException("Node does not exist: " + nodeId); + } + return nodePair.getSecond(); + } + + public int deleteDeltas(NodeRef nodeRef) + { + long nodeId = getNodeIdNotNull(nodeRef); + return deleteDeltas(nodeId); + } + + public int deleteDeltas(long nodeId) + { + return deleteUsageDeltaEntitiesByNodeId(nodeId); + } + + public long getTotalDeltaSize(NodeRef nodeRef, boolean removeDeltas) + { + long nodeId = getNodeIdNotNull(nodeRef); + UsageDeltaEntity entity = selectTotalUsageDeltaSize(nodeId); + Long totalSize = entity.getDeltaSize(); + // Remove the deltas, making sure that the correct number are removed + if (removeDeltas) + { + int deleted = deleteUsageDeltaEntitiesByNodeId(nodeId); + if (entity.getDeltaCount() != null && entity.getDeltaCount().intValue() != deleted) + { + throw new ConcurrencyFailureException( + "The number of usage deltas was " + entity.getDeltaCount() + " but only " + deleted + " were deleted."); + } + } + return (totalSize != null ? totalSize : 0L); + } + + public void insertDelta(NodeRef usageNodeRef, long deltaSize) + { + long nodeId = getNodeIdNotNull(usageNodeRef); + UsageDeltaEntity entity = new UsageDeltaEntity(nodeId, deltaSize); + + insertUsageDeltaEntity(entity); + } + + public Set getUsageDeltaNodes() + { + // TODO move into nodeDAO to directly return set of nodeRefs + List nodeIds = selectUsageDeltaNodes(); + Set nodeRefs = new HashSet(nodeIds.size()); + for (Long nodeId : nodeIds) + { + nodeRefs.add(getNodeRefNotNull(nodeId)); + } + return nodeRefs; + } + + public void getUserContentSizesForStore(StoreRef storeRef, MapHandler resultsCallback) + { + selectUserContentSizesForStore(storeRef, resultsCallback); + } + + public void getUsersWithoutUsage(StoreRef storeRef, MapHandler handler) + { + selectUsersWithoutUsage(storeRef, handler); + } + + public void getUsersWithUsage(StoreRef storeRef, MapHandler handler) + { + selectUsersWithUsage(storeRef, handler); + } + + protected abstract UsageDeltaEntity insertUsageDeltaEntity(UsageDeltaEntity entity); + protected abstract UsageDeltaEntity selectTotalUsageDeltaSize(long nodeEntityId); + protected abstract List selectUsageDeltaNodes(); + protected abstract void selectUsersWithoutUsage(StoreRef storeRef, MapHandler handler); + protected abstract void selectUsersWithUsage(StoreRef storeRef, MapHandler handler); + protected abstract void selectUserContentSizesForStore(StoreRef storeRef, MapHandler resultsCallback); + protected abstract int deleteUsageDeltaEntitiesByNodeId(long nodeEntityId); +} diff --git a/source/java/org/alfresco/repo/domain/usage/UsageDAO.java b/source/java/org/alfresco/repo/domain/usage/UsageDAO.java new file mode 100644 index 0000000000..d7e29a6bcc --- /dev/null +++ b/source/java/org/alfresco/repo/domain/usage/UsageDAO.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.usage; + +import java.util.Map; +import java.util.Set; + +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; + +/** + * This provides basic services such as caching, but defers to the underlying implementation + * for CRUD operations. + * + * alf_usage_delta + * + * @since 3.4 + * @author janv + */ +public interface UsageDAO +{ + /** + * Create a usage delta entry. + * + * @param deltaSize the size change + */ + public void insertDelta(NodeRef usageNodeRef, long deltaSize); + + /** + * Get the total delta size for a node. + * + * @param nodeRef the node reference + * @param removeDeltas true to remove the deltas before returning the result. + * @return sum of delta sizes (in bytes) - can be +ve or -ve + */ + public long getTotalDeltaSize(NodeRef nodeRef, boolean removeDeltas); + + public Set getUsageDeltaNodes(); + + /** + * Delete usage deltas for given nodeRef + * + * @param nodeRef + * @return + */ + public int deleteDeltas(NodeRef nodeRef); + + /** + * Delete usage deltas for given node entity id + * + * @param nodeId + * @return + */ + public int deleteDeltas(long nodeId); + + /** + * New style content urls - Iterate and sum all content node sizes for user (owner/creator) + * + * @param storeRef the store to search in + * @param handler the callback to use while iterating over the content sizes (one row per user) + * @return Returns the values for the given owner, creator and content size (summed) + */ + public void getUserContentSizesForStore( + StoreRef storeRef, + MapHandler resultsCallback); + + /** + * Iterate over all person nodes to get users without a calculated usage + * + * @param storeRef the store to search in + * @param handler the callback to use while iterating over the people + * @return Returns the values for username and person node uuid (excluding System) + */ + public void getUsersWithoutUsage( + StoreRef storeRef, + MapHandler resultsCallback); + + /** + * Iterate over all person nodes to get users with a calculated usage + * + * @param storeRef the store to search in + * @param handler the callback to use while iterating over the people + * @return Returns the values for the username and person node uuid (excluding System) + */ + public void getUsersWithUsage( + StoreRef storeRef, + MapHandler resultsCallback); + + /** + * A callback handler for iterating over the String results + */ + public interface StringHandler + { + void handle(String string); + } + + /** + * A callback handler for iterating over the Map results + */ + public interface MapHandler + { + void handle(Map result); + } +} diff --git a/source/java/org/alfresco/repo/domain/usage/UsageDAOTest.java b/source/java/org/alfresco/repo/domain/usage/UsageDAOTest.java new file mode 100644 index 0000000000..2faff7c5f6 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/usage/UsageDAOTest.java @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.usage; + +import java.util.Set; + +import junit.framework.TestCase; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.node.ChildAssocEntity; +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.springframework.context.ApplicationContext; + +/** + * @see UsageDAO + * + * @author janv + * @since 3.4 + */ +public class UsageDAOTest extends TestCase +{ + private ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); + + private TransactionService transactionService; + private RetryingTransactionHelper txnHelper; + + private UsageDAO usageDAO; + private NodeDAO nodeDAO; + + private final static StoreRef storeRef = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore"); + + @Override + public void setUp() throws Exception + { + transactionService = (TransactionService)ctx.getBean("transactionService"); + txnHelper = transactionService.getRetryingTransactionHelper(); + + usageDAO = (UsageDAO)ctx.getBean("usageDAO"); + nodeDAO = (NodeDAO)ctx.getBean("nodeDAO"); + } + + private NodeRef getRootNodeRef() + { + return nodeDAO.getRootNode(storeRef).getSecond(); + } + + private long getNodeId(NodeRef nodeRef) + { + return nodeDAO.getNodePair(nodeRef).getFirst(); + } + + private NodeRef createNode(long parentNodeId) + { + ChildAssocEntity assoc = nodeDAO.newNode( + parentNodeId, + ContentModel.ASSOC_CHILDREN, + ContentModel.ASSOC_CHILDREN, + storeRef, + null, + ContentModel.TYPE_CONTENT, + null, + null); + + return assoc.getChildNode().getNodeRef(); + } + + public void testCreateAndDeleteUsageDeltas() throws Exception + { + RetryingTransactionCallback callback = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + NodeRef rootNodeRef = getRootNodeRef(); + long rootNodeId = getNodeId(rootNodeRef); + usageDAO.deleteDeltas(rootNodeId); +// assertEquals(0L, usageDAO.getTotalDeltaSize(rootNodeRef, false)); + + Set usageDeltaNodes = usageDAO.getUsageDeltaNodes(); + for (NodeRef nodeRef : usageDeltaNodes) + { + long nodeId = getNodeId(nodeRef); + usageDAO.deleteDeltas(nodeId); + } + + assertEquals(0, usageDAO.getUsageDeltaNodes().size()); + + usageDAO.insertDelta(rootNodeRef, 100L); + assertEquals(100L, usageDAO.getTotalDeltaSize(rootNodeRef, false)); + + assertEquals(1, usageDAO.getUsageDeltaNodes().size()); + + usageDAO.insertDelta(rootNodeRef, 1000L); + assertEquals(1100L, usageDAO.getTotalDeltaSize(rootNodeRef, false)); + + assertEquals(1, usageDAO.getUsageDeltaNodes().size()); + + usageDAO.insertDelta(rootNodeRef, -500L); + assertEquals(600L, usageDAO.getTotalDeltaSize(rootNodeRef, false)); + + assertEquals(1, usageDAO.getUsageDeltaNodes().size()); + + NodeRef nodeRef1 = createNode(rootNodeId); + long nodeId1 = getNodeId(nodeRef1); + assertEquals(0L, usageDAO.getTotalDeltaSize(nodeRef1, false)); + + NodeRef nodeRef2 = createNode(rootNodeId); + long nodeId2 = getNodeId(nodeRef2); + assertEquals(0L, usageDAO.getTotalDeltaSize(nodeRef2, false)); + + assertEquals(1, usageDAO.getUsageDeltaNodes().size()); + + usageDAO.insertDelta(nodeRef1, 200L); + assertEquals(200L, usageDAO.getTotalDeltaSize(nodeRef1, false)); + + assertEquals(2, usageDAO.getUsageDeltaNodes().size()); + + usageDAO.insertDelta(nodeRef2, -400L); + assertEquals(-400L, usageDAO.getTotalDeltaSize(nodeRef2, false)); + + assertEquals(3, usageDAO.getUsageDeltaNodes().size()); + + usageDAO.deleteDeltas(rootNodeId); + assertEquals(0L, usageDAO.getTotalDeltaSize(rootNodeRef, false)); + + assertEquals(2, usageDAO.getUsageDeltaNodes().size()); + + usageDAO.deleteDeltas(nodeId1); + assertEquals(0L, usageDAO.getTotalDeltaSize(nodeRef1, false)); + + assertEquals(1, usageDAO.getUsageDeltaNodes().size()); + + usageDAO.deleteDeltas(nodeId2); + assertEquals(0L, usageDAO.getTotalDeltaSize(nodeRef2, false)); + + assertEquals(0, usageDAO.getUsageDeltaNodes().size()); + + return null; + } + }; + + txnHelper.doInTransaction(callback); + } + + public void testCreateUsageDeltasWithRollback() throws Exception + { + RetryingTransactionCallback voidCallback = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + NodeRef rootNodeRef = getRootNodeRef(); + long rootNodeId = getNodeId(rootNodeRef); + + usageDAO.deleteDeltas(rootNodeId); + assertEquals(0L, usageDAO.getTotalDeltaSize(rootNodeRef, false)); + + Set usageDeltaNodes = usageDAO.getUsageDeltaNodes(); + for (NodeRef nodeRef : usageDeltaNodes) + { + long nodeId = getNodeId(nodeRef); + usageDAO.deleteDeltas(nodeId); + } + + assertEquals(0, usageDAO.getUsageDeltaNodes().size()); + + return null; + } + }; + + txnHelper.doInTransaction(voidCallback); + + voidCallback = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + NodeRef usageNodeRef = getRootNodeRef(); + + usageDAO.insertDelta(usageNodeRef, 100L); + + // Now force a rollback + throw new RuntimeException("Forced"); + } + }; + + try + { + txnHelper.doInTransaction(voidCallback); + fail("Transaction didn't roll back"); + } + catch (RuntimeException e) + { + // Expected + } + + // Check that it doesn't exist + voidCallback = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + NodeRef usageNodeRef = getRootNodeRef(); + + assertEquals(0L, usageDAO.getTotalDeltaSize(usageNodeRef, false)); + + assertEquals(0, usageDAO.getUsageDeltaNodes().size()); + + return null; + } + }; + + txnHelper.doInTransaction(voidCallback); + } +} diff --git a/source/java/org/alfresco/repo/domain/usage/UsageDelta.java b/source/java/org/alfresco/repo/domain/usage/UsageDelta.java new file mode 100644 index 0000000000..0b56bdd579 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/usage/UsageDelta.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.usage; + + +/** + * Interface for persistent usage delta objects. + * + */ +public interface UsageDelta +{ + public Long getNodeId(); + + public Long getDeltaSize(); +} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/usage/UsageDeltaEntity.java b/source/java/org/alfresco/repo/domain/usage/UsageDeltaEntity.java new file mode 100644 index 0000000000..baf17bfd3e --- /dev/null +++ b/source/java/org/alfresco/repo/domain/usage/UsageDeltaEntity.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.usage; + + +/** + * Usage Delta Implementation + * + */ +public class UsageDeltaEntity implements UsageDelta +{ + private Long id; + private Long version; + + private Long nodeId; + private Long deltaSize; // +ve or -ve or 0 (in bytes) + private Integer deltaCount; + + /** + * Default constructor required + */ + public UsageDeltaEntity() + { + } + + public UsageDeltaEntity(long nodeId, long deltaSize) + { + this.nodeId = nodeId; + this.deltaSize = deltaSize; + } + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public Long getVersion() + { + return version; + } + + public void setVersion(Long version) + { + this.version = version; + } + + public Long getNodeId() + { + return nodeId; + } + + public void setNodeId(Long nodeId) + { + this.nodeId = nodeId; + } + + public Long getDeltaSize() + { + return deltaSize; + } + + public void setDeltaSize(Long deltaSize) + { + this.deltaSize = deltaSize; + } + + public Integer getDeltaCount() + { + return deltaCount; + } + + public void setDeltaCount(Integer deltaCount) + { + this.deltaCount = deltaCount; + } +} diff --git a/source/java/org/alfresco/repo/domain/usage/ibatis/UsageDAOImpl.java b/source/java/org/alfresco/repo/domain/usage/ibatis/UsageDAOImpl.java new file mode 100644 index 0000000000..003f797d28 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/usage/ibatis/UsageDAOImpl.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.usage.ibatis; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.qname.QNameDAO; +import org.alfresco.repo.domain.usage.AbstractUsageDAOImpl; +import org.alfresco.repo.domain.usage.UsageDeltaEntity; +import org.alfresco.service.cmr.repository.StoreRef; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.orm.ibatis.SqlMapClientTemplate; + +import com.ibatis.sqlmap.client.event.RowHandler; + +/** + * iBatis-specific implementation of the Usage DAO. + * + * @author janv + * @since 3.4 + */ +public class UsageDAOImpl extends AbstractUsageDAOImpl +{ + private static Log logger = LogFactory.getLog(UsageDAOImpl.class); + + private static final String INSERT_USAGE_DELTA = "alfresco.usage.insert_UsageDelta"; + private static final String SELECT_USAGE_DELTA_TOTAL_SIZE_BY_NODE = "alfresco.usage.select_GetTotalDeltaSizeByNodeId"; + private static final String SELECT_USAGE_DELTA_NODES = "alfresco.usage.select_GetUsageDeltaNodes"; + private static final String SELECT_USERS_WITH_USAGE = "alfresco.usage.select_GetUsersWithUsage"; + private static final String SELECT_USERS_WITHOUT_USAGE = "alfresco.usage.select_GetUsersWithoutUsage"; + private static final String SELECT_CONTENT_SIZES_NEW = "alfresco.usage.select_GetContentSizesForStoreNew"; + private static final String DELETE_USAGE_DELTAS_BY_NODE = "alfresco.usage.delete_UsageDeltasByNodeId"; + + + private SqlMapClientTemplate template; + private QNameDAO qnameDAO; + + public void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) + { + this.template = sqlMapClientTemplate; + } + + public void setQnameDAO(QNameDAO qnameDAO) + { + this.qnameDAO = qnameDAO; + } + + @Override + protected UsageDeltaEntity insertUsageDeltaEntity(UsageDeltaEntity entity) + { + entity.setVersion(0L); + Long id = (Long)template.insert(INSERT_USAGE_DELTA, entity); + entity.setId(id); + return entity; + } + + @Override + protected UsageDeltaEntity selectTotalUsageDeltaSize(long nodeEntityId) + { + Map params = new HashMap(1); + params.put("id", nodeEntityId); + + return (UsageDeltaEntity) template.queryForObject(SELECT_USAGE_DELTA_TOTAL_SIZE_BY_NODE, params); + } + + @SuppressWarnings("unchecked") + @Override + protected List selectUsageDeltaNodes() + { + return (List) template.queryForList(SELECT_USAGE_DELTA_NODES); + } + + @Override + protected int deleteUsageDeltaEntitiesByNodeId(long nodeEntityId) + { + Map params = new HashMap(1); + params.put("id", nodeEntityId); + + return template.delete(DELETE_USAGE_DELTAS_BY_NODE, params); + } + + @Override + protected void selectUsersWithoutUsage(StoreRef storeRef, MapHandler resultsCallback) + { + long personTypeQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.TYPE_PERSON).getFirst(); + long usernamePropQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.PROP_USERNAME).getFirst(); + long sizeCurrentPropQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.PROP_SIZE_CURRENT).getFirst(); + + Map params = new HashMap(5); + params.put("personTypeQNameID", personTypeQNameEntityId); // cm:person (type) + params.put("usernamePropQNameID", usernamePropQNameEntityId); // cm:username (prop) + params.put("sizeCurrentPropQNameID", sizeCurrentPropQNameEntityId); // cm:sizeCurrent (prop) + params.put("storeProtocol", storeRef.getProtocol()); + params.put("storeIdentifier", storeRef.getIdentifier()); + + MapRowHandler rowHandler = new MapRowHandler(resultsCallback); + + template.queryWithRowHandler(SELECT_USERS_WITHOUT_USAGE, params, rowHandler); + + if (logger.isDebugEnabled()) + { + logger.debug(" Listed " + rowHandler.total + " users without usage"); + } + } + + @Override + protected void selectUsersWithUsage(StoreRef storeRef, MapHandler resultsCallback) + { + long personTypeQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.TYPE_PERSON).getFirst(); + long usernamePropQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.PROP_USERNAME).getFirst(); + long sizeCurrentPropQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.PROP_SIZE_CURRENT).getFirst(); + + Map params = new HashMap(5); + params.put("personTypeQNameID", personTypeQNameEntityId); // cm:person (type) + params.put("usernamePropQNameID", usernamePropQNameEntityId); // cm:username (prop) + params.put("sizeCurrentPropQNameID", sizeCurrentPropQNameEntityId); // cm:sizeCurrent (prop) + params.put("storeProtocol", storeRef.getProtocol()); + params.put("storeIdentifier", storeRef.getIdentifier()); + + MapRowHandler rowHandler = new MapRowHandler(resultsCallback); + + template.queryWithRowHandler(SELECT_USERS_WITH_USAGE, params, rowHandler); + + if (logger.isDebugEnabled()) + { + logger.debug(" Listed " + rowHandler.total + " users with usage"); + } + } + + @Override + protected void selectUserContentSizesForStore(StoreRef storeRef, MapHandler resultsCallback) + { + long contentTypeQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.TYPE_CONTENT).getFirst(); + long ownerPropQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.PROP_OWNER).getFirst(); + long contentPropQNameEntityId = qnameDAO.getOrCreateQName(ContentModel.PROP_CONTENT).getFirst(); + + MapRowHandler rowHandler = new MapRowHandler(resultsCallback); + + Map params = new HashMap(5); + params.put("contentTypeQNameID", contentTypeQNameEntityId); // cm:content (type) + params.put("ownerPropQNameID", ownerPropQNameEntityId); // cm:owner (prop) + params.put("contentPropQNameID", contentPropQNameEntityId); // cm:content (prop) + params.put("storeProtocol", storeRef.getProtocol()); + params.put("storeIdentifier", storeRef.getIdentifier()); + + // Query for the 'new' (FK) style content data properties (stored in 'string_value') + template.queryWithRowHandler(SELECT_CONTENT_SIZES_NEW, params, rowHandler); + + if (logger.isDebugEnabled()) + { + logger.debug(" Listed " + rowHandler.total + " old content sizes"); + } + } + + /** + * Row handler for getting map of strings + */ + private static class MapRowHandler implements RowHandler + { + private final MapHandler handler; + + private int total = 0; + + private MapRowHandler(MapHandler handler) + { + this.handler = handler; + } + + @SuppressWarnings("unchecked") + public void handleRow(Object valueObject) + { + handler.handle((Map)valueObject); + total++; + if (logger.isDebugEnabled() && (total == 0 || (total % 1000 == 0) )) + { + logger.debug(" Listed " + total + " map entries"); + } + } + } +} diff --git a/source/java/org/alfresco/repo/jscript/AVMNode.java b/source/java/org/alfresco/repo/jscript/AVMNode.java index fd6b022a43..c88bd54a5d 100644 --- a/source/java/org/alfresco/repo/jscript/AVMNode.java +++ b/source/java/org/alfresco/repo/jscript/AVMNode.java @@ -18,20 +18,17 @@ */ package org.alfresco.repo.jscript; -import java.util.HashSet; -import java.util.List; import java.util.Set; import org.alfresco.model.WCMModel; import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.cmr.avm.locking.AVMLock; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.namespace.QName; import org.alfresco.util.Pair; -import org.springframework.extensions.surf.util.ParameterCheck; import org.mozilla.javascript.Scriptable; +import org.springframework.extensions.surf.util.ParameterCheck; /** * Represents a AVM specific node in the Script context. Provides specific implementations @@ -164,9 +161,9 @@ public class AVMNode extends ScriptNode */ public boolean getIsLocked() { - AVMLock lock = this.services.getAVMLockingService().getLock( + String lockOwner = this.services.getAVMLockingService().getLockOwner( getWebProject(), path.substring(path.indexOf("/"))); - return (lock != null); + return (lockOwner != null); } /** @@ -174,17 +171,16 @@ public class AVMNode extends ScriptNode */ public boolean isLockOwner() { - boolean lockOwner = false; - - AVMLock lock = this.services.getAVMLockingService().getLock( + String lockOwner = this.services.getAVMLockingService().getLockOwner( getWebProject(), path.substring(path.indexOf("/"))); - if (lock != null) + if (lockOwner != null) { - List lockUsers = lock.getOwners(); - lockOwner = (lockUsers.contains(this.services.getAuthenticationService().getCurrentUserName())); + return lockOwner.equals(this.services.getAuthenticationService().getCurrentUserName()); + } + else + { + return true; } - - return lockOwner; } /** diff --git a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java index 0653d0724b..5af809fcc8 100644 --- a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java +++ b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java @@ -32,10 +32,11 @@ import java.util.Stack; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; +import org.alfresco.repo.rule.ruletrigger.RuleTrigger; import org.alfresco.repo.search.QueryParameterDefImpl; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.repo.transaction.TransactionalResourceHelper; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.model.FileExistsException; @@ -693,7 +694,9 @@ public class FileFolderServiceImpl implements FileFolderService // used by the rule trigger to ensure inbound rule is not triggered by a file rename // // See http://issues.alfresco.com/browse/AR-1544 - AlfrescoTransactionSupport.bindResource(sourceNodeRef.toString()+"rename", sourceNodeRef); + Set nodeRefRenameSet = TransactionalResourceHelper.getSet(RuleTrigger.RULE_TRIGGER_NODESET); + String marker = sourceNodeRef.toString()+"rename"; + nodeRefRenameSet.add(marker); return moveOrCopy(sourceNodeRef, null, newName, true); } @@ -920,27 +923,9 @@ public class FileFolderServiceImpl implements FileFolderService private FileInfo createImpl(NodeRef parentNodeRef, String name, QName typeQName, QName assocQName) throws FileExistsException { - // file or folder - boolean isFolder = false; - try - { - isFolder = isFolder(typeQName); - } - catch (InvalidTypeException e) - { - throw new AlfrescoRuntimeException("The type is not supported by this service: " + typeQName); - } - // set up initial properties Map properties = new HashMap(11); properties.put(ContentModel.PROP_NAME, (Serializable) name); - if (!isFolder) - { - // guess a mimetype based on the filename - String mimetype = mimetypeService.guessMimetype(name); - ContentData contentData = new ContentData(null, mimetype, 0L, "UTF-8"); - properties.put(ContentModel.PROP_CONTENT, contentData); - } // create the node if (assocQName == null) diff --git a/source/java/org/alfresco/repo/node/AbstractNodeServiceImpl.java b/source/java/org/alfresco/repo/node/AbstractNodeServiceImpl.java index 0eb0d66420..5ad114fece 100644 --- a/source/java/org/alfresco/repo/node/AbstractNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/AbstractNodeServiceImpl.java @@ -553,6 +553,8 @@ public abstract class AbstractNodeServiceImpl implements NodeService /** * @see NodeServicePolicies.BeforeCreateChildAssociationPolicy#beforeCreateChildAssociation(NodeRef, * NodeRef, QName, QName) + * + * @deprecated V3.3: We don't know the child node reference until the association has been created */ protected void invokeBeforeCreateChildAssociation(NodeRef parentNodeRef, NodeRef childNodeRef, QName assocTypeQName, QName assocQName, boolean isNewNode) { diff --git a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java index af62d12d95..f889238d9b 100644 --- a/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java +++ b/source/java/org/alfresco/repo/node/BaseNodeServiceTest.java @@ -2010,39 +2010,6 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest RegexQNamePattern.MATCH_ALL); } - @SuppressWarnings("unchecked") - public void testParentAssocsCacheOnNewChildAssoc() throws Exception - { - Map assocRefs = buildNodeGraph(); - final ChildAssociationRef n3pn6Ref = assocRefs.get(QName.createQName(BaseNodeServiceTest.NAMESPACE, "n3_p_n6")); - - setComplete(); - endTransaction(); - - SimpleCache parentAssocsSharedCache = - (SimpleCache) applicationContext.getBean("parentAssocsSharedCache"); - parentAssocsSharedCache.clear(); - - // Create a secondary association between two nodes - RetryingTransactionCallback testCallback = new RetryingTransactionCallback() - { - public Void execute() throws Throwable - { - nodeService.addChild( - n3pn6Ref.getParentRef(), - n3pn6Ref.getChildRef(), - ASSOC_TYPE_QNAME_TEST_CHILDREN, - QName.createQName("pathA")); - // Now get it back - ChildAssociationRef checkRef = nodeService.getPrimaryParent(n3pn6Ref.getChildRef()); - assertNotNull("ParentAssocsCache not holding primary assoc", checkRef); - assertEquals("Primary parent assoc not correct", n3pn6Ref, checkRef); - return null; - } - }; - retryingTransactionHelper.doInTransaction(testCallback, false, true); - } - public void testGetChildAssocs() throws Exception { Map assocRefs = buildNodeGraph(); diff --git a/source/java/org/alfresco/repo/node/NodeBulkLoader.java b/source/java/org/alfresco/repo/node/NodeBulkLoader.java index 9b2befd5a9..2ada888cb7 100644 --- a/source/java/org/alfresco/repo/node/NodeBulkLoader.java +++ b/source/java/org/alfresco/repo/node/NodeBulkLoader.java @@ -42,7 +42,7 @@ public interface NodeBulkLoader public void cacheNodes(List nodeRefs); /** - * Clears the cached nodes + * FOR TESTING ONLY: Clears out node cache data */ public void clear(); } diff --git a/source/java/org/alfresco/repo/node/NodeServicePolicies.java b/source/java/org/alfresco/repo/node/NodeServicePolicies.java index 7f4ca4358a..790badb7cb 100644 --- a/source/java/org/alfresco/repo/node/NodeServicePolicies.java +++ b/source/java/org/alfresco/repo/node/NodeServicePolicies.java @@ -256,6 +256,9 @@ public interface NodeServicePolicies * @param assocTypeQName the type of the association * @param assocQName the name of the association * @param isNewNode true if the node is new or false if the node is being linked in + * + * @deprecated This is not necessary and we don't know about the child node until after the + * association has been created. */ public void beforeCreateChildAssociation( NodeRef parentNodeRef, diff --git a/source/java/org/alfresco/repo/node/cleanup/AbstractNodeCleanupWorker.java b/source/java/org/alfresco/repo/node/cleanup/AbstractNodeCleanupWorker.java index 7cfa3c0468..552f126d62 100644 --- a/source/java/org/alfresco/repo/node/cleanup/AbstractNodeCleanupWorker.java +++ b/source/java/org/alfresco/repo/node/cleanup/AbstractNodeCleanupWorker.java @@ -23,8 +23,8 @@ import java.util.List; import java.util.concurrent.locks.ReentrantLock; import org.alfresco.error.StackTraceUtil; +import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.node.db.DbNodeServiceImpl; -import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; @@ -49,7 +49,7 @@ public abstract class AbstractNodeCleanupWorker implements NodeCleanupWorker private NodeCleanupRegistry registry; protected TransactionService transactionService; protected DbNodeServiceImpl dbNodeService; - protected NodeDaoService nodeDaoService; + protected NodeDAO nodeDAO; public AbstractNodeCleanupWorker() { @@ -72,9 +72,9 @@ public abstract class AbstractNodeCleanupWorker implements NodeCleanupWorker this.dbNodeService = dbNodeService; } - public void setNodeDaoService(NodeDaoService nodeDaoService) + public void setNodeDAO(NodeDAO nodeDAO) { - this.nodeDaoService = nodeDaoService; + this.nodeDAO = nodeDAO; } public void register() @@ -82,7 +82,7 @@ public abstract class AbstractNodeCleanupWorker implements NodeCleanupWorker PropertyCheck.mandatory(this, "registry", registry); PropertyCheck.mandatory(this, "transactionService", transactionService); PropertyCheck.mandatory(this, "dbNodeService", dbNodeService); - PropertyCheck.mandatory(this, "nodeDaoService", nodeDaoService); + PropertyCheck.mandatory(this, "nodeDAO", nodeDAO); registry.register(this); } diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index 0f8152b1d6..511586776c 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -34,6 +34,10 @@ import java.util.Stack; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.domain.Node; +import org.alfresco.repo.domain.node.ChildAssocEntity; +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.repo.domain.node.NodeDAO.ChildAssocRefQueryCallback; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.node.AbstractNodeServiceImpl; import org.alfresco.repo.node.StoreArchiveMap; import org.alfresco.repo.node.index.NodeIndexer; @@ -41,7 +45,6 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.TransactionalResourceHelper; 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.InvalidAspectException; import org.alfresco.service.cmr.dictionary.InvalidTypeException; @@ -64,13 +67,11 @@ import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QNamePattern; import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.util.EqualsHelper; -import org.alfresco.util.GUID; +import org.alfresco.util.Pair; +import org.alfresco.util.ParameterCheck; import org.alfresco.util.PropertyMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.alfresco.util.Pair; -import org.springframework.extensions.surf.util.ParameterCheck; -import org.springframework.util.Assert; /** * Node service using database persistence layer to fulfill functionality @@ -80,9 +81,9 @@ import org.springframework.util.Assert; 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 QNameDAO qnameDAO; + private NodeDAO nodeDAO; private StoreArchiveMap storeArchiveMap; private NodeService avmNodeService; private NodeIndexer nodeIndexer; @@ -94,9 +95,14 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl storeArchiveMap = new StoreArchiveMap(); // in case it is not set } - public void setNodeDaoService(NodeDaoService nodeDaoService) + public void setQnameDAO(QNameDAO qnameDAO) { - this.nodeDaoService = nodeDaoService; + this.qnameDAO = qnameDAO; + } + + public void setNodeDAO(NodeDAO nodeDAO) + { + this.nodeDAO = nodeDAO; } public void setStoreArchiveMap(StoreArchiveMap storeArchiveMap) @@ -137,7 +143,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { ParameterCheck.mandatory("nodeRef", nodeRef); - Pair unchecked = nodeDaoService.getNodePair(nodeRef); + Pair unchecked = nodeDAO.getNodePair(nodeRef); if (unchecked == null) { throw new InvalidNodeRefException("Node does not exist: " + nodeRef, nodeRef); @@ -147,23 +153,19 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl public boolean exists(StoreRef storeRef) { - return (nodeDaoService.getRootNode(storeRef) != null); + return nodeDAO.exists(storeRef); } public boolean exists(NodeRef nodeRef) { ParameterCheck.mandatory("nodeRef", nodeRef); - - Pair nodePair = nodeDaoService.getNodePair(nodeRef); - boolean exists = (nodePair != null); - // done - return exists; + return nodeDAO.exists(nodeRef); } public Status getNodeStatus(NodeRef nodeRef) { ParameterCheck.mandatory("nodeRef", nodeRef); - NodeRef.Status status = nodeDaoService.getNodeRefStatus(nodeRef); + NodeRef.Status status = nodeDAO.getNodeRefStatus(nodeRef); return status; } @@ -173,7 +175,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl public List getStores() { // Get the ADM stores - List> stores = nodeDaoService.getStores(); + List> stores = nodeDAO.getStores(); List storeRefs = new ArrayList(50); for (Pair pair : stores) { @@ -198,7 +200,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl invokeBeforeCreateStore(ContentModel.TYPE_STOREROOT, storeRef); // create a new one - Pair rootNodePair = nodeDaoService.createStore(storeRef); + Pair rootNodePair = nodeDAO.newStore(storeRef); NodeRef rootNodeRef = rootNodePair.getSecond(); // invoke policies @@ -222,7 +224,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl public NodeRef getRootNode(StoreRef storeRef) throws InvalidStoreRefException { - Pair rootNodePair = nodeDaoService.getRootNode(storeRef); + Pair rootNodePair = nodeDAO.getRootNode(storeRef); if (rootNodePair == null) { throw new InvalidStoreRefException("Store does not exist: " + storeRef, storeRef); @@ -244,8 +246,9 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } /** - * @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) + * {@inheritDoc} */ + @SuppressWarnings("deprecation") public ChildAssociationRef createNode( NodeRef parentRef, QName assocTypeQName, @@ -253,9 +256,10 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl QName nodeTypeQName, Map properties) { - Assert.notNull(parentRef); - Assert.notNull(assocTypeQName); - Assert.notNull(assocQName); + ParameterCheck.mandatory("parentRef", parentRef); + ParameterCheck.mandatory("assocTypeQName", assocTypeQName); + ParameterCheck.mandatory("assocQName", assocQName); + ParameterCheck.mandatory("nodeTypeQName", nodeTypeQName); // Get the parent node Pair parentNodePair = getNodePairNotNull(parentRef); @@ -267,12 +271,9 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl properties = Collections.emptyMap(); } - // get/generate an ID for the node + // get an ID for the node String newUuid = generateGuid(properties); - // Remove any system properties - extractIntrinsicProperties(properties); - /** * Check the parent node has not been deleted in this txn. */ @@ -291,54 +292,55 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl throw new InvalidTypeException(nodeTypeQName); } - // create the node instance - Pair childNodePair = nodeDaoService.newNode(parentStoreRef, newUuid, nodeTypeQName); - - // Add defaults - addDefaults(childNodePair, nodeTypeQName); - - // set the properties passed in - if (properties.size() > 0) - { - nodeDaoService.addNodeProperties(childNodePair.getFirst(), properties); - } - - Map propertiesAfter = nodeDaoService.getNodeProperties(childNodePair.getFirst()); - - // We now have enough to declare the child association creation - invokeBeforeCreateChildAssociation(parentRef, childNodePair.getSecond(), assocTypeQName, assocQName, true); - // Ensure child uniqueness - String newName = extractNameProperty(propertiesAfter); - // Create the association - Pair childAssocPair = nodeDaoService.newChildAssoc( + String newName = extractNameProperty(properties); + + // create the node instance + ChildAssocEntity assoc = nodeDAO.newNode( parentNodePair.getFirst(), - childNodePair.getFirst(), - true, assocTypeQName, assocQName, - newName); - ChildAssociationRef childAssocRef = childAssocPair.getSecond(); - + parentStoreRef, + newUuid, + nodeTypeQName, + newName, + properties); + ChildAssociationRef childAssocRef = assoc.getRef(qnameDAO); + Pair childNodePair = assoc.getChildNode().getNodePair(); + + addAspectsAndProperties( + childNodePair, + nodeTypeQName, + Collections.emptySet(), + Collections.emptyMap(), + Collections.emptySet(), + properties, + true, + false); + + Map propertiesAfter = nodeDAO.getNodeProperties(childNodePair.getFirst()); + + // We now have enough to declare the child association creation + // TODO: Remove in call + invokeBeforeCreateChildAssociation(parentRef, childNodePair.getSecond(), assocTypeQName, assocQName, true); + // Invoke policy behaviour invokeOnCreateNode(childAssocRef); invokeOnCreateChildAssociation(childAssocRef, true); - addIntrinsicProperties(childNodePair, propertiesAfter); Map propertiesBefore = PropertyMap.EMPTY_MAP; invokeOnUpdateProperties( childAssocRef.getChildRef(), propertiesBefore, propertiesAfter); - // Add missing aspects - addMissingAspects(childNodePair, propertiesBefore, propertiesAfter); - addMissingAspects(parentNodePair, assocTypeQName); - untrackDeletedNodeRef(childAssocRef.getChildRef()); // Index nodeIndexer.indexCreateNode(childAssocRef); + // Ensure that the parent node has the required aspects + addAspectsAndProperties(parentNodePair, assocTypeQName, null, null, null, null, false); + // done return childAssocRef; } @@ -398,128 +400,239 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } /** - * Adds all the default aspects and properties required for the given type. - * Existing values will not be overridden. + * Adds all the aspects and properties required for the given node, along with mandatory aspects + * and related properties. + * Existing values will not be overridden. All required pre- and post-update notifications + * are sent for missing aspects. + * + * @param nodePair the node to which the details apply + * @param classQName the type or aspect QName for which the defaults must be applied. + * This may also be an association type. If this is null + * then properties and aspects are only applied for 'extra' aspects + * and 'extra' properties. + * @param existingAspects the existing aspects or null to have them fetched + * @param existingProperties the existing properties or null to have them fetched + * @param extraAspects any aspects that should be added to the 'missing' set (may be null) + * @param extraProperties any properties that should be added the the 'missing' set (may be null) + * @param overwriteExistingProperties true if the extra properties must completely overwrite + * the existing properties + * @return true if properties or aspects were added */ - private void addDefaults(Pair nodePair, QName typeQName) - { - addDefaultProperties(nodePair, typeQName); - addDefaultAspects(nodePair, typeQName); - } - - /** - * Add the default aspects to a given node - * @return Returns true if any aspects were added - */ - private boolean addDefaultAspects(Pair nodePair, QName typeQName) - { - ClassDefinition classDefinition = dictionaryService.getClass(typeQName); - if (classDefinition == null) - { - return false; - } - // Get the existing values - Long nodeId = nodePair.getFirst(); - Map existingProperties = nodeDaoService.getNodeProperties(nodeId); - Set existingAspects = nodeDaoService.getNodeAspects(nodeId); - return addDefaultAspects(nodePair, existingAspects, existingProperties, typeQName); - } - - /** - * Add the default aspects to a given node - * @return Returns true if any aspects were added - */ - private boolean addDefaultAspects( + private boolean addAspectsAndProperties( Pair nodePair, + QName classQName, Set existingAspects, Map existingProperties, - QName typeQName) + Set extraAspects, + Map extraProperties, + boolean overwriteExistingProperties) { - ClassDefinition classDefinition = dictionaryService.getClass(typeQName); - if (classDefinition == null) - { - return false; - } - + return addAspectsAndProperties(nodePair, classQName, existingAspects, existingProperties, extraAspects, extraProperties, overwriteExistingProperties, true); + } + + private boolean addAspectsAndProperties( + Pair nodePair, + QName classQName, + Set existingAspects, + Map existingProperties, + Set extraAspects, + Map extraProperties, + boolean overwriteExistingProperties, + boolean invokeOnUpdateProperties) + { + ParameterCheck.mandatory("nodePair", nodePair); + Long nodeId = nodePair.getFirst(); NodeRef nodeRef = nodePair.getSecond(); - // get the mandatory aspects for the node type - List defaultAspectDefs = classDefinition.getDefaultAspects(); + // Ensure that have a type that has no mandatory aspects or properties + if (classQName == null) + { + classQName = ContentModel.TYPE_BASE; + } - // add all the aspects to the node - boolean added = false; - for (AspectDefinition typeDefinition : defaultAspectDefs) + // Ensure we have 'extra' aspects and properties to play with + if (extraAspects == null) { - QName aspectQName = typeDefinition.getName(); - boolean existingAspect = existingAspects.contains(aspectQName); - // Only add the aspect if it isn't there - if (!existingAspect) - { - invokeBeforeAddAspect(nodeRef, aspectQName); - nodeDaoService.addNodeAspects(nodeId, Collections.singleton(aspectQName)); - added = true; - } - // Set default properties for the aspect - addDefaultProperties(nodePair, aspectQName); - if (!existingAspect) - { - // Fire policy - invokeOnAddAspect(nodeRef, aspectQName); - } - - // Now add any default aspects for this aspect - boolean moreAdded = addDefaultAspects(nodePair, aspectQName); - added = (added || moreAdded); + extraAspects = Collections.emptySet(); } - // Done - return added; - } - - /** - * @return Returns true if any properties were added - */ - private boolean addDefaultProperties(Pair nodePair, QName typeQName) - { - ClassDefinition classDefinition = dictionaryService.getClass(typeQName); - if (classDefinition == null) + if (extraProperties == null) { - return false; + extraProperties = Collections.emptyMap(); } - // Get the existing values - Long nodeId = nodePair.getFirst(); - Map existingProperties = nodeDaoService.getNodeProperties(nodeId); - return addDefaultProperties(nodePair, existingProperties, typeQName); - } - - /** - * Adds default properties for the given type to the node. Default values will not be set if there are existing values. - */ - private boolean addDefaultProperties(Pair nodePair, Map existingProperties, QName typeQName) - { - Long nodeId = nodePair.getFirst(); - // Get the default properties for this aspect - Map defaultProperties = getDefaultProperties(typeQName); - // Remove all default values where a value already exists - for (Map.Entry entry : existingProperties.entrySet()) + + // Get the existing aspects and properties, if necessary + if (existingAspects == null) { - QName existingPropertyQName = entry.getKey(); - Serializable existingProperty = entry.getValue(); - if (existingProperty != null) - { - defaultProperties.remove(existingPropertyQName); - } + existingAspects = nodeDAO.getNodeAspects(nodeId); } - // Add the properties to the node - but only if there is anything to set - if (defaultProperties.size() > 0) + if (existingProperties == null) { - nodeDaoService.addNodeProperties(nodeId, defaultProperties); - return true; + existingProperties = nodeDAO.getNodeProperties(nodeId); + } + + // To determine the 'missing' aspects, we need to determine the full set of properties + Map allProperties = new HashMap(37); + allProperties.putAll(existingProperties); + allProperties.putAll(extraProperties); + + // Copy incoming existing values so that we can modify appropriately + existingAspects = new HashSet(existingAspects); + + // Get the 'missing' aspects and append the 'extra' aspects + Set missingAspects = getMissingAspects(existingAspects, allProperties, classQName); + missingAspects.addAll(extraAspects); + // Notify 'before' adding aspect + for (QName missingAspect : missingAspects) + { + invokeBeforeAddAspect(nodeRef, missingAspect); + } + + // Get all missing properties for aspects that are missing. + // This will include the type if the type was passed in. + Set allClassQNames = new HashSet(13); + allClassQNames.add(classQName); + allClassQNames.addAll(missingAspects); + Map missingProperties = getMissingProperties(existingProperties, allClassQNames); + missingProperties.putAll(extraProperties); + + // Bulk-add the properties + boolean changedProperties = false; + if (overwriteExistingProperties) + { + // Overwrite properties + changedProperties = nodeDAO.setNodeProperties(nodeId, missingProperties); } else { - return false; + // Append properties + changedProperties = nodeDAO.addNodeProperties(nodeId, missingProperties); } + if (changedProperties && invokeOnUpdateProperties) + { + Map propertiesAfter = nodeDAO.getNodeProperties(nodeId); + invokeOnUpdateProperties(nodeRef, existingProperties, propertiesAfter); + } + // Bulk-add the aspects + boolean changedAspects = nodeDAO.addNodeAspects(nodeId, missingAspects); + if (changedAspects) + { + for (QName missingAspect : missingAspects) + { + invokeOnAddAspect(nodeRef, missingAspect); + } + } + // Done + return changedAspects || changedProperties; + } + + /** + * Get any aspects that should be added given the type, properties and existing aspects. + * Note that this does not included a search for properties required for the missing + * aspects. + * + * @param classQName the type, aspect or association + * @return Returns any aspects that should be added + */ + private Set getMissingAspects( + Set existingAspects, + Map existingProperties, + QName classQName) + { + // Copy incoming existing values so that we can modify appropriately + existingAspects = new HashSet(existingAspects); + + ClassDefinition classDefinition = dictionaryService.getClass(classQName); + if (classDefinition == null) + { + AssociationDefinition assocDef = dictionaryService.getAssociation(classQName); + if (assocDef == null) + { + return Collections.emptySet(); + } + classDefinition = assocDef.getSourceClass(); + classQName = classDefinition.getName(); + } + + Set missingAspects = new HashSet(7); + // Check that the aspect itself is present (only applicable for aspects) + if (classDefinition.isAspect() && !existingAspects.contains(classQName)) + { + missingAspects.add(classQName); + } + + // Find all aspects that should be present on the class + List defaultAspectDefs = classDefinition.getDefaultAspects(); + for (AspectDefinition defaultAspectDef : defaultAspectDefs) + { + QName defaultAspect = defaultAspectDef.getName(); + if (!existingAspects.contains(defaultAspect)) + { + missingAspects.add(defaultAspect); + } + } + // Find all aspects that should be present given the existing properties + for (QName existingPropQName : existingProperties.keySet()) + { + PropertyDefinition existingPropDef = dictionaryService.getProperty(existingPropQName); + if (existingPropDef == null || !existingPropDef.getContainerClass().isAspect()) + { + continue; // Property is undefined or belongs to a class + } + QName existingPropDefiningType = existingPropDef.getContainerClass().getName(); + if (!existingAspects.contains(existingPropDefiningType)) + { + missingAspects.add(existingPropDefiningType); + } + } + // If there were missing aspects, recurse to find further missing aspects + // Don't re-add ones we know about or we can end in infinite recursion. + // Don't send any properties because we don't want to reprocess them each time + Set allTypesAndAspects = new HashSet(13); + allTypesAndAspects.add(classQName); + allTypesAndAspects.addAll(existingAspects); + allTypesAndAspects.addAll(missingAspects); + Set missingAspectsCopy = new HashSet(missingAspects); + for (QName missingAspect : missingAspectsCopy) + { + Set furtherMissingAspects = getMissingAspects( + allTypesAndAspects, + Collections.emptyMap(), + missingAspect); + missingAspects.addAll(furtherMissingAspects); + allTypesAndAspects.addAll(furtherMissingAspects); + } + // Done + return missingAspects; + } + + /** + * @param existingProperties existing node properties + * @param classQNames the types or aspects to introspect + * @return Returns any properties that should be added + */ + private Map getMissingProperties(Map existingProperties, Set classQNames) + { + Map allDefaultProperties = new HashMap(17); + for (QName classQName : classQNames) + { + ClassDefinition classDefinition = dictionaryService.getClass(classQName); + if (classDefinition == null) + { + continue; + } + // Get the default properties for this type/aspect + Map defaultProperties = getDefaultProperties(classQName); + if (defaultProperties.size() > 0) + { + allDefaultProperties.putAll(defaultProperties); + } + } + // Work out what is missing + Map missingProperties = new HashMap(allDefaultProperties); + missingProperties.entrySet().removeAll(existingProperties.entrySet()); + // Done + return missingProperties; } public void setChildAssociationIndex(ChildAssociationRef childAssocRef, int index) @@ -533,36 +646,23 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl QName assocTypeQName = childAssocRef.getTypeQName(); QName assocQName = childAssocRef.getQName(); - Pair assocPair = nodeDaoService.getChildAssoc( - parentNodeId, - childNodeId, - assocTypeQName, - assocQName); - if (assocPair == null) + // set the index + int updated = nodeDAO.setChildAssocIndex( + parentNodeId, childNodeId, assocTypeQName, assocQName, index); + if (updated < 1) { - throw new InvalidChildAssociationRefException("Unable to set child association index: \n" + + throw new InvalidChildAssociationRefException( + "Unable to set child association index: \n" + " assoc: " + childAssocRef + "\n" + " index: " + index, childAssocRef); } - // Get the child node name - Map childNodeProperties = nodeDaoService.getNodeProperties(childNodeId); - String childNodeName = extractNameProperty(childNodeProperties); - // set the index - nodeDaoService.updateChildAssoc( - assocPair.getFirst(), - parentNodeId, - childNodeId, - assocTypeQName, - assocQName, - index, - childNodeName); } public QName getType(NodeRef nodeRef) throws InvalidNodeRefException { Pair nodePair = getNodePairNotNull(nodeRef); - return nodeDaoService.getNodeType(nodePair.getFirst()); + return nodeDAO.getNodeType(nodePair.getFirst()); } /** @@ -582,10 +682,10 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl invokeBeforeUpdateNode(nodeRef); // Set the type - nodeDaoService.updateNode(nodePair.getFirst(), null, null, typeQName); + nodeDAO.updateNode(nodePair.getFirst(), null, null, typeQName); // Add the default aspects and properties required for the given type. Existing values will not be overridden. - addDefaults(nodePair, typeQName); + addAspectsAndProperties(nodePair, typeQName, null, null, null, null, false); // Index nodeIndexer.indexUpdateNode(nodeRef); @@ -611,12 +711,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } // Check the properties - if (aspectProperties != null) - { - // Remove any system properties - extractIntrinsicProperties(aspectProperties); - } - else + if (aspectProperties == null) { // Make a map aspectProperties = Collections.emptyMap(); @@ -624,31 +719,27 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Make the properties immutable to be sure that they are not used incorrectly aspectProperties = Collections.unmodifiableMap(aspectProperties); - Pair nodePair = getNodePairNotNull(nodeRef); - Long nodeId = nodePair.getFirst(); - // Invoke policy behaviours invokeBeforeUpdateNode(nodeRef); - invokeBeforeAddAspect(nodeRef, aspectTypeQName); - // Add defaults - addDefaults(nodePair, aspectTypeQName); + // Add aspect and defaults + Pair nodePair = getNodePairNotNull(nodeRef); + boolean modified = addAspectsAndProperties( + nodePair, + aspectTypeQName, + null, + null, + Collections.singleton(aspectTypeQName), + aspectProperties, + false); - if (aspectProperties.size() > 0) - { - nodeDaoService.addNodeProperties(nodeId, aspectProperties); - } - - if (!nodeDaoService.hasNodeAspect(nodeId, aspectTypeQName)) + if (modified) { // Invoke policy behaviours invokeOnUpdateNode(nodeRef); - invokeOnAddAspect(nodeRef, aspectTypeQName); - nodeDaoService.addNodeAspects(nodeId, Collections.singleton(aspectTypeQName)); + // Index + nodeIndexer.indexUpdateNode(nodeRef); } - - // Index - nodeIndexer.indexUpdateNode(nodeRef); } public void removeAspect(NodeRef nodeRef, QName aspectTypeQName) @@ -661,14 +752,14 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl final Pair nodePair = getNodePairNotNull(nodeRef); final Long nodeId = nodePair.getFirst(); - boolean hadAspect = nodeDaoService.hasNodeAspect(nodeId, aspectTypeQName); + boolean hadAspect = nodeDAO.hasNodeAspect(nodeId, aspectTypeQName); // Invoke policy behaviours invokeBeforeUpdateNode(nodeRef); if (hadAspect) { invokeBeforeRemoveAspect(nodeRef, aspectTypeQName); - nodeDaoService.removeNodeAspects(nodeId, Collections.singleton(aspectTypeQName)); + nodeDAO.removeNodeAspects(nodeId, Collections.singleton(aspectTypeQName)); } AspectDefinition aspectDef = dictionaryService.getAspect(aspectTypeQName); @@ -678,13 +769,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Remove default properties Map propertyDefs = aspectDef.getProperties(); Set propertyToRemoveQNames = propertyDefs.keySet(); - nodeDaoService.removeNodeProperties(nodeId, propertyToRemoveQNames); + nodeDAO.removeNodeProperties(nodeId, propertyToRemoveQNames); // Remove child associations // We have to iterate over the associations and remove all those between the parent and child final List> assocsToDelete = new ArrayList>(5); final List> nodesToDelete = new ArrayList>(5); - NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback() + NodeDAO.ChildAssocRefQueryCallback callback = new NodeDAO.ChildAssocRefQueryCallback() { public boolean handle( Pair childAssocPair, @@ -702,8 +793,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { assocsToDelete.add(childAssocPair); } - // No recurse - return false; + // More results + return true; } public boolean preLoadNodes() @@ -712,8 +803,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } }; // Get all the QNames to remove - List assocTypeQNamesToRemove = new ArrayList(aspectDef.getChildAssociations().keySet()); - nodeDaoService.getChildAssocsByTypeQNames(nodeId, assocTypeQNamesToRemove, callback); + Set assocTypeQNamesToRemove = new HashSet(aspectDef.getChildAssociations().keySet()); + nodeDAO.getChildAssocs(nodeId, assocTypeQNamesToRemove, callback); // Delete all the collected associations for (Pair assocPair : assocsToDelete) { @@ -722,7 +813,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl ChildAssociationRef assocRef = assocPair.getSecond(); // delete the association instance - it is not primary invokeBeforeDeleteChildAssociation(assocRef); - nodeDaoService.deleteChildAssoc(assocId); + nodeDAO.deleteChildAssoc(assocId); invokeOnDeleteChildAssociation(assocRef); } @@ -735,20 +826,18 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Remove regular associations Map nodeAssocDefs = aspectDef.getAssociations(); - Collection> nodeAssocPairs = nodeDaoService.getNodeAssocsToAndFrom(nodeId); - for (Pair nodeAssocPair : nodeAssocPairs) + Set nodeAssocTypeQNamesToRemove = new HashSet(13); + for (Map.Entry entry : nodeAssocDefs.entrySet()) { - updated = true; - QName nodeAssocTypeQName = nodeAssocPair.getSecond().getTypeQName(); - // Ignore if the association type is not defined by the aspect - if (!nodeAssocDefs.containsKey(nodeAssocTypeQName)) + if (entry.getValue().isChild()) { + // Not interested in child assocs continue; } - updated = true; - // It has to be removed - nodeDaoService.deleteNodeAssoc(nodeAssocPair.getFirst()); + nodeAssocTypeQNamesToRemove.add(entry.getKey()); } + int assocsDeleted = nodeDAO.removeNodeAssocsToAndFrom(nodeId, nodeAssocTypeQNamesToRemove); + updated = updated || assocsDeleted > 0; } // Invoke policy behaviours @@ -771,13 +860,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl public boolean hasAspect(NodeRef nodeRef, QName aspectQName) throws InvalidNodeRefException, InvalidAspectException { Pair nodePair = getNodePairNotNull(nodeRef); - return nodeDaoService.hasNodeAspect(nodePair.getFirst(), aspectQName); + return nodeDAO.hasNodeAspect(nodePair.getFirst(), aspectQName); } public Set getAspects(NodeRef nodeRef) throws InvalidNodeRefException { Pair nodePair = getNodePairNotNull(nodeRef); - return nodeDaoService.getNodeAspects(nodePair.getFirst()); + return nodeDAO.getNodeAspects(nodePair.getFirst()); } /** @@ -792,11 +881,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Boolean requiresDelete = null; // get the primary parent-child relationship before it is gone - Pair childAssocPair = nodeDaoService.getPrimaryParentAssoc(nodeId); + Pair childAssocPair = nodeDAO.getPrimaryParentAssoc(nodeId); ChildAssociationRef childAssocRef = childAssocPair.getSecond(); // get type and aspect QNames as they will be unavailable after the delete - QName nodeTypeQName = nodeDaoService.getNodeType(nodeId); - Set nodeAspectQNames = nodeDaoService.getNodeAspects(nodeId); + QName nodeTypeQName = nodeDAO.getNodeType(nodeId); + Set nodeAspectQNames = nodeDAO.getNodeAspects(nodeId); StoreRef storeRef = nodeRef.getStoreRef(); StoreRef archiveStoreRef = storeArchiveMap.get(storeRef); @@ -857,7 +946,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Cascade delecte as required deletePrimaryChildrenNotArchived(nodePair); // perform a normal deletion - nodeDaoService.deleteNode(nodeId); + nodeDAO.deleteNode(nodeId); // Invoke policy behaviours invokeOnDeleteNode(childAssocRef, nodeTypeQName, nodeAspectQNames, false); @@ -888,7 +977,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl final List> childNodePairs = new ArrayList>(5); final Map childAssocRefsByChildId = new HashMap(5); - NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback() + NodeDAO.ChildAssocRefQueryCallback callback = new NodeDAO.ChildAssocRefQueryCallback() { public boolean handle( Pair childAssocPair, @@ -899,8 +988,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Add it childNodePairs.add(childNodePair); childAssocRefsByChildId.put(childNodePair.getFirst(), childAssocPair.getSecond()); - // No recurse - return false; + // More results + return true; } public boolean preLoadNodes() @@ -910,15 +999,15 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl }; // Get all the QNames to remove - nodeDaoService.getPrimaryChildAssocs(nodeId, callback); + nodeDAO.getChildAssocs(nodeId, null, null, null, Boolean.TRUE, null, callback); // Each child must be deleted for (Pair childNodePair : childNodePairs) { // Fire node policies. This ensures that each node in the hierarchy gets a notification fired. Long childNodeId = childNodePair.getFirst(); NodeRef childNodeRef = childNodePair.getSecond(); - QName childNodeType = nodeDaoService.getNodeType(childNodeId); - Set childNodeQNames = nodeDaoService.getNodeAspects(childNodeId); + QName childNodeType = nodeDAO.getNodeType(childNodeId); + Set childNodeQNames = nodeDAO.getNodeAspects(childNodeId); ChildAssociationRef childParentAssocRef = childAssocRefsByChildId.get(childNodeId); // remove the deleted node from the list of new nodes @@ -934,7 +1023,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // the actual delete starts. deletePrimaryChildrenNotArchived(childNodePair); // Delete the child - nodeDaoService.deleteNode(childNodeId); + nodeDAO.deleteNode(childNodeId); invokeOnDeleteNode(childParentAssocRef, childNodeType, childNodeQNames, false); // lose interest in tracking this node ref @@ -952,8 +1041,12 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // Get the node's name, if present Pair childNodePair = getNodePairNotNull(childRef); Long childNodeId = childNodePair.getFirst(); - Map childNodeProperties = nodeDaoService.getNodeProperties(childNodePair.getFirst()); + Map childNodeProperties = nodeDAO.getNodeProperties(childNodePair.getFirst()); String childNodeName = extractNameProperty(childNodeProperties); + if (childNodeName == null) + { + childNodeName = childRef.getId(); + } List childAssociationRefs = new ArrayList(parentRefs.size()); List> parentNodePairs = new ArrayList>(parentRefs.size()); @@ -971,10 +1064,10 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl invokeBeforeCreateChildAssociation(parentRef, childRef, assocTypeQName, assocQName, false); // make the association - Pair childAssocPair = nodeDaoService.newChildAssoc(parentNodeId, childNodeId, - false, assocTypeQName, assocQName, childNodeName); - // ensure name uniqueness - setChildNameUnique(childAssocPair, childNodePair); + Pair childAssocPair = nodeDAO.newChildAssoc( + parentNodeId, childNodeId, + assocTypeQName, assocQName, + childNodeName); childAssociationRefs.add(childAssocPair.getSecond()); } @@ -989,10 +1082,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl invokeOnCreateChildAssociation(childAssocRef, false); } - // Add missing aspects + // Get the type associated with the association + // The association may be sourced on an aspect, which may itself mandate further aspects for (Pair parentNodePair : parentNodePairs) { - addMissingAspects(parentNodePair, assocTypeQName); + addAspectsAndProperties(parentNodePair, assocTypeQName, null, null, null, null, false); } // Index @@ -1012,7 +1106,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl final Long childNodeId = childNodePair.getFirst(); // Get the primary parent association for the child - Pair primaryChildAssocPair = nodeDaoService.getPrimaryParentAssoc(childNodeId); + Pair primaryChildAssocPair = nodeDAO.getPrimaryParentAssoc(childNodeId); // We can shortcut if our parent is also the primary parent if (primaryChildAssocPair != null) { @@ -1027,22 +1121,22 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // We have to iterate over the associations and remove all those between the parent and child final List> assocsToDelete = new ArrayList>(5); - NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback() + NodeDAO.ChildAssocRefQueryCallback callback = new NodeDAO.ChildAssocRefQueryCallback() { public boolean handle( Pair childAssocPair, Pair parentNodePair, Pair childNodePair) { - // Ignore if the child is not ours + // Ignore if the child is not ours (redundant check) if (!childNodePair.getFirst().equals(childNodeId)) { return false; } // Add it assocsToDelete.add(childAssocPair); - // No recurse - return false; + // More results + return true; } public boolean preLoadNodes() @@ -1050,7 +1144,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl return true; } }; - nodeDaoService.getChildAssocs(parentNodeId, callback, false); + nodeDAO.getChildAssocs(parentNodeId, childNodeId, null, null, null, null, callback); // Delete all the collected associations for (Pair assocPair : assocsToDelete) @@ -1059,7 +1153,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl ChildAssociationRef assocRef = assocPair.getSecond(); // delete the association instance - it is not primary invokeBeforeDeleteChildAssociation(assocRef); - nodeDaoService.deleteChildAssoc(assocId); + nodeDAO.deleteChildAssoc(assocId); invokeOnDeleteChildAssociation(assocRef); // Index @@ -1075,7 +1169,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Long childNodeId = getNodePairNotNull(childAssocRef.getChildRef()).getFirst(); QName assocTypeQName = childAssocRef.getTypeQName(); QName assocQName = childAssocRef.getQName(); - Pair assocPair = nodeDaoService.getChildAssoc( + Pair assocPair = nodeDAO.getChildAssoc( parentNodeId, childNodeId, assocTypeQName, assocQName); if (assocPair == null) { @@ -1096,7 +1190,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { // Delete the association invokeBeforeDeleteChildAssociation(childAssocRef); - nodeDaoService.deleteChildAssoc(assocId); + nodeDAO.deleteChildAssoc(assocId); invokeOnDeleteChildAssociation(childAssocRef); // Index nodeIndexer.indexDeleteChildAssociation(childAssocRef); @@ -1111,7 +1205,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Long childNodeId = getNodePairNotNull(childAssocRef.getChildRef()).getFirst(); QName assocTypeQName = childAssocRef.getTypeQName(); QName assocQName = childAssocRef.getQName(); - Pair assocPair = nodeDaoService.getChildAssoc( + Pair assocPair = nodeDAO.getChildAssoc( parentNodeId, childNodeId, assocTypeQName, assocQName); if (assocPair == null) { @@ -1127,7 +1221,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl " Child Assoc: " + assocRef); } // Delete the secondary association - nodeDaoService.deleteChildAssoc(assocId); + nodeDAO.deleteChildAssoc(assocId); invokeOnDeleteChildAssociation(childAssocRef); // Index nodeIndexer.indexDeleteChildAssociation(childAssocRef); @@ -1135,50 +1229,6 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl return true; } - /** - * Remove properties that should not be persisted as general properties. Where necessary, the - * properties are set on the node. - * - * @param node the node to set properties on - * @param properties properties to change - */ - private void extractIntrinsicProperties(Map properties) - { - properties.remove(ContentModel.PROP_STORE_PROTOCOL); - properties.remove(ContentModel.PROP_STORE_IDENTIFIER); - properties.remove(ContentModel.PROP_NODE_UUID); - properties.remove(ContentModel.PROP_NODE_DBID); - } - - /** - * Adds all properties used by the - * {@link ContentModel#ASPECT_REFERENCEABLE referencable aspect}. - *

- * This method can be used to ensure that the values used by the aspect - * are present as node properties. - *

- * This method also ensures that the {@link ContentModel#PROP_NAME name property} - * is always present as a property on a node. - * - * @param node the node with the values - * @param nodeRef the node reference containing the values required - * @param properties the node properties - */ - private void addIntrinsicProperties(Pair nodePair, Map properties) - { - Long nodeId = nodePair.getFirst(); - NodeRef nodeRef = nodePair.getSecond(); - properties.put(ContentModel.PROP_STORE_PROTOCOL, nodeRef.getStoreRef().getProtocol()); - properties.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier()); - properties.put(ContentModel.PROP_NODE_UUID, nodeRef.getId()); - properties.put(ContentModel.PROP_NODE_DBID, nodeId); - // add the ID as the name, if required - if (properties.get(ContentModel.PROP_NAME) == null) - { - properties.put(ContentModel.PROP_NAME, nodeRef.getId()); - } - } - public Serializable getProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException { Long nodeId = getNodePairNotNull(nodeRef).getFirst(); @@ -1200,7 +1250,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl return nodeId; } - Serializable property = nodeDaoService.getNodeProperty(nodeId, qname); + Serializable property = nodeDAO.getNodeProperty(nodeId, qname); // check if we need to provide a spoofed name if (property == null && qname.equals(ContentModel.PROP_NAME)) @@ -1224,101 +1274,35 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl private Map getPropertiesImpl(Pair nodePair) throws InvalidNodeRefException { Long nodeId = nodePair.getFirst(); - Map nodeProperties = nodeDaoService.getNodeProperties(nodeId); - // spoof referencable properties - addIntrinsicProperties(nodePair, nodeProperties); + Map nodeProperties = nodeDAO.getNodeProperties(nodeId); // done return nodeProperties; } /** - * Find any aspects that are missing for the node, given the properties before and after an update. + * Performs additional tasks associated with setting a property. + * + * @return Returns true if any work was done by this method */ - private void addMissingAspects( - Pair nodePair, - Map propertiesBefore, - Map propertiesAfter) + private boolean setPropertiesCommonWork(Pair nodePair, Map properties) { Long nodeId = nodePair.getFirst(); - NodeRef nodeRef = nodePair.getSecond(); - Set aspectQNamesToAdd = new HashSet(5); - Set newProperties = new HashSet(propertiesAfter.keySet()); - newProperties.removeAll(propertiesBefore.entrySet()); - Set existingAspectsQNames = nodeDaoService.getNodeAspects(nodeId); - for (QName newPropertyQName : newProperties) + + boolean changed = false; + // cm:name special handling + if (properties.containsKey(ContentModel.PROP_NAME)) { - PropertyDefinition propDef = dictionaryService.getProperty(newPropertyQName); - if (propDef == null) + String name = extractNameProperty(properties); + Pair primaryParentAssocPair = nodeDAO.getPrimaryParentAssoc(nodeId); + if (primaryParentAssocPair != null) { - continue; // Ignore undefined properties - } - if (!propDef.getContainerClass().isAspect()) - { - continue; - } - QName containerClassQName = propDef.getContainerClass().getName(); - // Remove this aspect - it is there - if (existingAspectsQNames.contains(containerClassQName)) - { - // Already there - continue; - } - aspectQNamesToAdd.add(containerClassQName); - } - // Add the aspects and any missing, default properties - if (aspectQNamesToAdd.size() > 0) - { - for (QName aspectQNameToAdd : aspectQNamesToAdd) - { - invokeBeforeAddAspect(nodeRef, aspectQNameToAdd); - } - nodeDaoService.addNodeAspects(nodeId, aspectQNamesToAdd); - // Add the aspects and then their appropriate default values. - for (QName aspectQNameToAdd : aspectQNamesToAdd) - { - addDefaultProperties(nodePair, propertiesAfter, aspectQNameToAdd); - addDefaultAspects(nodePair, aspectQNameToAdd); - } - for (QName aspectQNameToAdd : aspectQNamesToAdd) - { - invokeOnAddAspect(nodeRef, aspectQNameToAdd); + String oldName = extractNameProperty(nodeDAO.getNodeProperties(nodeId)); + String newName = DefaultTypeConverter.INSTANCE.convert(String.class, name); + changed = setChildNameUnique(nodePair, newName, oldName); } } - } - - /** - * Find any aspects that are missing for the node, given the association type. - */ - private void addMissingAspects( - Pair nodePair, - QName assocTypeQName) - { - Long nodeId = nodePair.getFirst(); - NodeRef nodeRef = nodePair.getSecond(); - Set existingAspectsQNames = nodeDaoService.getNodeAspects(nodeId); - AssociationDefinition assocDef = dictionaryService.getAssociation(assocTypeQName); - if (assocDef == null) - { - return; // Ignore undefined properties - } - if (!assocDef.getSourceClass().isAspect()) - { - return; - } - QName aspectQNameToAdd = assocDef.getSourceClass().getName(); - // Remove this aspect - it is there - if (existingAspectsQNames.contains(aspectQNameToAdd)) - { - // Already there - return; - } - // Add the aspects and any missing, default properties - invokeBeforeAddAspect(nodeRef, aspectQNameToAdd); - nodeDaoService.addNodeAspects(nodeId, Collections.singleton(aspectQNameToAdd)); - // Add the aspects and then their appropriate default values. - addDefaultProperties(nodePair, aspectQNameToAdd); - addDefaultAspects(nodePair, aspectQNameToAdd); - invokeOnAddAspect(nodeRef, aspectQNameToAdd); + // Done + return changed; } /** @@ -1329,65 +1313,38 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl */ public void setProperty(NodeRef nodeRef, QName qname, Serializable value) throws InvalidNodeRefException { - Assert.notNull(qname); + ParameterCheck.mandatory("nodeRef", nodeRef); + ParameterCheck.mandatory("qname", qname); - // get the node - Pair nodePair = getNodePairNotNull(nodeRef); - Long nodeId = nodePair.getFirst(); - - // Ensure that we are not setting intrinsic properties - Map properties = new HashMap(1, 1.0F); - properties.put(qname, value); - extractIntrinsicProperties(properties); - - // Shortcut if nothing is left - if (properties.size() == 0) - { - return; - } - - // Get the properties from before - Map propertiesBefore = getPropertiesImpl(nodePair); - - invokeBeforeUpdateNode(nodeRef); - // Update the properties - setPropertyImpl(nodeId, qname, value); - // Policy callbacks - Map propertiesAfter = getPropertiesImpl(nodePair); - invokeOnUpdateNode(nodeRef); - invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter); - - // Add any missing aspects - addMissingAspects(nodePair, propertiesBefore, propertiesAfter); - - // Index - nodeIndexer.indexUpdateNode(nodeRef); - } - - /** - * Sets the property, taking special care to handle intrinsic properties and cm:name properly - */ - private void setPropertyImpl(Long nodeId, QName qname, Serializable value) - { + // The UUID cannot be explicitly changed if (qname.equals(ContentModel.PROP_NODE_UUID)) { throw new IllegalArgumentException("The node UUID cannot be changed."); } - else + + // get the node + Pair nodePair = getNodePairNotNull(nodeRef); + + // Invoke policy behaviour + invokeBeforeUpdateNode(nodeRef); + + // cm:name special handling + setPropertiesCommonWork( + nodePair, + Collections.singletonMap(qname, value)); + + // Add the property and all required defaults + boolean changed = addAspectsAndProperties( + nodePair, null, + null, null, + null, Collections.singletonMap(qname, value), false); + + if (changed) { - // cm:name special handling - if (qname.equals(ContentModel.PROP_NAME)) - { - Pair primaryParentAssocPair = nodeDaoService.getPrimaryParentAssoc(nodeId); - if (primaryParentAssocPair != null) - { - String oldName = extractNameProperty(nodeDaoService.getNodeProperties(nodeId)); - String newName = DefaultTypeConverter.INSTANCE.convert(String.class, value); - setChildNameUnique(primaryParentAssocPair, newName, oldName); - } - } - // Set the property - nodeDaoService.addNodeProperty(nodeId, qname, value); + // Invoke policy behaviour + invokeOnUpdateNode(nodeRef); + // Index + nodeIndexer.indexUpdateNode(nodeRef); } } @@ -1406,76 +1363,45 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl public void setProperties(NodeRef nodeRef, Map properties) throws InvalidNodeRefException { Pair nodePair = getNodePairNotNull(nodeRef); - Long nodeId = nodePair.getFirst(); - extractIntrinsicProperties(properties); - // Invoke policy behaviours - Map propertiesBefore = getPropertiesImpl(nodePair); invokeBeforeUpdateNode(nodeRef); - // Do the set properties - setPropertiesImpl(nodeId, properties); - - // Invoke policy behaviours - Map propertiesAfter = getPropertiesImpl(nodePair); - invokeOnUpdateNode(nodeRef); - invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter); + // SetProperties common tasks + setPropertiesCommonWork(nodePair, properties); - // Add any missing aspects - addMissingAspects(nodePair, propertiesBefore, propertiesAfter); + // Set properties and defaults, overwriting the existing properties + boolean changed = addAspectsAndProperties(nodePair, null, null, null, null, properties, true); - // Index - nodeIndexer.indexUpdateNode(nodeRef); + if (changed) + { + // Invoke policy behaviours + invokeOnUpdateNode(nodeRef); + // Index + nodeIndexer.indexUpdateNode(nodeRef); + } } public void addProperties(NodeRef nodeRef, Map properties) throws InvalidNodeRefException { Pair nodePair = getNodePairNotNull(nodeRef); - Long nodeId = nodePair.getFirst(); - extractIntrinsicProperties(properties); - // Invoke policy behaviours - Map propertiesBefore = getPropertiesImpl(nodePair); invokeBeforeUpdateNode(nodeRef); - // Change each property - for (Map.Entry entry : properties.entrySet()) - { - QName propertyQName = entry.getKey(); - Serializable propertyValue = entry.getValue(); - setPropertyImpl(nodeId, propertyQName, propertyValue); - } + // cm:name special handling + setPropertiesCommonWork(nodePair, properties); - // Invoke policy behaviours - Map propertiesAfter = getPropertiesImpl(nodePair); - invokeOnUpdateNode(nodeRef); - invokeOnUpdateProperties(nodeRef, propertiesBefore, propertiesAfter); + // Add properties and defaults + boolean changed = addAspectsAndProperties(nodePair, null, null, null, null, properties, false); - // Add any missing aspects - addMissingAspects(nodePair, propertiesBefore, propertiesAfter); - - // Index - nodeIndexer.indexUpdateNode(nodeRef); - } - - private void setPropertiesImpl(Long nodeId, Map properties) - { - // Get the cm:name and uuid for special handling - if (properties.containsKey(ContentModel.PROP_NAME)) + if (changed) { - Serializable name = properties.get(ContentModel.PROP_NAME); - setPropertyImpl(nodeId, ContentModel.PROP_NAME, name); + // Invoke policy behaviours + invokeOnUpdateNode(nodeRef); + // Index + nodeIndexer.indexUpdateNode(nodeRef); } - if (properties.containsKey(ContentModel.PROP_NODE_UUID)) - { - throw new IllegalArgumentException("The node UUID cannot be set"); - } - // Now remove special properties - extractIntrinsicProperties(properties); - // Update the node - nodeDaoService.setNodeProperties(nodeId, properties); } public void removeProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException @@ -1493,14 +1419,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl // cm:name special handling if (qname.equals(ContentModel.PROP_NAME)) { - Pair primaryParentAssocPair = nodeDaoService.getPrimaryParentAssoc(nodeId); - String oldName = extractNameProperty(nodeDaoService.getNodeProperties(nodeId)); + String oldName = extractNameProperty(nodeDAO.getNodeProperties(nodeId)); String newName = null; - setChildNameUnique(primaryParentAssocPair, newName, oldName); + setChildNameUnique(nodePair, newName, oldName); } // Remove - nodeDaoService.removeNodeProperties(nodeId, Collections.singleton(qname)); + nodeDAO.removeNodeProperties(nodeId, Collections.singleton(qname)); // Invoke policy behaviours Map propertiesAfter = getPropertiesImpl(nodePair); @@ -1513,48 +1438,66 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl public Collection getParents(NodeRef nodeRef) throws InvalidNodeRefException { - // Get the node - Pair nodePair = getNodePairNotNull(nodeRef); - Long nodeId = nodePair.getFirst(); + List parentAssocs = getParentAssocs( + nodeRef, + RegexQNamePattern.MATCH_ALL, + RegexQNamePattern.MATCH_ALL); - // Get the assocs pointing to it - Collection> parentAssocPairs = nodeDaoService.getParentAssocs(nodeId); - // list of results - Collection results = new ArrayList(parentAssocPairs.size()); - for (Pair assocPair : parentAssocPairs) + // Copy into the set to avoid duplicates + Set parentNodeRefs = new HashSet(parentAssocs.size()); + for (ChildAssociationRef parentAssoc : parentAssocs) { - NodeRef parentNodeRef = assocPair.getSecond().getParentRef(); - results.add(parentNodeRef); + NodeRef parentNodeRef = parentAssoc.getParentRef(); + parentNodeRefs.add(parentNodeRef); } - // done - return results; + // Done + return new ArrayList(parentNodeRefs); } /** * Filters out any associations if their qname is not a match to the given pattern. */ - public List getParentAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern) + public List getParentAssocs( + final NodeRef nodeRef, + final QNamePattern typeQNamePattern, + final QNamePattern qnamePattern) { // Get the node Pair nodePair = getNodePairNotNull(nodeRef); Long nodeId = nodePair.getFirst(); - // Get the assocs pointing to it - Collection> parentAssocPairs = nodeDaoService.getParentAssocs(nodeId); - // list of results - List results = new ArrayList(parentAssocPairs.size()); - for (Pair assocPair : parentAssocPairs) + final List results = new ArrayList(10); + // We have a callback handler to filter results + ChildAssocRefQueryCallback callback = new ChildAssocRefQueryCallback() { - ChildAssociationRef assocRef = assocPair.getSecond(); - QName assocTypeQName = assocRef.getTypeQName(); - QName assocQName = assocRef.getQName(); - if (!qnamePattern.isMatch(assocQName) || !typeQNamePattern.isMatch(assocTypeQName)) + public boolean preLoadNodes() { - // No match - continue; + return false; } - results.add(assocRef); - } + + public boolean handle( + Pair childAssocPair, + Pair parentNodePair, + Pair childNodePair) + { + if (!typeQNamePattern.isMatch(childAssocPair.getSecond().getTypeQName())) + { + return true; + } + if (!qnamePattern.isMatch(childAssocPair.getSecond().getQName())) + { + return true; + } + results.add(childAssocPair.getSecond()); + return true; + } + }; + + // Get the assocs pointing to it + QName typeQName = (typeQNamePattern instanceof QName) ? (QName) typeQNamePattern : null; + QName qname = (qnamePattern instanceof QName) ? (QName) qnamePattern : null; + + nodeDAO.getParentAssocs(nodeId, typeQName, qname, null, callback); // done return results; } @@ -1570,154 +1513,51 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl /** * Filters out any associations if their qname is not a match to the given pattern. */ - public List getChildAssocs(NodeRef nodeRef, final QNamePattern typeQNamePattern, final QNamePattern qnamePattern, final boolean preload) + public List getChildAssocs( + NodeRef nodeRef, + final QNamePattern typeQNamePattern, + final QNamePattern qnamePattern, + final boolean preload) { // Get the node Pair nodePair = getNodePairNotNull(nodeRef); Long nodeId = nodePair.getFirst(); - final List results = new ArrayList(100); - - abstract class BaseCallback implements NodeDaoService.ChildAssocRefQueryCallback + final List results = new ArrayList(10); + // We have a callback handler to filter results + ChildAssocRefQueryCallback callback = new ChildAssocRefQueryCallback() { public boolean preLoadNodes() { return preload; } - } - - if (qnamePattern instanceof QName) - { - // Both explicit QNames - if (typeQNamePattern instanceof QName) - { - NodeDaoService.ChildAssocRefQueryCallback callback = new BaseCallback() - { - public boolean handle(Pair childAssocPair, - Pair parentNodePair, Pair childNodePair) - { - results.add(childAssocPair.getSecond()); - return false; - } - }; - // Get all child associations with the specific qualified name - nodeDaoService.getChildAssocsByTypeQNameAndQName(nodeId, (QName) typeQNamePattern, - (QName) qnamePattern, callback); - } - // Type is explicit, local qname is pattern - else - { - NodeDaoService.ChildAssocRefQueryCallback callback; - if (typeQNamePattern.equals(RegexQNamePattern.MATCH_ALL)) - { - callback = new BaseCallback() - { - public boolean handle(Pair childAssocPair, - Pair parentNodePair, Pair childNodePair) - { - results.add(childAssocPair.getSecond()); - return false; - } - }; - } - else - { - callback = new BaseCallback() - { - public boolean handle(Pair childAssocPair, - Pair parentNodePair, Pair childNodePair) - { - ChildAssociationRef assocRef = childAssocPair.getSecond(); - QName assocTypeQName = assocRef.getTypeQName(); - if (!typeQNamePattern.isMatch(assocTypeQName)) - { - // No match - return false; - } - results.add(assocRef); - return false; - } - }; - - } - - // Get all child associations with the specific qualified name - nodeDaoService.getChildAssocs(nodeId, (QName) qnamePattern, callback); - } - } - else - { - // Local qname is pattern, type name is explicit - if (typeQNamePattern instanceof QName) - { - NodeDaoService.ChildAssocRefQueryCallback callback; - // if the type is the wildcard type, and the qname is not a search, then use a shortcut query - if (qnamePattern.equals(RegexQNamePattern.MATCH_ALL)) - { - callback = new BaseCallback() - { - public boolean handle(Pair childAssocPair, - Pair parentNodePair, Pair childNodePair) - { - results.add(childAssocPair.getSecond()); - return false; - } - }; - } - else - { - - callback = new BaseCallback() - { - public boolean handle(Pair childAssocPair, - Pair parentNodePair, Pair childNodePair) - { - ChildAssociationRef assocRef = childAssocPair.getSecond(); - QName assocQName = assocRef.getQName(); - if (!qnamePattern.isMatch(assocQName)) - { - // No match - return false; - } - results.add(assocRef); - return false; - } - }; - } - - // Get all child associations with the specific type qualified name - nodeDaoService.getChildAssocsByTypeQNames(nodeId, Collections.singletonList((QName) typeQNamePattern), - callback); - - } - // Local qname is pattern, type name is pattern - else - { - NodeDaoService.ChildAssocRefQueryCallback callback = new BaseCallback() - { - public boolean handle(Pair childAssocPair, - Pair parentNodePair, Pair childNodePair) - { - ChildAssociationRef assocRef = childAssocPair.getSecond(); - QName assocTypeQName = assocRef.getTypeQName(); - QName assocQName = assocRef.getQName(); - if (!qnamePattern.isMatch(assocQName) || !typeQNamePattern.isMatch(assocTypeQName)) - { - // No match - return false; - } - results.add(assocRef); - return false; - } - }; - // Get all child associations - nodeDaoService.getChildAssocs(nodeId, callback, false); - } - } + public boolean handle( + Pair childAssocPair, + Pair parentNodePair, + Pair childNodePair) + { + if (!typeQNamePattern.isMatch(childAssocPair.getSecond().getTypeQName())) + { + return true; + } + if (!qnamePattern.isMatch(childAssocPair.getSecond().getQName())) + { + return true; + } + results.add(childAssocPair.getSecond()); + return true; + } + }; + + // Get the assocs pointing to it + QName typeQName = (typeQNamePattern instanceof QName) ? (QName) typeQNamePattern : null; + QName qname = (qnamePattern instanceof QName) ? (QName) qnamePattern : null; + + nodeDAO.getChildAssocs(nodeId, null, typeQName, qname, null, null, callback); // sort the results List orderedList = reorderChildAssocs(results); - // done + // Done return orderedList; } @@ -1729,7 +1569,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl final List results = new ArrayList(100); - NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback() + NodeDAO.ChildAssocRefQueryCallback callback = new NodeDAO.ChildAssocRefQueryCallback() { public boolean handle( Pair childAssocPair, @@ -1737,7 +1577,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Pair childNodePair) { results.add(childAssocPair.getSecond()); - return false; + // More results + return true; } public boolean preLoadNodes() @@ -1746,7 +1587,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } }; // Get all child associations with the specific qualified name - nodeDaoService.getChildAssocsByChildTypes(nodeId, childNodeTypeQNames, callback); + nodeDAO.getChildAssocsByChildTypes(nodeId, childNodeTypeQNames, callback); // Sort the results List orderedList = reorderChildAssocs(results); // Done @@ -1783,7 +1624,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Pair nodePair = getNodePairNotNull(nodeRef); Long nodeId = nodePair.getFirst(); - Pair childAssocPair = nodeDaoService.getChildAssoc(nodeId, assocTypeQName, childName); + Pair childAssocPair = nodeDAO.getChildAssoc(nodeId, assocTypeQName, childName); if (childAssocPair != null) { return childAssocPair.getSecond().getChildRef(); @@ -1802,7 +1643,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl final List results = new ArrayList(100); - NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback() + NodeDAO.ChildAssocRefQueryCallback callback = new NodeDAO.ChildAssocRefQueryCallback() { public boolean handle( Pair childAssocPair, @@ -1810,7 +1651,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Pair childNodePair) { results.add(childAssocPair.getSecond()); - return false; + // More results + return true; } public boolean preLoadNodes() @@ -1819,7 +1661,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } }; // Get all child associations with the specific qualified name - nodeDaoService.getChildAssocs(nodeId, assocTypeQName, childNames, callback); + nodeDAO.getChildAssocs(nodeId, assocTypeQName, childNames, callback); // Sort the results List orderedList = reorderChildAssocs(results); // Done @@ -1833,7 +1675,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Long nodeId = nodePair.getFirst(); // get the primary parent assoc - Pair assocPair = nodeDaoService.getPrimaryParentAssoc(nodeId); + Pair assocPair = nodeDAO.getPrimaryParentAssoc(nodeId); // done - the assoc may be null for a root node ChildAssociationRef assocRef = null; @@ -1857,14 +1699,14 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl long targetNodeId = targetNodePair.getFirst(); // we are sure that the association doesn't exist - make it - Pair assocPair = nodeDaoService.newNodeAssoc(sourceNodeId, targetNodeId, assocTypeQName); - AssociationRef assocRef = assocPair.getSecond(); + Long assocId = nodeDAO.newNodeAssoc(sourceNodeId, targetNodeId, assocTypeQName); + AssociationRef assocRef = new AssociationRef(assocId, sourceRef, assocTypeQName, targetRef); // Invoke policy behaviours invokeOnCreateAssociation(assocRef); // Add missing aspects - addMissingAspects(sourceNodePair, assocTypeQName); + addAspectsAndProperties(sourceNodePair, assocTypeQName, null, null, null, null, false); return assocRef; } @@ -1877,12 +1719,13 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl final List results = new ArrayList(100); - NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback() + NodeDAO.ChildAssocRefQueryCallback callback = new NodeDAO.ChildAssocRefQueryCallback() { public boolean handle(Pair childAssocPair, Pair parentNodePair, Pair childNodePair) { results.add(childAssocPair.getSecond()); + // More results return true; } @@ -1893,7 +1736,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl }; // Get the child associations that meet the criteria - nodeDaoService.getChildAssocsWithoutParentAssocsOfType(parentNodeId, assocTypeQName, callback); + nodeDAO.getChildAssocsWithoutParentAssocsOfType(parentNodeId, assocTypeQName, callback); // done return results; @@ -1907,25 +1750,21 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Pair targetNodePair = getNodePairNotNull(targetRef); long targetNodeId = targetNodePair.getFirst(); - // get the association - Pair assocPair = nodeDaoService.getNodeAssoc(sourceNodeId, targetNodeId, assocTypeQName); - if (assocPair == null) - { - // nothing to remove - return; - } - AssociationRef assocRef = assocPair.getSecond(); - // delete it - nodeDaoService.deleteNodeAssoc(assocPair.getFirst()); + int assocsDeleted = nodeDAO.removeNodeAssoc(sourceNodeId, targetNodeId, assocTypeQName); - // Invoke policy behaviours - invokeOnDeleteAssociation(assocRef); + if (assocsDeleted > 0) + { + AssociationRef assocRef = new AssociationRef(sourceRef, assocTypeQName, targetRef); + // Invoke policy behaviours + invokeOnDeleteAssociation(assocRef); + } } public AssociationRef getAssoc(Long id) { - return nodeDaoService.getNodeAssocOrNull(id); + throw new UnsupportedOperationException("TODO: Implement the method for the new DAO implementation."); +// return nodeDaoService.getNodeAssocOrNull(id); } public List getTargetAssocs(NodeRef sourceRef, QNamePattern qnamePattern) @@ -1934,7 +1773,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl long sourceNodeId = sourceNodePair.getFirst(); // get all assocs to target - Collection> assocPairs = nodeDaoService.getTargetNodeAssocs(sourceNodeId); + Collection> assocPairs = nodeDAO.getTargetNodeAssocs(sourceNodeId); List nodeAssocRefs = new ArrayList(assocPairs.size()); for (Pair assocPair : assocPairs) { @@ -1956,7 +1795,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl long targetNodeId = targetNodePair.getFirst(); // get all assocs to target - Collection> assocPairs = nodeDaoService.getSourceNodeAssocs(targetNodeId); + Collection> assocPairs = nodeDAO.getSourceNodeAssocs(targetNodeId); List nodeAssocRefs = new ArrayList(assocPairs.size()); for (Pair assocPair : assocPairs) { @@ -1995,50 +1834,17 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { // get the starting node Pair nodePair = getNodePairNotNull(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 assocIdStack = new Stack(); - // call recursive method to sort it out - nodeDaoService.prependPaths(nodePair, null, currentPath, paths, assocIdStack, 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; + return nodeDAO.getPaths(nodePair, primaryOnly); } private void archiveNode(NodeRef nodeRef, StoreRef archiveStoreRef) { Pair nodePair = getNodePairNotNull(nodeRef); Long nodeId = nodePair.getFirst(); - Pair primaryParentAssocPair = nodeDaoService.getPrimaryParentAssoc(nodeId); + Pair primaryParentAssocPair = nodeDAO.getPrimaryParentAssoc(nodeId); Set newAspects = new HashSet(5); - Map existingProperties = nodeDaoService.getNodeProperties(nodeId); + Map existingProperties = nodeDAO.getNodeProperties(nodeId); Map newProperties = new HashMap(11); // add the aspect @@ -2060,11 +1866,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl newProperties.put(ContentModel.PROP_OWNER, AuthenticationUtil.getFullyAuthenticatedUser()); // Set the aspects and properties - nodeDaoService.addNodeProperties(nodeId, newProperties); - nodeDaoService.addNodeAspects(nodeId, newAspects); + nodeDAO.addNodeProperties(nodeId, newProperties); + nodeDAO.addNodeAspects(nodeId, newAspects); // move the node - Pair archiveStoreRootNodePair = nodeDaoService.getRootNode(archiveStoreRef); + Pair archiveStoreRootNodePair = nodeDAO.getRootNode(archiveStoreRef); moveNode( nodeRef, archiveStoreRootNodePair.getSecond(), @@ -2076,9 +1882,9 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { Pair archivedNodePair = getNodePairNotNull(archivedNodeRef); Long archivedNodeId = archivedNodePair.getFirst(); - Set existingAspects = nodeDaoService.getNodeAspects(archivedNodeId); + Set existingAspects = nodeDAO.getNodeAspects(archivedNodeId); Set newAspects = new HashSet(5); - Map existingProperties = nodeDaoService.getNodeProperties(archivedNodeId); + Map existingProperties = nodeDAO.getNodeProperties(archivedNodeId); Map newProperties = new HashMap(11); // the node must be a top-level archive node @@ -2095,8 +1901,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl removePropertyQNames.add(ContentModel.PROP_ARCHIVED_BY); removePropertyQNames.add(ContentModel.PROP_ARCHIVED_DATE); removePropertyQNames.add(ContentModel.PROP_ARCHIVED_ORIGINAL_OWNER); - nodeDaoService.removeNodeProperties(archivedNodeId, removePropertyQNames); - nodeDaoService.removeNodeAspects(archivedNodeId, Collections.singleton(ContentModel.ASPECT_ARCHIVED)); + nodeDAO.removeNodeProperties(archivedNodeId, removePropertyQNames); + nodeDAO.removeNodeAspects(archivedNodeId, Collections.singleton(ContentModel.ASPECT_ARCHIVED)); // restore the original ownership if (originalOwner != null) @@ -2161,7 +1967,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Pair parentNodePair = getNodePairNotNull(newParentRef); Long nodeToMoveId = nodeToMovePair.getFirst(); - QName nodeToMoveTypeQName = nodeDaoService.getNodeType(nodeToMoveId); + QName nodeToMoveTypeQName = nodeDAO.getNodeType(nodeToMoveId); NodeRef oldNodeToMoveRef = nodeToMovePair.getSecond(); Long parentNodeId = parentNodePair.getFirst(); NodeRef parentNodeRef = parentNodePair.getSecond(); @@ -2171,13 +1977,12 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Pair newNodeToMovePair = new Pair(nodeToMoveId, newNodeToMoveRef); // Get the primary parent association - Pair oldParentAssocPair = nodeDaoService.getPrimaryParentAssoc(nodeToMoveId); + Pair oldParentAssocPair = nodeDAO.getPrimaryParentAssoc(nodeToMoveId); if (oldParentAssocPair == null) { // The node doesn't have parent. Moving it is not possible. throw new IllegalArgumentException("Node " + nodeToMoveId + " doesn't have a parent. Use 'addChild' instead of move."); } - Long oldParentAssocId = oldParentAssocPair.getFirst(); ChildAssociationRef oldParentAssocRef = oldParentAssocPair.getSecond(); // Shortcut this whole process if nothing has changed @@ -2190,11 +1995,6 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } boolean movingStore = !oldStoreRef.equals(newStoreRef); - // Handle store conflicts - if (movingStore) - { - handleStoreMoveConflicts(nodeToMovePair, newStoreRef); - } // Invoke "Before"policy behaviour if (movingStore) @@ -2214,29 +2014,12 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl invokeBeforeCreateChildAssociation(newParentRef, nodeToMoveRef, assocTypeQName, assocQName, false); } - // Handle store moves - if (movingStore) - { - Pair newNodePair = nodeDaoService.moveNodeToStore(nodeToMoveId, newStoreRef); - if (!newNodePair.equals(newNodeToMovePair)) - { - throw new RuntimeException("Store-moved pair isn't expected: " + newNodePair + " != " + newNodeToMovePair); - } - } - - // Get the new node's cm:name - Map newNodeProperties = nodeDaoService.getNodeProperties(nodeToMoveId); - String newNodeChildName = extractNameProperty(newNodeProperties); - // Modify the association directly. We do this AFTER the change of the node's store so that - // the association reference returned is correct. - Pair newParentAssocPair = nodeDaoService.updateChildAssoc( - oldParentAssocId, - parentNodeId, + // Move node under the new parent + Pair newParentAssocPair = nodeDAO.moveNode( nodeToMoveId, + parentNodeId, assocTypeQName, - assocQName, - -1, - newNodeChildName); + assocQName); ChildAssociationRef newParentAssocRef = newParentAssocPair.getSecond(); // Handle indexing differently if it is a store move @@ -2252,20 +2035,17 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl nodeIndexer.indexUpdateChildAssociation(oldParentAssocRef, newParentAssocRef); } - // Ensure name uniqueness - setChildNameUnique(newParentAssocPair, newNodeToMovePair); - - // Check that there is not a cyclic relationship - getPaths(newNodeToMoveRef, false); - // Call behaviours if (movingStore) { - Set nodeToMoveAspectQNames = nodeDaoService.getNodeAspects(nodeToMoveId); + Set nodeToMoveAspectQNames = nodeDAO.getNodeAspects(nodeToMoveId); // The Node changes NodeRefs, so this is really the deletion of the old node and creation // of a node in a new store as far as the clients are concerned. invokeOnDeleteNode(oldParentAssocRef, nodeToMoveTypeQName, nodeToMoveAspectQNames, true); invokeOnCreateNode(newParentAssocRef); + + // Pull children to the new store + pullNodeChildrenToSameStore(newNodeToMovePair); } else { @@ -2274,44 +2054,20 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl invokeOnMoveNode(oldParentAssocRef, newParentAssocRef); } - // Pull children to the new store - pullNodeChildrenToSameStore(newNodeToMovePair, true); - // Done return newParentAssocRef; } - /** - * Silently gives any clashing target nodes a new UUID - * @param nodeToMovePair the node that will be moved - * @param newStoreRef the store that the node will be moved to - */ - private void handleStoreMoveConflicts(Pair nodeToMovePair, StoreRef newStoreRef) - { - NodeRef oldNodeToMoveRef = nodeToMovePair.getSecond(); - NodeRef newNodeToMoveRef = new NodeRef(newStoreRef, oldNodeToMoveRef.getId()); - // If the new node reference is already taken, then give it a new uuid - Pair conflictingNodePair = nodeDaoService.getNodePair(newNodeToMoveRef); - if (conflictingNodePair != null) - { - // We are creating a new node. This noderef will be reused, so will be an update - nodeDaoService.updateNode(conflictingNodePair.getFirst(), null, GUID.generate(), null); - } - } - /** * This process is less invasive than the move method as the child associations - * do not need to be remade. If the children are in the same store, only the indexChildren - * value is needed. + * do not need to be remade. */ - private void pullNodeChildrenToSameStore(Pair nodePair, boolean indexChildren) + private void pullNodeChildrenToSameStore(Pair nodePair) { Long nodeId = nodePair.getFirst(); - NodeRef nodeRef = nodePair.getSecond(); - StoreRef storeRef = nodeRef.getStoreRef(); // Get the node's children, but only one's that aren't in the same store final List> childNodePairs = new ArrayList>(5); - NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback() + NodeDAO.ChildAssocRefQueryCallback callback = new NodeDAO.ChildAssocRefQueryCallback() { public boolean handle( Pair childAssocPair, @@ -2321,7 +2077,8 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { // Add it childNodePairs.add(childNodePair); - return false; + // More results + return true; } public boolean preLoadNodes() @@ -2330,21 +2087,21 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl } }; // We only need to move child nodes that are not already in the same store - nodeDaoService.getPrimaryChildAssocsNotInSameStore(nodeId, callback); + nodeDAO.getChildAssocs(nodeId, null, null, null, Boolean.TRUE, Boolean.FALSE, callback); // Each child must be moved to the same store as the parent for (Pair oldChildNodePair : childNodePairs) { Long childNodeId = oldChildNodePair.getFirst(); NodeRef childNodeRef = oldChildNodePair.getSecond(); - if (nodeDaoService.getNodeRefStatus(childNodeRef).isDeleted()) + if (nodeDAO.getNodeRefStatus(childNodeRef).isDeleted()) { // Node has already been deleted. continue; } - QName childNodeTypeQName = nodeDaoService.getNodeType(childNodeId); - Set childNodeAspectQNames = nodeDaoService.getNodeAspects(childNodeId); - Pair oldParentAssocPair = nodeDaoService.getPrimaryParentAssoc(childNodeId); + QName childNodeTypeQName = nodeDAO.getNodeType(childNodeId); + Set childNodeAspectQNames = nodeDAO.getNodeAspects(childNodeId); + Pair oldParentAssocPair = nodeDAO.getPrimaryParentAssoc(childNodeId); Pair newChildNodePair = oldChildNodePair; Pair newParentAssocPair = oldParentAssocPair; ChildAssociationRef newParentAssocRef = newParentAssocPair.getSecond(); @@ -2362,80 +2119,18 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl newParentAssocRef.getTypeQName(), newParentAssocRef.getQName(), childNodeTypeQName); - // Move the node - handleStoreMoveConflicts(oldChildNodePair, storeRef); - // Change the store - newChildNodePair = nodeDaoService.moveNodeToStore(oldChildNodePair.getFirst(), storeRef); - // Get the new parent assoc - newParentAssocPair = nodeDaoService.getPrimaryParentAssoc(childNodeId); + // Move the node as this gives back the primary parent association + newParentAssocPair = nodeDAO.moveNode(childNodeId, nodeId, null,null); // Index - if (indexChildren) - { - nodeIndexer.indexCreateNode(newParentAssocPair.getSecond()); - } - else - { - // The node we have just moved doesn't have it's children indexed, so tag it - nodeDaoService.addNodeAspects(childNodeId, Collections.singleton(ContentModel.ASPECT_INDEX_CHILDREN)); - } + nodeIndexer.indexCreateNode(newParentAssocPair.getSecond()); // Fire node policies. This ensures that each node in the hierarchy gets a notification fired. invokeOnDeleteNode(oldParentAssocPair.getSecond(), childNodeTypeQName, childNodeAspectQNames, true); invokeOnCreateNode(newParentAssocPair.getSecond()); // Cascade - pullNodeChildrenToSameStore(newChildNodePair, indexChildren); + pullNodeChildrenToSameStore(newChildNodePair); } } - public void indexChildren(Pair nodePair, boolean cascade) - { - Long nodeId = nodePair.getFirst(); - // Get the node's children, but only one's that aren't in the same store - final List> childNodePairs = new ArrayList>(5); - NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback() - { - public boolean handle( - Pair childAssocPair, - Pair parentNodePair, - Pair childNodePair - ) - { - // Add it - childNodePairs.add(childNodePair); - return false; - } - - public boolean preLoadNodes() - { - return true; - } - }; - - nodeDaoService.getPrimaryChildAssocs(nodeId, callback); - // Each child must be moved to the same store as the parent - for (Pair oldChildNodePair : childNodePairs) - { - Long childNodeId = oldChildNodePair.getFirst(); - NodeRef oldChildNodeRef = oldChildNodePair.getSecond(); - Pair newChildNodePair = oldChildNodePair; - // Touch the node child node so that index tracking will work - nodeDaoService.setNodeStatus(childNodeId); - // Index - nodeIndexer.indexUpdateNode(oldChildNodeRef); - // Cascade, if required - if (cascade) - { - indexChildren(newChildNodePair, cascade); - } - else - { - // We didn't cascade to the children, so tag the node to index the children later - nodeDaoService.addNodeAspects(childNodeId, Collections.singleton(ContentModel.ASPECT_INDEX_CHILDREN)); - } - } - // We have indexed the children, so remove the tagging aspect - nodeDaoService.removeNodeAspects(nodeId, Collections.singleton(ContentModel.ASPECT_INDEX_CHILDREN)); - } - public NodeRef getStoreArchiveNode(StoreRef storeRef) { StoreRef archiveStoreRef = storeArchiveMap.get(storeRef); @@ -2457,41 +2152,29 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl return name; } - private void setChildNameUnique(Pair childAssocPair, Pair childNodePair) - { - // Get the node's existing name - Serializable nameValue = nodeDaoService.getNodeProperty(childNodePair.getFirst(), ContentModel.PROP_NAME); - String name = (String) DefaultTypeConverter.INSTANCE.convert(String.class, nameValue); - setChildNameUnique(childAssocPair, name, null); - } - /** * Ensures name uniqueness for the child and the child association. Note that nothing is done if the * association type doesn't enforce name uniqueness. + * + * @return Returns true if the child association cm:name was written */ - private void setChildNameUnique(Pair childAssocPair, String newName, String oldName) + private boolean setChildNameUnique(Pair childNodePair, String newName, String oldName) { - if (childAssocPair == null) + if (newName == null) { - // This happens if the node is a root node - return; + newName = childNodePair.getSecond().getId(); // Use the node's GUID } - else if (EqualsHelper.nullSafeEquals(newName, oldName)) + Long childNodeId = childNodePair.getFirst(); + + if (EqualsHelper.nullSafeEquals(newName, oldName)) { // The name has not changed - return; + return false; } - Long assocId = childAssocPair.getFirst(); - QName assocTypeQName = childAssocPair.getSecond().getTypeQName(); - AssociationDefinition assocDef = dictionaryService.getAssociation(assocTypeQName); - if (!assocDef.isChild()) + else { - throw new IllegalArgumentException("Child association has non-child type: " + assocId); - } - ChildAssociationDefinition childAssocDef = (ChildAssociationDefinition) assocDef; - if (!childAssocDef.getDuplicateChildNamesAllowed()) - { - nodeDaoService.setChildNameUnique(assocId, newName); + nodeDAO.setChildAssocsUniqueName(childNodeId, newName); + return true; } } } diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java index dd17bc7775..56b29b9c0f 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImplTest.java @@ -19,7 +19,6 @@ package org.alfresco.repo.node.db; import java.io.Serializable; -import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; @@ -28,25 +27,20 @@ import java.util.Set; import javax.transaction.UserTransaction; -import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.model.ContentModel; -import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.node.BaseNodeServiceTest; -import org.alfresco.repo.node.db.NodeDaoService.NodePropertyHandler; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.MLText; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.Pair; -import org.apache.commons.lang.mutable.MutableInt; +import org.springframework.extensions.surf.util.I18NUtil; /** * @see org.alfresco.repo.node.db.DbNodeServiceImpl @@ -57,7 +51,7 @@ import org.apache.commons.lang.mutable.MutableInt; public class DbNodeServiceImplTest extends BaseNodeServiceTest { private TransactionService txnService; - private NodeDaoService nodeDaoService; + private NodeDAO nodeDAO; private DictionaryService dictionaryService; protected NodeService getNodeService() @@ -73,7 +67,7 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest { super.onSetUpInTransaction(); txnService = (TransactionService) applicationContext.getBean("transactionComponent"); - nodeDaoService = (NodeDaoService) applicationContext.getBean("nodeDaoService"); + nodeDAO = (NodeDAO) applicationContext.getBean("nodeDAO"); dictionaryService = (DictionaryService) applicationContext.getBean("dictionaryService"); } @@ -206,13 +200,13 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest public Object execute() { // check n6 - NodeRef.Status n6Status = nodeDaoService.getNodeRefStatus(n6Ref); + NodeRef.Status n6Status = nodeDAO.getNodeRefStatus(n6Ref); if (!n6Status.isDeleted()) { throw new RuntimeException("Deleted node does not have deleted status"); } // n8 is a primary child - it should be deleted too - NodeRef.Status n8Status = nodeDaoService.getNodeRefStatus(n8Ref); + NodeRef.Status n8Status = nodeDAO.getNodeRefStatus(n8Ref); if (!n8Status.isDeleted()) { throw new RuntimeException("Cascade-deleted node does not have deleted status"); @@ -350,32 +344,6 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest assertEquals("Setting of MLText over String failed.", mlText, mlTextCheck); } - public void testDuplicatePrimaryParentHandling() throws Exception - { - Map assocRefs = buildNodeGraph(); - // get the node to play with - ChildAssociationRef n1pn3Ref = assocRefs.get(QName.createQName(BaseNodeServiceTest.NAMESPACE, "n1_p_n3")); - ChildAssociationRef n6pn8Ref = assocRefs.get(QName.createQName(BaseNodeServiceTest.NAMESPACE, "n6_p_n8")); - final NodeRef n1Ref = n1pn3Ref.getParentRef(); - final NodeRef n8Ref = n6pn8Ref.getChildRef(); - - // Add a make n1 a second primary parent of n8 - Pair n1Pair = nodeDaoService.getNodePair(n1Ref); - Pair n8Pair = nodeDaoService.getNodePair(n8Ref); - Pair assocPair = nodeDaoService.newChildAssoc( - n1Pair.getFirst(), - n8Pair.getFirst(), - true, - ContentModel.ASSOC_CONTAINS, - QName.createQName(NAMESPACE, "n1pn8"), - null); - - // Now get the node primary parent - nodeService.getPrimaryParent(n8Ref); - // Get it again - nodeService.getPrimaryParent(n8Ref); - } - /** * It would appear that an issue has arisen with creating and deleting nodes * in the same transaction. @@ -392,33 +360,6 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest nodeService.deleteNode(nodeRef); } - /** - * Adds a property to a node and checks that it can be found using the low-level DB query - */ - public void testGetPropertyValuesByPropertyAndValue() throws Throwable - { - String findMeValue = "FIND ME"; - nodeService.setProperty(rootNodeRef, PROP_QNAME_STRING_PROP_SINGLE, findMeValue); - final MutableInt count = new MutableInt(0); - // Add a property to the root node and check - NodePropertyHandler handler = new NodePropertyHandler() - { - public void handle(NodeRef nodeRef, QName nodeTypeQName, QName propertyQName, Serializable value) - { - if (nodeTypeQName.equals(ContentModel.TYPE_STOREROOT)) - { - count.setValue(1); - } - } - }; - nodeDaoService.getPropertyValuesByPropertyAndValue( - rootNodeRef.getStoreRef(), - PROP_QNAME_STRING_PROP_SINGLE, - findMeValue, - handler); - assertTrue("Set value not found.", count.intValue() == 1); - } - public void testAspectRemovalWithCommit() throws Throwable { // Create a node to add the aspect to diff --git a/source/java/org/alfresco/repo/node/db/DeletedNodeCleanupWorker.java b/source/java/org/alfresco/repo/node/db/DeletedNodeCleanupWorker.java index 756d686cfd..5cba74ad7c 100644 --- a/source/java/org/alfresco/repo/node/db/DeletedNodeCleanupWorker.java +++ b/source/java/org/alfresco/repo/node/db/DeletedNodeCleanupWorker.java @@ -22,8 +22,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.alfresco.repo.domain.node.NodeDAO.NodeRefQueryCallback; import org.alfresco.repo.node.cleanup.AbstractNodeCleanupWorker; -import org.alfresco.repo.node.db.NodeDaoService.NodeRefQueryCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.repository.NodeRef; @@ -105,11 +105,11 @@ public class DeletedNodeCleanupWorker extends AbstractNodeCleanupWorker return true; } }; - nodeDaoService.getNodesDeletedInOldTxns(minNodeId.longValue(), maxCommitTime, NODE_PURGE_BATCH_SIZE, callback); + nodeDAO.getNodesDeletedInOldTxns(minNodeId.longValue(), maxCommitTime, NODE_PURGE_BATCH_SIZE, callback); for (Pair nodePair : nodePairs) { Long nodeId = nodePair.getFirst(); - nodeDaoService.purgeNode(nodeId); + nodeDAO.purgeNode(nodeId); // Update the min node ID for the next query if (nodeId.longValue() > minNodeId.longValue()) { @@ -192,13 +192,13 @@ public class DeletedNodeCleanupWorker extends AbstractNodeCleanupWorker { public Integer execute() throws Throwable { - final List txnIds = nodeDaoService.getTxnsUnused( + final List txnIds = nodeDAO.getTxnsUnused( minTxnId.longValue(), maxCommitTime, TXN_PURGE_BATCH_SIZE); for (Long txnId : txnIds) { - nodeDaoService.purgeTxn(txnId); + nodeDAO.purgeTxn(txnId); // Update the min node ID for the next query if (txnId.longValue() > minTxnId.longValue()) { diff --git a/source/java/org/alfresco/repo/node/db/IndexChildrenWhereRequiredWorker.java b/source/java/org/alfresco/repo/node/db/IndexChildrenWhereRequiredWorker.java deleted file mode 100644 index 4d35d5767d..0000000000 --- a/source/java/org/alfresco/repo/node/db/IndexChildrenWhereRequiredWorker.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.node.db; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.node.cleanup.AbstractNodeCleanupWorker; -import org.alfresco.repo.node.db.NodeDaoService.NodeRefQueryCallback; -import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.util.Pair; - -/** - * Indexes child nodes where cascade re-indexing is disabled. - * - * @author Derek Hulley - * @since 2.2 SP2 - */ -public class IndexChildrenWhereRequiredWorker extends AbstractNodeCleanupWorker -{ - /** - * Default constructor - */ - public IndexChildrenWhereRequiredWorker() - { - } - - /** - * {@inheritDoc} - */ - protected List doCleanInternal() throws Throwable - { - List indexChildrenResults = indexChildrenWhereRequired(); - - List allResults = new ArrayList(100); - allResults.addAll(indexChildrenResults); - - // Done - return allResults; - } - - private List indexChildrenWhereRequired() - { - final List> parentNodePairs = new ArrayList>(100); - final NodeRefQueryCallback callback = new NodeRefQueryCallback() - { - public boolean handle(Pair nodePair) - { - parentNodePairs.add(nodePair); - return true; - } - }; - RetryingTransactionCallback getNodesCallback = new RetryingTransactionCallback() - { - public Object execute() throws Throwable - { - nodeDaoService.getNodesWithAspect(ContentModel.ASPECT_INDEX_CHILDREN, Long.MIN_VALUE, 100, callback); - // Done - return null; - } - }; - transactionService.getRetryingTransactionHelper().doInTransaction(getNodesCallback, true, true); - // Process the nodes in random order - Collections.shuffle(parentNodePairs); - // Iterate and operate - List results = new ArrayList(100); - for (final Pair parentNodePair : parentNodePairs) - { - RetryingTransactionCallback indexChildrenCallback = new RetryingTransactionCallback() - { - public String execute() throws Throwable - { - // Index children without full cascade - dbNodeService.indexChildren(parentNodePair, true); - // Done - return null; - } - }; - RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper(); - txnHelper.setMaxRetries(1); - try - { - txnHelper.doInTransaction(indexChildrenCallback, false, true); - String msg = - "Indexed child nodes: \n" + - " Parent node: " + parentNodePair.getFirst(); - results.add(msg); - } - catch (Throwable e) - { - String msg = - "Failed to index child nodes." + - " Set log level to WARN for this class to get exception log: \n" + - " Parent node: " + parentNodePair.getFirst() + "\n" + - " Error: " + e.getMessage(); - // It failed; do a full log in WARN mode - if (logger.isWarnEnabled()) - { - logger.warn(msg, e); - } - else - { - logger.error(msg); - } - results.add(msg); - } - } - // Done - if (logger.isDebugEnabled()) - { - StringBuilder sb = new StringBuilder(256); - sb.append("Indexed child nodes: \n") - .append(" Results:\n"); - for (String msg : results) - { - sb.append(" ").append(msg).append("\n"); - } - logger.debug(sb.toString()); - } - return results; - } -} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/node/db/NodeDaoService.java b/source/java/org/alfresco/repo/node/db/NodeDaoService.java index 7d8e44a403..7f503716cf 100644 --- a/source/java/org/alfresco/repo/node/db/NodeDaoService.java +++ b/source/java/org/alfresco/repo/node/db/NodeDaoService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2009 Alfresco Software Limited. * * This file is part of Alfresco * @@ -18,31 +18,6 @@ */ package org.alfresco.repo.node.db; -import java.io.Serializable; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Stack; - -import org.alfresco.repo.domain.ChildAssoc; -import org.alfresco.repo.domain.NodeAssoc; -import org.alfresco.repo.domain.NodePropertyValue; -import org.alfresco.repo.domain.PropertyMapKey; -import org.alfresco.repo.domain.Transaction; -import org.alfresco.repo.domain.hibernate.DirtySessionAnnotation; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; -import org.alfresco.service.cmr.dictionary.InvalidTypeException; -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.NodeRef; -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.namespace.QName; -import org.alfresco.util.Pair; - /** * Service layer accessing persistent node entities directly * @@ -61,611 +36,4 @@ public interface NodeDaoService * Flush the data changes to the persistence layer. */ public void flush(); - - /** - * Fetch a list of all stores in the repository - * - * @return Returns a list of stores - */ - @DirtySessionAnnotation(markDirty=false) - public List> getStores(); - - @DirtySessionAnnotation(markDirty=false) - public Pair getRootNode(StoreRef storeRef); - - /** - * Creates a unique store for the given protocol and identifier combination. - * The root node is created with the "root" aspect. - * @return Returns the root node, which is added automatically. - * @throws StoreExistsException if the store already exists - */ - @DirtySessionAnnotation(markDirty=true) - public Pair createStore(StoreRef storeRef); - - @DirtySessionAnnotation(markDirty=false) - public NodeRef.Status getNodeRefStatus(NodeRef nodeRef); - - /** - * Create a new node. Note that allowing the uuid to be assigned by passing in a null - * is more efficient. - * - * @param storeRef the store to which the node must belong - * @param uuid the node store-unique identifier, or null to assign a GUID - * @param nodeTypeQName the type of the node - * @return Returns a new node Id of the given type and attached to the store - * @throws InvalidTypeException if the node type is invalid or if the node type - * is not a valid real node - */ - @DirtySessionAnnotation(markDirty=true) - public Pair newNode(StoreRef storeRef, String uuid, QName nodeTypeQName) throws InvalidTypeException; - - @DirtySessionAnnotation(markDirty=true) - public Pair moveNodeToStore(Long nodeId, StoreRef storeRef); - - /** - * @param nodeRef the node reference - * @return Returns the node entity ID - */ - @DirtySessionAnnotation(markDirty=false) - public Pair getNodePair(NodeRef nodeRef); - - @DirtySessionAnnotation(markDirty=false) - public Pair getNodePair(Long nodeId); - - @DirtySessionAnnotation(markDirty=false) - public QName getNodeType(Long nodeId); - - @DirtySessionAnnotation(markDirty=true) - public void setNodeStatus(Long nodeId); - - @DirtySessionAnnotation(markDirty=false) - public Long getNodeAccessControlList(Long nodeId); - - @DirtySessionAnnotation(markDirty=true) - public void setNodeAccessControlList(Long nodeId, Long aclId); - - /** - * @param storeRef the new store or null to keep the existing one - * @param uuid the new UUID for the node or null to keep it the same - * @param nodeTypeQName the new type QName for the node or null to keep the existing one - */ - @DirtySessionAnnotation(markDirty=true) - public void updateNode(Long nodeId, StoreRef storeRef, String uuid, QName nodeTypeQName); - - @DirtySessionAnnotation(markDirty=false) - public Serializable getNodeProperty(Long nodeId, QName propertyQName); - - /** - * - * @param nodeId the node's ID - * @return Returns a copy of the low-level properties including auditable properties - * @throws ObjectNotFoundException if the node ID is invalid - * - * @see #getNodePair(NodeRef) - */ - @DirtySessionAnnotation(markDirty=false) - public Map getNodePropertiesRaw(Long nodeId); - - @DirtySessionAnnotation(markDirty=false) - public Map getNodeProperties(Long nodeId); - - @DirtySessionAnnotation(markDirty=true) - public void addNodeProperty(Long nodeId, QName qname, Serializable value); - - @DirtySessionAnnotation(markDirty=true) - public void addNodeProperties(Long nodeId, Map properties); - - @DirtySessionAnnotation(markDirty=true) - public void removeNodeProperties(Long nodeId, Set propertyQNames); - - @DirtySessionAnnotation(markDirty=true) - public void setNodeProperties(Long nodeId, Map properties); - - @DirtySessionAnnotation(markDirty=false) - public Set getNodeAspects(Long nodeId); - - @DirtySessionAnnotation(markDirty=true) - public void addNodeAspects(Long nodeId, Set aspectQNames); - - @DirtySessionAnnotation(markDirty=true) - public void removeNodeAspects(Long nodeId, Set aspectQNames); - - @DirtySessionAnnotation(markDirty=false) - public boolean hasNodeAspect(Long nodeId, QName aspectQName); - - /** - * Deletes the node and all entities. Note that the node entry will still exist and be - * associated with a live transaction. - */ - @DirtySessionAnnotation(markDirty=true) - public void deleteNode(Long nodeId); - - /** - * Remove all traces of the node. This assumes that the node has been marked - * for deletion using {@link #deleteNode(Long)}. - */ - @DirtySessionAnnotation(markDirty=true) - public void purgeNode(Long nodeId); - - /** - * @param name the cm:name to apply to the association - * @return Returns the persisted and filled association's ID - * - * @see ChildAssoc - */ - @DirtySessionAnnotation(markDirty=true) - public Pair newChildAssoc( - Long parentNodeId, - Long childNodeId, - boolean isPrimary, - QName assocTypeQName, - QName qname, - String name); - - /** - * Change the name of the child node. - * - * @param childId the child association to change - * @param childName the name to put on the association - */ - @DirtySessionAnnotation(markDirty=false) - public void setChildNameUnique(Long assocId, String childName); - - /** - * @param index the association index. -1 to keep the existing value - */ - @DirtySessionAnnotation(markDirty=true) - public Pair updateChildAssoc( - Long childAssocId, - Long parentNodeId, - Long childNodeId, - QName assocTypeQName, - QName qname, - int index, - String childName); - - /** - * Interface used to iterate over results from child association queries - * @author Derek Hulley - */ - public interface ChildAssocRefQueryCallback - { - /** - * - * @return Return true if resursion into the child node - * is required. - */ - boolean handle( - Pair childAssocPair, - Pair parentNodePair, - Pair childNodePair - ); - - boolean preLoadNodes(); - } - - /** - * Interface used to iterate over results from child association queries - * @author Derek Hulley - */ - public interface ChildAssocRefQueryCallbackFilter extends ChildAssocRefQueryCallback - { - /** - * Method to handle raw query results and decide if the result should be filtered out or not. - * If true is returned, the standard {@link #handle(Pair, Pair, Pair) handler} method - * will be called. If false is returned, then the query result will be skipped. - *

- * This provides a quick way to filter out results without having to pull in full entities. - * - * @return Return true if the standard {@link #handle(Pair, Pair, Pair) handler} - * method should be called, or false to filter the result out. - */ - boolean isDesiredRow( - Pair childAssocPair, - Pair parentNodePair, - Pair childNodePair, - String assocChildNodeName, - Long assocChildNodeNameCrc - ); - } - - /** - * Get a collection of all child association references for a given parent node. - *

- * WARNING: Be sure selective when doing this call recursively. - * - * @param parentNodeId the parent node - * @param resultsCallback the callback that will be called with the results - * @param recurse if true then iterate over the entire tree of nodes. - * Resursion is done top-down i.e. the first level children are all - * enumerated first, followed by all second level children and so on. - */ - @DirtySessionAnnotation(markDirty=false) - public void getChildAssocs(Long parentNodeId, ChildAssocRefQueryCallback resultsCallback, boolean recurse); - - /** - * Get a collection of all child association references for a given parent node. - * - * @param parentNodeId the parent node - * @param resultsCallback the callback that will be called with the results - */ - @DirtySessionAnnotation(markDirty=false) - public void getChildAssocs(Long parentNodeId, QName assocQName, ChildAssocRefQueryCallback resultsCallback); - - /** - * Get a collection of all child associations references where the child name is an exact match. - * This method only works if the association type fundamentally supports unique-name enforcement. - * - * @param parentNodeId the parent node - * @param assocTypeQName the type of the association to check. - * @param childNames the names of the child nodes (cm:name). These will be matched exactly. - * @param resultsCallback the callback that will be called with the results - */ - @DirtySessionAnnotation(markDirty=false) - public void getChildAssocs(Long parentNodeId, QName assocTypeQName, Collection childNames, ChildAssocRefQueryCallback resultsCallback); - - @DirtySessionAnnotation(markDirty=false) - public void getChildAssocsByTypeQNames( - Long parentNodeId, - List assocTypeQNames, - ChildAssocRefQueryCallback resultsCallback); - - @DirtySessionAnnotation(markDirty=false) - public void getChildAssocsByTypeQNameAndQName( - Long parentNodeId, - QName assocTypeQName, - QName assocQName, - ChildAssocRefQueryCallback resultsCallback); - - @DirtySessionAnnotation(markDirty=false) - public void getChildAssocsByChildTypes( - Long parentNodeId, - Set childNodeTypeQNames, - ChildAssocRefQueryCallback resultsCallback); - - @DirtySessionAnnotation(markDirty=false) - public void getPrimaryChildAssocs(Long parentNodeId, ChildAssocRefQueryCallback resultsCallback); - - @DirtySessionAnnotation(markDirty=false) - public void getPrimaryChildAssocsNotInSameStore(Long parentNodeId, ChildAssocRefQueryCallback resultsCallback); - - /** - * Interface used to iterate over pure node results - * @author Derek Hulley - */ - public interface NodeRefQueryCallback - { - /** - * - * @param nodePair the node result - * @return Returns true if more results are required - */ - boolean handle(Pair nodePair); - } - - /** - * Gets a set of nodes that have parents in the given store, but are themselves located in a different - * store. - * - * @param storeId the store of the parent nodes - * @param minNodeId the min node ID to return - * @param count the maximum number of results - * @param resultsCallback the node callback - * - * @deprecated Since 2.2SP6, 3.1SP2, 3.2: not performant and not relevant to any use-cases - */ - @DirtySessionAnnotation(markDirty=false) - public void getNodesWithChildrenInDifferentStore( - Long storeId, - Long minNodeId, - int count, - NodeRefQueryCallback resultsCallback); - - @DirtySessionAnnotation(markDirty=false) - public void getNodesWithAspect(QName aspectQName, Long minNodeId, int count, NodeRefQueryCallback resultsCallback); - - /** - * Gets the set of child associations of a certain parent node without parent associations of a certain type to - * other nodes with the same parent! In effect the 'orphans' with respect to a certain association type. - * - * @param parentNodeId - * the parent node ID - * @param assocTypeQName - * the association type QName - * @param resultsCallback - * the callback that will be called with the results - */ - @DirtySessionAnnotation(markDirty = false) - public void getChildAssocsWithoutParentAssocsOfType(final Long parentNodeId, final QName assocTypeQName, - ChildAssocRefQueryCallback resultsCallback); - /** - * @return Returns an association matching the given parent, type and child name (cm:name) - or null if not found - */ - @DirtySessionAnnotation(markDirty=false) - public Pair getChildAssoc(Long parentNodeId, QName assocTypeQName, String childName); - - /** - * @return Returns a matching association or null if one was not found - * - * @see ChildAssoc - */ - @DirtySessionAnnotation(markDirty=false) - public Pair getChildAssoc( - Long parentNodeId, - Long childNodeId, - QName assocTypeQName, - QName qname); - - /** - * Deletes an explicit child association. - * - * @return Returns true if the association was deleted, otherwise false - */ - @DirtySessionAnnotation(markDirty=true) - public boolean deleteChildAssoc( - final Long parentNodeId, - final Long childNodeId, - final QName assocTypeQName, - final QName qname); - - /** - * @param assoc the child association to remove - */ - @DirtySessionAnnotation(markDirty=true) - public void deleteChildAssoc(Long childAssocId); - - /** - * Finds the association between the node's primary parent and the node itself - */ - @DirtySessionAnnotation(markDirty=false) - public Pair getPrimaryParentAssoc(Long childNodeId); - - /** - * Get all parent associations for the node. This methods includes a cache safety check. - * @param childNode the child node - * @return Returns all parent associations for the node. - */ - @DirtySessionAnnotation(markDirty=false) - public Collection> getParentAssocs(final Long childNodeId); - - /** - * @return Returns the persisted and filled association - * @see NodeAssoc - */ - @DirtySessionAnnotation(markDirty=true) - public Pair newNodeAssoc( - Long sourceNodeId, - Long targetNodeId, - QName assocTypeQName); - - /** - * @return Returns a list of all node associations associated with the given node - */ - @DirtySessionAnnotation(markDirty=false) - public Collection> getNodeAssocsToAndFrom(final Long nodeId); - - /** - * @return Returns the node association or null if not found - */ - @DirtySessionAnnotation(markDirty=false) - public Pair getNodeAssoc(Long sourceNodeId, Long targetNodeId, QName assocTypeQName); - - /** - * Gets a node association by ID. - * - * @param assocId - * the association id - * @return the node association, or null if it does not exist - */ - @DirtySessionAnnotation(markDirty = false) - public AssociationRef getNodeAssocOrNull(Long assocId); - - /** - * @return Returns all the node associations where the node is the source - */ - @DirtySessionAnnotation(markDirty=false) - public Collection> getTargetNodeAssocs(Long sourceNodeId); - - /** - * @return Returns all the node associations where the node is the target - */ - @DirtySessionAnnotation(markDirty=false) - public Collection> getSourceNodeAssocs(Long targetNodeId); - - /** - * @param assoc the node association to remove - */ - @DirtySessionAnnotation(markDirty=true) - public void deleteNodeAssoc(Long assocId); - - /** - * Iterate over all nodes that have a given property type with a given string value. - * - * @param storeRef the store to search in - * @param propertyQName the qualified name of the property - * @param value the string value to match - * @param handler the callback to use while iterating over the URLs - * @return Returns the values for the given type definition - */ - @DirtySessionAnnotation(markDirty=true) - public void getPropertyValuesByPropertyAndValue( - StoreRef storeRef, - QName propertyQName, - String value, - NodePropertyHandler handler); - - /** - * Interface used to iterate over object array results - */ - public interface ObjectArrayQueryCallback - { - boolean handle(Object[] array); - } - - /** - * Iterate over all content nodes to get owner/creator and content url (in order to extract content size) - * - * @param storeRef the store to search in - * @param handler the callback to use while iterating over the URLs - * @return Returns the values for the given owner, creator and content url - */ - @DirtySessionAnnotation(markDirty=true) - public void getContentUrlsForStore( - StoreRef storeRef, - ObjectArrayQueryCallback resultsCallback); - - /** - * Iterate over all person nodes with missing usage property (for one-off patch) - * - * @param storeRef the store to search in - * @param handler the callback to use while iterating over the people - * @return Returns the values for person node uuid - */ - @DirtySessionAnnotation(markDirty=true) - public void getUsersWithoutUsageProp( - StoreRef storeRef, - ObjectArrayQueryCallback resultsCallback); - - - /** - * Iterate over all person nodes to get users without a calculated usage - * - * @param storeRef the store to search in - * @param handler the callback to use while iterating over the people - * @return Returns the values for username and person node uuid (excluding System) - */ - @DirtySessionAnnotation(markDirty=true) - public void getUsersWithoutUsage( - StoreRef storeRef, - ObjectArrayQueryCallback resultsCallback); - - /** - * Iterate over all person nodes to get users with a calculated usage - * - * @param storeRef the store to search in - * @param handler the callback to use while iterating over the people - * @return Returns the values for the username and person node uuid (excluding System) - */ - @DirtySessionAnnotation(markDirty=true) - public void getUsersWithUsage( - StoreRef storeRef, - ObjectArrayQueryCallback resultsCallback); - - /** - * Iterate over all property values for the given type definition. This will also dig out values that - * were persisted as type d:any. - * - * @param actualDataTypeDefinition the persisted type to retrieve - * @param handler the callback to use while iterating over the URLs - * @return Returns the values for the given type definition - */ - @DirtySessionAnnotation(markDirty=true) - public void getPropertyValuesByActualType(DataTypeDefinition actualDataTypeDefinition, NodePropertyHandler handler); - - /** - * Gets a batch of deleted nodes in old transactions. - * - * @param minNodeId the minimum node ID - * @param maxCommitTime the maximum commit time (to set a minimum transaction age) - * @param count the maximum number of results (for batching) - * @param resultsCallback the callback to pass results back - */ - @DirtySessionAnnotation(markDirty=false) - public void getNodesDeletedInOldTxns(Long minNodeId, long maxCommitTime, int count, NodeRefQueryCallback resultsCallback); - - /** - * Iterface to handle callbacks when iterating over properties - * - * @author Derek Hulley - * @since 2.0 - */ - public interface NodePropertyHandler - { - void handle(NodeRef nodeRef, QName nodeTypeQName, QName propertyQName, Serializable value); - } - - /** - * Retrieves the maximum transaction ID for which the commit time is less than the given time. - * - * @param maxCommitTime the max commit time (ms) - * @return the last transaction on or before the given time - */ - @DirtySessionAnnotation(markDirty=true) - public Long getMaxTxnIdByCommitTime(final long maxCommitTime); - /** - * Retrieves a specific transaction. - * - * @param txnId the unique transaction ID. - * @return the requested transaction or null - */ - @DirtySessionAnnotation(markDirty=true) - public Transaction getTxnById(long txnId); - /** - * Get all transactions in a given time range. Since time-based retrieval doesn't guarantee uniqueness - * for any given millisecond, a list of optional exclusions may be provided. - * - * @param excludeTxnIds a list of txn IDs to ignore. null is allowed. - * @param remoteOnly true if locally-written transactions must be ignored - */ - @DirtySessionAnnotation(markDirty=true) - public List getTxnsByCommitTimeAscending( - long fromTimeInclusive, - long toTimeExclusive, - int count, - List excludeTxnIds, - boolean remoteOnly); - /** - * Get all transactions in a given time range. Since time-based retrieval doesn't guarantee uniqueness - * for any given millisecond, a list of optional exclusions may be provided. - * - * @param excludeTxnIds a list of txn IDs to ignore. null is allowed. - * @param remoteOnly true if locally-written transactions must be ignored - */ - @DirtySessionAnnotation(markDirty=true) - public List getTxnsByCommitTimeDescending( - long fromTimeInclusive, - long toTimeExclusive, - int count, - List excludeTxnIds, - boolean remoteOnly); - /** - * Get the lowest commit time for a set of transactions - * - * @param includeTxnIds a list of transaction IDs to search for - * @return Returns the transactions by commit time for the given IDs - */ - @DirtySessionAnnotation(markDirty=true) - public List getTxnsByMinCommitTime(List includeTxnIds); - - @DirtySessionAnnotation(markDirty=false) - public int getTxnUpdateCount(final long txnId); - - @DirtySessionAnnotation(markDirty=false) - public int getTxnDeleteCount(final long txnId); - - @DirtySessionAnnotation(markDirty=false) - public int getTransactionCount(); - - @DirtySessionAnnotation(markDirty=false) - public List getTxnChangesForStore(final StoreRef storeRef, final long txnId); - - @DirtySessionAnnotation(markDirty=false) - public List getTxnChanges(final long txnId); - - @DirtySessionAnnotation(markDirty=false) - public List getTxnsUnused(Long minTxnId, long maxCommitTime, int count); - - @DirtySessionAnnotation(markDirty=true) - public void purgeTxn(Long txnId); - - @DirtySessionAnnotation(markDirty=false) - public Long getMinTxnCommitTime(); - - @DirtySessionAnnotation(markDirty=false) - public Long getMaxTxnCommitTime(); - - @DirtySessionAnnotation(markDirty=false) - public void prependPaths(Pair currentNodePair, Pair currentRootNodePair, - Path currentPath, Collection completedPaths, Stack assocIdStack, boolean primaryOnly) - throws CyclicChildRelationshipException; } 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 5b323565d6..1165cb873a 100644 --- a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java @@ -1,20 +1,26 @@ /* * Copyright (C) 2005-2010 Alfresco Software Limited. * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" */ package org.alfresco.repo.node.db.hibernate; @@ -36,7 +42,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.SortedMap; -import java.util.Stack; import java.util.TreeMap; import java.util.zip.CRC32; @@ -46,39 +51,31 @@ import org.alfresco.model.ContentModel; import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.domain.AuditableProperties; import org.alfresco.repo.domain.ChildAssoc; -import org.alfresco.repo.domain.ContentDataId; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.LocaleDAO; import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.NodeAssoc; -import org.alfresco.repo.domain.NodePropertyValue; -import org.alfresco.repo.domain.PropertyMapKey; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.domain.Server; import org.alfresco.repo.domain.Store; -import org.alfresco.repo.domain.Transaction; -import org.alfresco.repo.domain.UsageDeltaDAO; import org.alfresco.repo.domain.contentdata.ContentDataDAO; import org.alfresco.repo.domain.hibernate.ChildAssocImpl; -import org.alfresco.repo.domain.hibernate.DMPermissionsDaoComponentImpl; -import org.alfresco.repo.domain.hibernate.DbAccessControlListImpl; import org.alfresco.repo.domain.hibernate.DirtySessionMethodInterceptor; -import org.alfresco.repo.domain.hibernate.NodeAssocImpl; import org.alfresco.repo.domain.hibernate.NodeImpl; -import org.alfresco.repo.domain.hibernate.ServerImpl; import org.alfresco.repo.domain.hibernate.SessionSizeResourceManager; import org.alfresco.repo.domain.hibernate.StoreImpl; import org.alfresco.repo.domain.hibernate.TransactionImpl; +import org.alfresco.repo.domain.locale.LocaleDAO; +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.repo.domain.node.NodePropertyKey; +import org.alfresco.repo.domain.node.NodePropertyValue; +import org.alfresco.repo.domain.node.Transaction; +import org.alfresco.repo.domain.node.NodeDAO.NodeRefQueryCallback; +import org.alfresco.repo.domain.permissions.AclDAO; +import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.repo.node.NodeBulkLoader; import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.permissions.ACLType; import org.alfresco.repo.security.permissions.AccessControlListProperties; -import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties; import org.alfresco.repo.security.permissions.impl.AclChange; -import org.alfresco.repo.security.permissions.impl.AclDaoComponent; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.TransactionAwareSingleton; @@ -90,35 +87,23 @@ import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.DictionaryException; 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.AssociationExistsException; -import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.CyclicChildRelationshipException; import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; import org.alfresco.service.cmr.repository.EntityRef; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; -import org.alfresco.service.cmr.repository.InvalidStoreRefException; import org.alfresco.service.cmr.repository.MLText; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.Path; -import org.alfresco.service.cmr.repository.StoreExistsException; import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.repository.datatype.TypeConversionException; -import org.alfresco.service.cmr.repository.datatype.TypeConverter; import org.alfresco.service.namespace.QName; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.EqualsHelper; import org.alfresco.util.GUID; import org.alfresco.util.Pair; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.CacheMode; import org.hibernate.Criteria; -import org.hibernate.FetchMode; import org.hibernate.FlushMode; import org.hibernate.HibernateException; import org.hibernate.LockMode; @@ -127,7 +112,6 @@ import org.hibernate.Query; import org.hibernate.ScrollMode; import org.hibernate.ScrollableResults; import org.hibernate.Session; -import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.SQLGrammarException; @@ -140,48 +124,21 @@ import org.springframework.orm.hibernate3.support.HibernateDaoSupport; * * @author Derek Hulley */ -public class HibernateNodeDaoServiceImpl - extends HibernateDaoSupport - implements NodeDaoService, TransactionalDao, NodeBulkLoader +public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements NodeDaoService, TransactionalDao, + NodeBulkLoader { private static final String QUERY_GET_STORE_BY_ALL = "store.GetStoreByAll"; - private static final String QUERY_GET_ALL_STORES = "store.GetAllStores"; - private static final String QUERY_GET_NODE_BY_STORE_ID_AND_UUID = "node.GetNodeByStoreIdAndUuid"; - private static final String QUERY_GET_CHILD_NODE_IDS = "node.GetChildNodeIds"; - private static final String QUERY_GET_CHILD_ASSOCS_BY_ALL = "node.GetChildAssocsByAll"; - private static final String QUERY_GET_CHILD_ASSOC_BY_TYPE_AND_NAME = "node.GetChildAssocByTypeAndName"; - private static final String QUERY_GET_CHILD_ASSOC_REFS_BY_TYPE_AND_NAME_LIST = "node.GetChildAssocRefsByTypeAndNameList"; - private static final String QUERY_GET_CHILD_ASSOC_REFS = "node.GetChildAssocRefs"; - private static final String QUERY_GET_CHILD_ASSOC_REFS_BY_QNAME = "node.GetChildAssocRefsByQName"; - private static final String QUERY_GET_CHILD_ASSOC_REFS_BY_TYPEQNAMES = "node.GetChildAssocRefsByTypeQNames"; - private static final String QUERY_GET_CHILD_ASSOC_REFS_BY_TYPEQNAME_AND_QNAME = "node.GetChildAssocRefsByTypeQNameAndQName"; - private static final String QUERY_GET_CHILD_ASSOC_REFS_BY_CHILD_TYPEQNAME = "node.GetChildAssocRefsByChildTypeQName"; - private static final String QUERY_GET_PRIMARY_CHILD_ASSOCS = "node.GetPrimaryChildAssocs"; - private static final String QUERY_GET_PRIMARY_CHILD_ASSOCS_NOT_IN_SAME_STORE = "node.GetPrimaryChildAssocsNotInSameStore"; - private static final String QUERY_GET_NODES_WITH_CHILDREN_IN_DIFFERENT_STORE ="node.GetNodesWithChildrenInDifferentStore"; - private static final String QUERY_GET_NODES_WITH_ASPECT ="node.GetNodesWithAspect"; - private static final String QUERY_GET_CHILD_ASSOCS_WITHOUT_PARENT_ASSOCS_OF_TYPE ="node.GetChildAssocsWithoutParentAssocsOfType"; private static final String QUERY_GET_PARENT_ASSOCS = "node.GetParentAssocs"; - 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_STRING_AND_STORE = "node.GetNodesWithPropertyValuesByStringAndStore"; - private static final String QUERY_GET_CONTENT_URLS_FOR_STORE_OLD = "node.GetContentUrlsForStoreOld"; - private static final String QUERY_GET_CONTENT_URLS_FOR_STORE_NEW = "node.GetContentUrlsForStoreNew"; - private static final String QUERY_GET_USERS_WITHOUT_USAGE_PROP = "node.GetUsersWithoutUsageProp"; - private static final String QUERY_GET_USERS_WITHOUT_USAGE = "node.GetUsersWithoutUsage"; - private static final String QUERY_GET_USERS_WITH_USAGE = "node.GetUsersWithUsage"; - private static final String QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_ACTUAL_TYPE = "node.GetNodesWithPropertyValuesByActualType"; private static final String QUERY_GET_DELETED_NODES_BY_MAX_TXNID = "node.GetDeletedNodesByMaxTxnId"; private static final String QUERY_GET_SERVER_BY_IPADDRESS = "server.getServerByIpAddress"; - + private static final Long NULL_CACHE_VALUE = new Long(-1); private static Log logger = LogFactory.getLog(HibernateNodeDaoServiceImpl.class); /** Log to trace parent association caching: classname + .ParentAssocsCache */ - private static Log loggerParentAssocsCache = LogFactory.getLog(HibernateNodeDaoServiceImpl.class.getName() + ".ParentAssocsCache"); - + private static Log loggerParentAssocsCache = LogFactory.getLog(HibernateNodeDaoServiceImpl.class.getName() + + ".ParentAssocsCache"); + /** * Exceptions that indicate duplicate child names violations. */ @@ -189,21 +146,23 @@ public class HibernateNodeDaoServiceImpl public static final Class[] DUPLICATE_CHILD_NAME_EXCEPTIONS; static { - DUPLICATE_CHILD_NAME_EXCEPTIONS = new Class[] { - ConstraintViolationException.class, - DataIntegrityViolationException.class, - SQLGrammarException.class // Hibernate misinterprets a MS SQL Server exception - }; + DUPLICATE_CHILD_NAME_EXCEPTIONS = new Class[] + { ConstraintViolationException.class, DataIntegrityViolationException.class, SQLGrammarException.class // Hibernate + // misinterprets + // a MS + // SQL + // Server + // exception + }; } + /** Used for refactoring of DAO */ private QNameDAO qnameDAO; private ContentDataDAO contentDataDAO; - private UsageDeltaDAO usageDeltaDAO; - private AclDaoComponent aclDaoComponent; + private AclDAO aclDaoComponent; private LocaleDAO localeDAO; private DictionaryService dictionaryService; private boolean enableTimestampPropagation; - private TransactionService transactionService; private RetryingTransactionHelper auditableTransactionHelper; private BehaviourFilter behaviourFilter; /** A cache mapping StoreRef and NodeRef instances to the entity IDs (primary key) */ @@ -212,10 +171,10 @@ public class HibernateNodeDaoServiceImpl private SimpleCache parentAssocsCache; private boolean isDebugEnabled = logger.isDebugEnabled(); private boolean isDebugParentAssocCacheEnabled = loggerParentAssocsCache.isDebugEnabled(); - + /** a uuid identifying this unique instance */ private final String uuid; - + private static TransactionAwareSingleton serverIdSingleton = new TransactionAwareSingleton(); private final String ipAddress; @@ -236,7 +195,7 @@ public class HibernateNodeDaoServiceImpl { throw new AlfrescoRuntimeException("Failed to get server IP address", e); } - + changeTxnIdSet = new HashSet(0); enableTimestampPropagation = true; } @@ -257,7 +216,7 @@ public class HibernateNodeDaoServiceImpl HibernateNodeDaoServiceImpl that = (HibernateNodeDaoServiceImpl) obj; return this.uuid.equals(that.uuid); } - + /** * @see #uuid */ @@ -282,12 +241,7 @@ public class HibernateNodeDaoServiceImpl this.contentDataDAO = contentDataDAO; } - public void setUsageDeltaDAO(UsageDeltaDAO usageDeltaDAO) - { - this.usageDeltaDAO = usageDeltaDAO; - } - - public void setAclDaoComponent(AclDaoComponent aclDaoComponent) + public void setAclDAO(AclDAO aclDaoComponent) { this.aclDaoComponent = aclDaoComponent; } @@ -318,16 +272,8 @@ public class HibernateNodeDaoServiceImpl } /** - * Executes post-transaction code - */ - public void setTransactionService(TransactionService transactionService) - { - this.transactionService = transactionService; - } - - /** - * Set the component to start new transactions when setting auditable properties (timestamps) - * in the post-transaction phase. + * Set the component to start new transactions when setting auditable properties (timestamps) in the + * post-transaction phase. */ public void setAuditableTransactionHelper(RetryingTransactionHelper auditableTransactionHelper) { @@ -335,9 +281,9 @@ public class HibernateNodeDaoServiceImpl } /** - * Set the component to determine the correct aspect behaviours. This applies - * particularly to the cm:auditable case, where the setting of values - * is done automatically except when the behaviour is disabled. + * Set the component to determine the correct aspect behaviours. This applies particularly to the + * cm:auditable case, where the setting of values is done automatically except when the behaviour is + * disabled. */ public void setBehaviourFilter(BehaviourFilter behaviourFilter) { @@ -347,7 +293,7 @@ public class HibernateNodeDaoServiceImpl /** * Ste the transaction-aware cache to store Store and Root Node IDs by Store Reference * - * @param storeAndNodeIdCache the cache + * @param storeAndNodeIdCache the cache */ public void setStoreAndNodeIdCache(SimpleCache storeAndNodeIdCache) { @@ -357,7 +303,7 @@ public class HibernateNodeDaoServiceImpl /** * Set the transaction-aware cache to store parent associations by child node id * - * @param parentAssocsCache the cache + * @param parentAssocsCache the cache */ public void setParentAssocsCache(SimpleCache parentAssocsCache) { @@ -365,7 +311,7 @@ public class HibernateNodeDaoServiceImpl } /** - * @return Returns the ID of this instance's server instance or null + * @return Returns the ID of this instance's server instance or null */ private Long getServerIdOrNull() { @@ -380,8 +326,7 @@ public class HibernateNodeDaoServiceImpl { public Object doInHibernate(Session session) { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_SERVER_BY_IPADDRESS) + Query query = session.getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_SERVER_BY_IPADDRESS) .setString("ipAddress", ipAddress); return query.uniqueResult(); } @@ -397,120 +342,19 @@ public class HibernateNodeDaoServiceImpl return null; } } - - /** - * 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); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - 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) - { - String changeTxnId = AlfrescoTransactionSupport.getTransactionId(); - // no transaction instance has been bound to the transaction - transaction = new TransactionImpl(); - transaction.setChangeTxnId(changeTxnId); - transaction.setServer(getServer()); - txnId = getHibernateTemplate().save(transaction); - // bind the id - AlfrescoTransactionSupport.bindResource(RESOURCE_KEY_TRANSACTION_ID, txnId); - - if (isDebugEnabled) - { - if (!changeTxnIdSet.add(changeTxnId)) - { - // the txn id was already used! - logger.error("Change transaction ID already used: " + transaction); - } - logger.debug("Created new transaction: " + transaction); - } - } - else - { - transaction = (Transaction) getHibernateTemplate().get(TransactionImpl.class, txnId); - if (isDebugEnabled) - { - logger.debug("Using existing transaction: " + transaction); - } - } - return transaction; - } - - /** - * Ensure that any transaction that might be present is updated to reflect the current time. - */ + public void beforeCommit() { - Serializable txnId = (Serializable) AlfrescoTransactionSupport.getResource(RESOURCE_KEY_TRANSACTION_ID); - if (txnId != null) - { - // A write was done during the current transaction - Transaction transaction = (Transaction) getHibernateTemplate().get(TransactionImpl.class, txnId); - transaction.setCommitTimeMs(System.currentTimeMillis()); - } + throw new UnsupportedOperationException(); + } + + public Long getCurrentTransactionId() + { + throw new UnsupportedOperationException(); } /** - * Does this Session contain any changes which must be - * synchronized with the store? + * Does this Session contain any changes which must be synchronized with the store? * * @return true => changes are pending */ @@ -525,7 +369,7 @@ public class HibernateNodeDaoServiceImpl } }; // execute the callback - return ((Boolean)getHibernateTemplate().execute(callback)).booleanValue(); + return ((Boolean) getHibernateTemplate().execute(callback)).booleanValue(); } /** @@ -537,7 +381,7 @@ public class HibernateNodeDaoServiceImpl } /** - * @return Returns the Store entity or null + * @return Returns the Store entity or null */ private Store getStore(final StoreRef storeRef) { @@ -572,10 +416,8 @@ public class HibernateNodeDaoServiceImpl { public Object doInHibernate(Session session) { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_STORE_BY_ALL) - .setString("protocol", storeRef.getProtocol()) - .setString("identifier", storeRef.getIdentifier()); + Query query = session.getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_STORE_BY_ALL).setString( + "protocol", storeRef.getProtocol()).setString("identifier", storeRef.getIdentifier()); return query.uniqueResult(); } }; @@ -593,24 +435,13 @@ public class HibernateNodeDaoServiceImpl return store; } - private Store getStoreNotNull(StoreRef storeRef) - { - Store store = getStore(storeRef); - if (store == null) - { - throw new InvalidStoreRefException(storeRef); - } - // done - return store; - } - /** - * Fetch the node. If the ID is invalid, we assume that the state of the current session - * is invalid i.e. the data is stale + * Fetch the node. If the ID is invalid, we assume that the state of the current session is invalid i.e. the data is + * stale * - * @param nodeId the node's ID - * @return the node - * @throws ObjectNotFoundException if the ID doesn't refer to a node. + * @param nodeId the node's ID + * @return the node + * @throws ObjectNotFoundException if the ID doesn't refer to a node. */ private Node getNodeNotNull(Long nodeId) { @@ -621,27 +452,27 @@ public class HibernateNodeDaoServiceImpl } return node; } - + /** - * Fetch the node. If the ID is invalid, null is returned. + * Fetch the node. If the ID is invalid, null is returned. * - * @param nodeId the node's ID - * @return the node - * @throws ObjectNotFoundException if the ID doesn't refer to a node. + * @param nodeId the node's ID + * @return the node + * @throws ObjectNotFoundException if the ID doesn't refer to a node. */ private Node getNodeOrNull(Long nodeId) { Node node = (Node) getHibernateTemplate().get(NodeImpl.class, nodeId); return node; } - + /** - * Fetch the child assoc. If the ID is invalid, we assume that the state of the current session - * is invalid i.e. the data is stale + * Fetch the child assoc. If the ID is invalid, we assume that the state of the current session is invalid i.e. the + * data is stale * - * @param childAssocId the assoc's ID - * @return the assoc - * @throws AlfrescoRuntimeException if the ID doesn't refer to an assoc. + * @param childAssocId the assoc's ID + * @return the assoc + * @throws AlfrescoRuntimeException if the ID doesn't refer to an assoc. */ private ChildAssoc getChildAssocNotNull(Long childAssocId) { @@ -653,342 +484,39 @@ public class HibernateNodeDaoServiceImpl return assoc; } -// /** -// * Fetch the child assoc. If the ID is invalid, we assume that the state of the current session -// * is invalid i.e. the data is stale -// * -// * @param nodeAssocId the assoc's ID -// * @return the assoc -// * @throws AlfrescoRuntimeException if the ID doesn't refer to an assoc. -// */ -// private NodeAssoc getNodeAssocNotNull(Long nodeAssocId) -// { -// NodeAssoc assoc = (NodeAssoc) getHibernateTemplate().get(NodeAssocImpl.class, nodeAssocId); -// if (assoc == null) -// { -// throw new AlfrescoRuntimeException("NodeAssoc ID " + nodeAssocId + " is invalid"); -// } -// return assoc; -// } -// - /** - * @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); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List stores = (List) getHibernateTemplate().execute(callback); - List> storeRefs = new ArrayList>(stores.size()); - for (Store store : stores) - { - Pair storePair = new Pair(store.getId(), store.getStoreRef()); - storeRefs.add(storePair); - } - // done - return storeRefs; - } - - public Pair getRootNode(StoreRef storeRef) - { - Store store = getStore(storeRef); - if (store == null) - { - return null; - } - Node rootNode = store.getRootNode(); - if (rootNode == null) - { - throw new InvalidStoreRefException("Store does not have a root node: " + storeRef, storeRef); - } - // done - return new Pair(rootNode.getId(), rootNode.getNodeRef()); - } - - /** - * Ensures that the store protocol/identifier combination is unique - */ - public Pair createStore(StoreRef storeRef) - { - Store store = getStore(storeRef); - if (store != null) - { - throw new StoreExistsException(storeRef); - } - - store = new StoreImpl(); - // set key values - store.setProtocol(storeRef.getProtocol()); - store.setIdentifier(storeRef.getIdentifier()); - // The root node may be null exactly because the Store needs an ID before it can be assigned to a node - getHibernateTemplate().save(store); - // create and assign a root node - Node rootNode = newNode( - store, - null, - ContentModel.TYPE_STOREROOT); - store.setRootNode(rootNode); - // Add the root aspect - Pair rootAspectQNamePair = qnameDAO.getOrCreateQName(ContentModel.ASPECT_ROOT); - rootNode.getAspects().add(rootAspectQNamePair.getFirst()); - parentAssocsCache.remove(rootNode.getId()); - - // Assign permissions to the root node - SimpleAccessControlListProperties properties = aclDaoComponent.getDefaultProperties(); - Long id = aclDaoComponent.createAccessControlList(properties); - DbAccessControlList acl = aclDaoComponent.getDbAccessControlList(id); - rootNode.setAccessControlList(acl); - - // Cache the value - storeAndNodeIdCache.put(storeRef, store.getId()); - // Done - return new Pair(rootNode.getId(), rootNode.getNodeRef()); - } - - public NodeRef.Status getNodeRefStatus(NodeRef nodeRef) - { - // Get the store - StoreRef storeRef = nodeRef.getStoreRef(); - Store store = getStore(storeRef); - if (store == null) - { - // No such store therefore no such node reference - return null; - } - Node node = getNodeOrNull(store, nodeRef.getId()); - if (node == null) // node never existed - { - return null; - } - else - { - return new NodeRef.Status( - node.getTransaction().getChangeTxnId(), - node.getTransaction().getId(), - node.getDeleted()); - } - } - - private Node getNodeOrNull(final Store store, final String uuid) - { - NodeRef nodeRef = new NodeRef(store.getStoreRef(), uuid); - // Look it up in the cache - Long nodeId = storeAndNodeIdCache.get(nodeRef); - // Load it - if (nodeId != null) - { - // Check for null persistence (previously missed value) - if (nodeId.equals(NULL_CACHE_VALUE)) - { - // There is no such value matching - return null; - } - // Don't use the method that throws an exception as the cache might be invalid. - Node node = (Node) getSession().get(NodeImpl.class, nodeId); - if (node == null) - { - // It is not available, so we need to go the query route. - // But first remove the cache entry - storeAndNodeIdCache.remove(nodeRef); - // Recurse, but this time there is no cache entry - return getNodeOrNull(store, uuid); - } - else - { - return node; - } - } - // Query for it - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODE_BY_STORE_ID_AND_UUID) - .setLong("storeId", store.getId()) - .setString("uuid", uuid); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.uniqueResult(); - } - }; - Object[] result = (Object[]) getHibernateTemplate().execute(callback); - // Cache the value - final Node node; - if (result == null) - { - node = null; - storeAndNodeIdCache.put(nodeRef, NULL_CACHE_VALUE); - } - else - { - node = (Node) result[0]; - storeAndNodeIdCache.put(nodeRef, node.getId()); - } - return node; - } - - private void updateNodeStatus(Node node, boolean deleted) - { - Transaction currentTxn = getCurrentTransaction(); - // Update it if required - if (!EqualsHelper.nullSafeEquals(node.getTransaction(), currentTxn)) - { - // Txn has changed - DirtySessionMethodInterceptor.setSessionDirty(); - node.setTransaction(currentTxn); - } - if (node.getDeleted() != deleted) - { - DirtySessionMethodInterceptor.setSessionDirty(); - node.setDeleted(deleted); - } - } - private static final String UNKNOWN_USER = "unknown"; + private String getCurrentUser() { String user = AuthenticationUtil.getFullyAuthenticatedUser(); return (user == null) ? UNKNOWN_USER : user; } - - private void recordNodeCreate(Node node) - { - updateNodeStatus(node, false); - // Handle cm:auditable - if (hasNodeAspect(node, ContentModel.ASPECT_AUDITABLE)) - { - String currentUser = getCurrentUser(); - Date currentDate = new Date(); - AuditableProperties auditableProperties = new AuditableProperties(); - node.setAuditableProperties(auditableProperties); - auditableProperties.setAuditValues(currentUser, currentDate, false); - } - } - /** - * Record the node update, setting the node's cm:auditable properties. - * The cm:auditable properties set implicity if the automatic behaviour - * {@link BehaviourFilter#isEnabled(NodeRef, QName) behaviour} is enabled. - * - * @see #recordNodeUpdate(Node, Map) - */ - private void recordNodeUpdate(Node node) - { - recordNodeUpdate(node, null); - } - - /** - * Record the node update, setting the node's cm:auditable properties. - * The cm:auditable properties set implicity if the automatic behaviour - * {@link BehaviourFilter#isEnabled(NodeRef, QName) behaviour} is enabled, - * otherwise the properties are extracted from the properties passed in. - * - * @param node the node to operate on - * @param properties the node properties from which cm:auditable properties - * may be extracted - */ - private void recordNodeUpdate(Node node, Map properties) - { - updateNodeStatus(node, false); - // Handle cm:auditable - if (hasNodeAspect(node, ContentModel.ASPECT_AUDITABLE)) - { - NodeRef nodeRef = node.getNodeRef(); - AuditableProperties auditableProperties = node.getAuditableProperties(); - if (auditableProperties == null) - { - auditableProperties = new AuditableProperties(); - node.setAuditableProperties(auditableProperties); - } - String currentUser = getCurrentUser(); - Date currentDate = new Date(); - // Check if the cm:auditable aspect behaviour is enabled - if (behaviourFilter.isEnabled(nodeRef, ContentModel.ASPECT_AUDITABLE)) - { - // Automatic cm:auditable behaviour - auditableProperties.setAuditValues(currentUser, currentDate, false); - } - else if (properties != null) - { - // Manual cm:auditable behaviour - node.getAuditableProperties().setAuditValues(currentUser, currentDate, properties); - } - // else - // there are no properties, so there is nothing to set - } - // Propagate timestamps - propagateTimestamps(node); - } - - private void recordNodeDelete(Node node) - { - updateNodeStatus(node, true); - // Handle cm:auditable - if (hasNodeAspect(node, ContentModel.ASPECT_AUDITABLE)) - { - String currentUser = getCurrentUser(); - Date currentDate = new Date(); - AuditableProperties auditableProperties = node.getAuditableProperties(); - if (auditableProperties == null) - { - auditableProperties = new AuditableProperties(); - node.setAuditableProperties(auditableProperties); - } - auditableProperties.setAuditValues(currentUser, currentDate, false); - } - } - - /** - * Ensures that timestamps are propagated for the cm:auditable aspect as required - * and defined by the model. - */ - private void propagateTimestamps(Node node) - { - // Shortcut - if (!enableTimestampPropagation) - { - return; - } - Long nodeId = node.getId(); - NodeInfo parentAssocs = getParentAssocsInternal(nodeId); - for (ParentAssocInfo parentAssoc : parentAssocs.getParentAssocs().values()) - { - propagateTimestamps(parentAssoc); - } - } - /** * Sets the timestamps for nodes set during the transaction. *

* The implementation attempts to propagate the timestamps in the same transaction, but during periods of high - * concurrent modification to children of a particular parent node, the contention-resolution at the database - * can lead to delays in the processes. When this occurs, the process is pushed to after the transaction for an + * concurrent modification to children of a particular parent node, the contention-resolution at the database can + * lead to delays in the processes. When this occurs, the process is pushed to after the transaction for an * arbitrary period of time, after which the server will again attempt to do the work in the transaction. * * @author Derek Hulley */ - private class TimestampPropagator extends TransactionListenerAdapter implements RetryingTransactionCallback + private class TimestampPropagator extends TransactionListenerAdapter implements + RetryingTransactionCallback { private final Set nodeIds; - + private TimestampPropagator() { this.nodeIds = new HashSet(23); } - + public void addNode(Long nodeId) { nodeIds.add(nodeId); } - + @Override public void afterCommit() { @@ -1012,7 +540,7 @@ public class HibernateNodeDaoServiceImpl long now = System.currentTimeMillis(); return executeImpl(now, true); } - + private Integer executeImpl(long now, boolean isPostTransaction) throws Throwable { if (logger.isDebugEnabled()) @@ -1044,7 +572,7 @@ public class HibernateNodeDaoServiceImpl continue; } // Lock it - session.lock(node, LockMode.UPGRADE_NOWAIT); // Might fail immediately, but that is better than waiting + session.lock(node, LockMode.UPGRADE_NOWAIT); // Might fail immediately, but that is better than waiting auditableProperties.setAuditValues(modifier, modifiedDate, false); count++; if (count % 1000 == 0) @@ -1056,11 +584,12 @@ public class HibernateNodeDaoServiceImpl return new Integer(count); } } - + private static final String RESOURCE_KEY_TIMESTAMP_PROPAGATOR = "hibernate.timestamp.propagator"; + /** - * Ensures that the timestamps are propogated to the parent node of the association, but only - * if the association requires it. + * Ensures that the timestamps are propogated to the parent node of the association, but only if the association + * requires it. */ private void propagateTimestamps(ParentAssocInfo parentAssocPair) { @@ -1088,8 +617,8 @@ public class HibernateNodeDaoServiceImpl return; } // We have to update the parent - TimestampPropagator propagator = - (TimestampPropagator) AlfrescoTransactionSupport.getResource(RESOURCE_KEY_TIMESTAMP_PROPAGATOR); + TimestampPropagator propagator = (TimestampPropagator) AlfrescoTransactionSupport + .getResource(RESOURCE_KEY_TIMESTAMP_PROPAGATOR); if (propagator == null) { propagator = new TimestampPropagator(); @@ -1098,877 +627,12 @@ public class HibernateNodeDaoServiceImpl propagator.addNode(parentAssocPair.getParentNodeId()); } - public Pair newNode(StoreRef storeRef, String uuid, QName nodeTypeQName) throws InvalidTypeException - { - Store store = (Store) getStoreNotNull(storeRef); - Node newNode = newNode(store, uuid, nodeTypeQName); - Long nodeId = newNode.getId(); - NodeRef nodeRef = newNode.getNodeRef(); - return new Pair(nodeId, nodeRef); - } - - private Node newNode(Store store, String uuid, QName nodeTypeQName) throws InvalidTypeException - { - Node node = null; - if (uuid != null) - { - // Get any existing Node. A node with this UUID may have existed before, but must be marked - // deleted; otherwise it will be considered live and valid - node = getNodeOrNull(store, uuid); - } - else - { - uuid = GUID.generate(); - } - if (node != null) - { - if (!node.getDeleted()) - { - // If there is already an undeleted node, then there is a clash - throw new InvalidNodeRefException("Live Node exists: " + node.getNodeRef(), node.getNodeRef()); - } - // Set clean values - node.setTypeQName(qnameDAO, nodeTypeQName); - node.setDeleted(false); - node.setAccessControlList(null); - // Record node change - recordNodeCreate(node); - } - else - { - // There is no existing node, deleted or otherwise. - node = new NodeImpl(); - node.setStore(store); - node.setUuid(uuid); - node.setTypeQName(qnameDAO, nodeTypeQName); - node.setDeleted(false); - node.setAccessControlList(null); - // Record node change - recordNodeCreate(node); - // Persist it - getHibernateTemplate().save(node); - - // Update the cache - storeAndNodeIdCache.put(node.getNodeRef(), node.getId()); - } - - // Done - return node; - } - - /** - * This moves the entire node, ensuring that a trail is left behind. It is more - * efficient to move the node and recreate a deleted node in it's wake because of - * the other properties and aspects that need to go with the node. - */ - public Pair moveNodeToStore(Long nodeId, StoreRef storeRef) - { - Node node = getNodeNotNull(nodeId); - // Update the node - updateNode(nodeId, storeRef, null, null); - NodeRef nodeRef = node.getNodeRef(); - - return new Pair(node.getId(), nodeRef); - } - - public Pair getNodePair(NodeRef nodeRef) - { - Store store = getStore(nodeRef.getStoreRef()); - if (store == null) - { - return null; - } - // Get the node: none, deleted or live - Node node = getNodeOrNull(store, nodeRef.getId()); - if (node == null) - { - // The node doesn't exist even as a deleted reference - return null; - } - else if (node.getDeleted()) - { - // The reference exists, but only as a deleted node - return null; - } - else - { - // The node is live - return new Pair(node.getId(), nodeRef); - } - } - - public Pair getNodePair(Long nodeId) - { - Node node = (Node) getHibernateTemplate().get(NodeImpl.class, nodeId); - if (node == null) - { - return null; - } - else if (node.getDeleted()) - { - // The node reference exists, but it is officially deleted - return null; - } - else - { - return new Pair(nodeId, node.getNodeRef()); - } - } - - public QName getNodeType(Long nodeId) - { - Node node = getNodeNotNull(nodeId); - QName nodeTypeQName = node.getTypeQName(qnameDAO); - return nodeTypeQName; - } - - public void setNodeStatus(Long nodeId) - { - Node node = getNodeNotNull(nodeId); - recordNodeUpdate(node); - } - - public Long getNodeAccessControlList(Long nodeId) - { - Node node = getNodeNotNull(nodeId); - DbAccessControlList acl = node.getAccessControlList(); - if (acl == null) - { - return null; - } - else - { - return acl.getId(); - } - } - - public void setNodeAccessControlList(Long nodeId, Long aclId) - { - Node node = getNodeNotNull(nodeId); - if (aclId == null) - { - node.setAccessControlList(null); - } - else - { - DbAccessControlList acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, aclId); - if (acl == null) - { - throw new IllegalArgumentException("ACL with ID " + aclId + " doesn't exist."); - } - node.setAccessControlList(acl); - } - } - - public void updateNode(Long nodeId, StoreRef storeRefAfter, String uuidAfter, QName nodeTypeQName) - { - Node node = getNodeNotNull(nodeId); - Store storeBefore = node.getStore(); - String uuidBefore = node.getUuid(); - NodeRef nodeRefBefore = node.getNodeRef(); - - final Store storeAfter; - if (storeRefAfter == null) - { - storeAfter = storeBefore; - storeRefAfter = storeBefore.getStoreRef(); - } - else - { - storeAfter = getStoreNotNull(storeRefAfter); - } - if (uuidAfter == null) - { - uuidAfter = uuidBefore; - } - - NodeRef nodeRefAfter = new NodeRef(storeRefAfter, uuidAfter); - if (!nodeRefAfter.equals(nodeRefBefore)) - { - Node conflictingNode = getNodeOrNull(storeAfter, uuidAfter); - if (conflictingNode != null) - { - if (!conflictingNode.getDeleted()) - { - throw new InvalidNodeRefException("Live Node exists: " + node.getNodeRef(), node.getNodeRef()); - } - // It is a deleted node so just remove the conflict - getHibernateTemplate().delete(conflictingNode); - // Flush immediately to ensure that the record is deleted - DirtySessionMethodInterceptor.flushSession(getSession(), true); - // The cache entry will be overwritten so we don't need to do it here - } - // ETHREEOH-4031: ParentAssocsCache gets out of date when parent NodeRefs are modified - parentAssocsCache.remove(nodeId); - removeParentAssocCacheEntriesForParent(nodeId); - - // Change the store - node.setStore(storeAfter); - node.setUuid(uuidAfter); - // We will need to record the change for the new node - recordNodeUpdate(node); - // Flush immediately to ensure that the record changes - DirtySessionMethodInterceptor.flushSession(getSession(), true); - - // We need to create a dummy reference for the node that was just moved away - Node oldNodeDummy = new NodeImpl(); - oldNodeDummy.setStore(storeBefore); - oldNodeDummy.setUuid(uuidBefore); - oldNodeDummy.setTypeQNameId(node.getTypeQNameId()); - recordNodeDelete(oldNodeDummy); - // Persist - getHibernateTemplate().save(oldNodeDummy); - - // Update cache entries - NodeRef nodeRef = node.getNodeRef(); - storeAndNodeIdCache.put(nodeRef, node.getId()); - storeAndNodeIdCache.put(nodeRefBefore, oldNodeDummy.getId()); - } - - // Only update the node type if it is changing - if (nodeTypeQName != null) - { - Long nodeTypeQNameId = qnameDAO.getOrCreateQName(nodeTypeQName).getFirst(); - if (!nodeTypeQNameId.equals(node.getTypeQNameId())) - { - node.setTypeQNameId(nodeTypeQNameId); - // We will need to record the change - recordNodeUpdate(node); - } - } - } - - public Map getNodePropertiesRaw(Long nodeId) - { - Node node = getNodeNotNull(nodeId); - Map props = node.getProperties(); - // Copy this for adding - props = new HashMap(props); - // Add the auditable properties - if (hasNodeAspect(node, ContentModel.ASPECT_AUDITABLE)) - { - AuditableProperties auditable = node.getAuditableProperties(); - Map auditableProperties = auditable.getAuditableProperties(); - for (Map.Entry entry : auditableProperties.entrySet()) - { - // Get default locale for the key - Pair defaultLocalePair = localeDAO.getDefaultLocalePair(); - if (defaultLocalePair == null) - { - continue; - } - - QName auditablePropertyQName = entry.getKey(); - Pair auditablePropertyQNamePair = qnameDAO.getQName(auditablePropertyQName); - if (auditablePropertyQNamePair == null) - { - continue; - } - Serializable auditablePropertyValue = entry.getValue(); - NodePropertyValue npv = new NodePropertyValue(auditablePropertyQName, auditablePropertyValue); - PropertyMapKey npk = new PropertyMapKey(); - npk.setQnameId(auditablePropertyQNamePair.getFirst()); - npk.setListIndex(HibernateNodeDaoServiceImpl.IDX_NO_COLLECTION); - npk.setLocaleId(defaultLocalePair.getFirst()); - // Add this property to the map - props.put(npk, npv); - } - } - // Done - return props; - } - - public Serializable getNodeProperty(Long nodeId, QName propertyQName) - { - Node node = getNodeNotNull(nodeId); - - // Handle cm:auditable - if (AuditableProperties.isAuditableProperty(propertyQName)) - { - // Only bother if the aspect is present - if (hasNodeAspect(node, ContentModel.ASPECT_AUDITABLE)) - { - AuditableProperties auditableProperties = node.getAuditableProperties(); - return auditableProperties == null ? null : auditableProperties.getAuditableProperty(propertyQName); - } - else - { - return null; - } - } - - Pair propertyQNamePair = qnameDAO.getQName(propertyQName); - if (propertyQNamePair == null) - { - return null; - } - - Map nodeProperties = node.getProperties(); - Serializable propertyValue = HibernateNodeDaoServiceImpl.getPublicProperty( - nodeProperties, - propertyQName, - qnameDAO, localeDAO, contentDataDAO, dictionaryService); - return propertyValue; - } - - public Map getNodeProperties(Long nodeId) - { - Node node = getNodeNotNull(nodeId); - Map nodeProperties = node.getProperties(); - - // Convert the QName IDs - Map converted = HibernateNodeDaoServiceImpl.convertToPublicProperties( - nodeProperties, - qnameDAO, - localeDAO, - contentDataDAO, - dictionaryService); - - // Handle cm:auditable - if (hasNodeAspect(node, ContentModel.ASPECT_AUDITABLE)) - { - AuditableProperties auditableProperties = node.getAuditableProperties(); - if (auditableProperties == null) - { - auditableProperties = new AuditableProperties(); - } - converted.putAll(auditableProperties.getAuditableProperties()); - } - - // Done - return converted; - } - - private void addNodePropertyImpl(Node node, QName qname, Serializable value, Long localeId) - { - // Handle cm:auditable - if (AuditableProperties.isAuditableProperty(qname)) - { - // This is never set manually - return; - } - - PropertyDefinition propertyDef = dictionaryService.getProperty(qname); - Long qnameId = qnameDAO.getOrCreateQName(qname).getFirst(); - - /* - * TODO: Put into interceptor - * This method will replaces a content property. We therefore remove the existing content data. - * New ContentData entities will be created. Re-using content data will mean comparing old - * with new - it is faster to just create a new row. - */ - if (propertyDef != null && propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT)) - { - Set contentQNamesToRemoveIds = Collections.singleton(qnameId); - // Flush the session to ensure this non-hibernate DAO can do its job - getHibernateTemplate().execute(new SessionFlusher()); - contentDataDAO.deleteContentDataForNode( - node.getId(), - contentQNamesToRemoveIds); - } - - Map persistableProperties = new HashMap(3); - - HibernateNodeDaoServiceImpl.addValueToPersistedProperties( - persistableProperties, - propertyDef, - (short)-1, - qnameId, - localeId, - value, - localeDAO, - contentDataDAO); - - Map nodeProperties = node.getProperties(); - - Iterator oldPropertyKeysIterator = nodeProperties.keySet().iterator(); - while (oldPropertyKeysIterator.hasNext()) - { - PropertyMapKey oldPropertyKey = oldPropertyKeysIterator.next(); - // If the qname doesn't match, then ignore - if (!oldPropertyKey.getQnameId().equals(qnameId)) - { - continue; - } - // The qname matches, but is the key present in the new values - if (persistableProperties.containsKey(oldPropertyKey)) - { - // The key is present in both maps so it'll be updated - continue; - } - // Remove the entry from the node's properties - oldPropertyKeysIterator.remove(); - } - - // Now add all the new properties. The will overwrite and/or add values. - nodeProperties.putAll(persistableProperties); - } - - public void addNodeProperty(Long nodeId, QName qname, Serializable propertyValue) - { - Node node = getNodeNotNull(nodeId); - Long localeId = localeDAO.getOrCreateDefaultLocalePair().getFirst(); - addNodePropertyImpl(node, qname, propertyValue, localeId); - - // Record change ID - recordNodeUpdate( - node, - Collections.singletonMap(qname, propertyValue)); - } - - public void addNodeProperties(Long nodeId, Map properties) - { - Node node = getNodeNotNull(nodeId); - - Long localeId = localeDAO.getOrCreateDefaultLocalePair().getFirst(); - for (Map.Entry entry : properties.entrySet()) - { - QName qname = entry.getKey(); - if (AuditableProperties.isAuditableProperty(qname)) - { - continue; - } - Serializable value = entry.getValue(); - addNodePropertyImpl(node, qname, value, localeId); - } - - // Record change ID - recordNodeUpdate(node, properties); - } - - public void setNodeProperties(Long nodeId, Map propertiesIncl) - { - /* - * TODO: Put into interceptor - * This method will replace all properties. We therefore remove all existing content data. - * New ContentData entities will be created. Re-using content data will mean comparing old - * with new - it is faster to just create a new row. - */ - Set contentQNames = new HashSet(dictionaryService.getAllProperties(DataTypeDefinition.CONTENT)); - Set contentQNameIds = qnameDAO.convertQNamesToIds(contentQNames, false); - // Flush the session to ensure this non-hibernate DAO can do its job - getHibernateTemplate().execute(new SessionFlusher()); - contentDataDAO.deleteContentDataForNode(nodeId, contentQNameIds); - - Node node = getNodeNotNull(nodeId); - - // Handle cm:auditable. These need to be removed from the properties. - Map properties = new HashMap(propertiesIncl.size()); - for (Map.Entry entry : propertiesIncl.entrySet()) - { - QName propertyQName = entry.getKey(); - Serializable value = entry.getValue(); - if (AuditableProperties.isAuditableProperty(propertyQName)) - { - continue; - } - // The value was NOT an auditable value - properties.put(propertyQName, value); - } - - // Convert - Map persistableProperties = HibernateNodeDaoServiceImpl.convertToPersistentProperties( - properties, - qnameDAO, - localeDAO, - contentDataDAO, - dictionaryService); - - // Get the persistent map attached to the node - Map nodeProperties = node.getProperties(); - - // In order to make as few changes as possible, we need to update existing properties wherever possible. - // This means keeping track of map keys that weren't updated - Set toRemove = new HashSet(nodeProperties.keySet()); - - // Loop over the converted values and update the persisted node properties map - for (Map.Entry entry : persistableProperties.entrySet()) - { - PropertyMapKey key = entry.getKey(); - toRemove.remove(key); - // Add the value to the node's map - nodeProperties.put(key, entry.getValue()); - } - - // Now remove all untouched keys - for (PropertyMapKey key : toRemove) - { - nodeProperties.remove(key); - } - - // Record change ID - recordNodeUpdate(node, propertiesIncl); - } - - public void removeNodeProperties(Long nodeId, Set propertyQNamesIncl) - { - /* - * TODO: Put into interceptor - * This method will replace all properties. We therefore remove all existing content data. - * New ContentData entities will be created. Re-using content data will mean comparing old - * with new - it is faster to just create a new row. - */ - Set contentQNames = new HashSet(dictionaryService.getAllProperties(DataTypeDefinition.CONTENT)); - Set contentQNamesToRemove = new HashSet(3); - for (QName propertyQName : propertyQNamesIncl) - { - if (contentQNames.contains(propertyQName)) - { - contentQNamesToRemove.add(propertyQName); - } - } - Set contentQNamesToRemoveIds = qnameDAO.convertQNamesToIds(contentQNamesToRemove, false); - - // Flush the session to ensure this non-hibernate DAO can do its job - getHibernateTemplate().execute(new SessionFlusher()); - contentDataDAO.deleteContentDataForNode(nodeId, contentQNamesToRemoveIds); - - Node node = getNodeNotNull(nodeId); - - // Handle cm:auditable. These need to be removed from the list. - Set propertyQNames = new HashSet(propertyQNamesIncl.size()); - for (QName propertyQName : propertyQNamesIncl) - { - if (AuditableProperties.isAuditableProperty(propertyQName)) - { - continue; - } - propertyQNames.add(propertyQName); - } - - Map nodeProperties = node.getProperties(); - - Set propertyQNameIds = qnameDAO.convertQNamesToIds(propertyQNames, true); - - // Loop over the current properties and remove any that have the same qname. - // Make a copy as we will modify the original map. - Set entrySet = new HashSet(nodeProperties.keySet()); - for (PropertyMapKey propertyMapKey : entrySet) - { - Long propertyQNameId = propertyMapKey.getQnameId(); - if (propertyQNameIds.contains(propertyQNameId)) - { - nodeProperties.remove(propertyMapKey); - } - } - - // Record change ID - recordNodeUpdate(node); - } - - public Set getNodeAspects(Long nodeId) - { - Node node = getNodeNotNull(nodeId); - Set nodeAspects = node.getAspects(); - - // Convert - Set nodeAspectQNames = qnameDAO.convertIdsToQNames(nodeAspects); - - // Add sys:referenceable - nodeAspectQNames.add(ContentModel.ASPECT_REFERENCEABLE); - - // Make immutable - return nodeAspectQNames; - } - - public void addNodeAspects(Long nodeId, Set aspectQNames) - { - Node node = getNodeNotNull(nodeId); - - aspectQNames = new HashSet(aspectQNames); - // Remove sys:referenceable - aspectQNames.remove(ContentModel.ASPECT_REFERENCEABLE); - - // Convert - Set aspectQNameIds = qnameDAO.convertQNamesToIds(aspectQNames, true); - - // Add them - Set nodeAspects = node.getAspects(); - nodeAspects.addAll(aspectQNameIds); - - if (hasNodeAspect(node, ContentModel.ASPECT_ROOT)) - { - parentAssocsCache.remove(nodeId); - } - - // Record change ID - recordNodeUpdate(node); - } - - public void removeNodeAspects(Long nodeId, Set aspectQNames) - { - Node node = getNodeNotNull(nodeId); - - aspectQNames = new HashSet(aspectQNames); - // Remove sys:referenceable - aspectQNames.remove(ContentModel.ASPECT_REFERENCEABLE); - // Handle cm:auditable - aspectQNames.remove(ContentModel.ASPECT_AUDITABLE); - - // Convert - Set aspectQNameIds = qnameDAO.convertQNamesToIds(aspectQNames, false); - - // Remove them - Set nodeAspects = node.getAspects(); - nodeAspects.removeAll(aspectQNameIds); - - if (aspectQNames.contains(ContentModel.ASPECT_ROOT)) - { - parentAssocsCache.remove(nodeId); - } - - // Record change ID - recordNodeUpdate(node); - } - - public boolean hasNodeAspect(Long nodeId, QName aspectQName) - { - // Shortcut sys:referenceable - if (aspectQName.equals(ContentModel.ASPECT_REFERENCEABLE)) - { - return true; - } - Node node = getNodeNotNull(nodeId); - return hasNodeAspect(node, aspectQName); - } - - private boolean hasNodeAspect(Node node, QName aspectQName) - { - return hasNodeAspect(qnameDAO, node, aspectQName); - } - - private static boolean hasNodeAspect(QNameDAO qnameDAO, Node node, QName aspectQName) - { - Pair aspectQNamePair = qnameDAO.getQName(aspectQName); - if (aspectQNamePair == null) - { - return false; - } - - Set nodeAspects = node.getAspects(); - return nodeAspects.contains(aspectQNamePair.getFirst()); - } - - /** - * Manually ensures that all cascading of associations is taken care of - */ - public void deleteNode(Long nodeId) - { - /* - * TODO: Put into interceptor - * This method will remove all properties. We therefore remove all existing content data. - */ - Set contentQNames = new HashSet(dictionaryService.getAllProperties(DataTypeDefinition.CONTENT)); - Set contentQNamesToRemoveIds = qnameDAO.convertQNamesToIds(contentQNames, false); - - // Flush the session to ensure this non-hibernate DAO can do its job - getHibernateTemplate().execute(new SessionFlusher()); - contentDataDAO.deleteContentDataForNode(nodeId, contentQNamesToRemoveIds); - - Node node = getNodeNotNull(nodeId); - - // Propagate timestamps - propagateTimestamps(node); - - Set deletedChildAssocIds = new HashSet(10); - deleteNodeInternal(node, false, deletedChildAssocIds); - - // Record change ID - recordNodeDelete(node); - } - - /** - * Final purge of the node entry. No transaction recording is done for this. - */ - public void purgeNode(Long nodeId) - { - Node node = (Node) getSession().get(NodeImpl.class, nodeId); - if (node != null) - { - getHibernateTemplate().delete(node); - } - } - - /** - * Ensures that parent association entries are removed for all children of a given node - */ - private void removeParentAssocCacheEntriesForParent(final Long parentNodeId) - { - HibernateCallback getChildNodeIdsCallback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_NODE_IDS) - .setLong("parentId", parentNodeId); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults results = null; - try - { - results = (ScrollableResults) getHibernateTemplate().execute(getChildNodeIdsCallback); - - while (results.next()) - { - Long childNodeId = results.getLong(0); - parentAssocsCache.remove(childNodeId); - if (isDebugParentAssocCacheEnabled) - { - loggerParentAssocsCache.debug( - "Parent associations cache - Removing entry: \n" + - " Node: " + childNodeId); - } - } - } - finally - { - if(results != null) - { - results.close(); - } - } - } - - private static final String QUERY_DELETE_PARENT_ASSOCS = "node.DeleteParentAssocs"; - private static final String QUERY_DELETE_CHILD_ASSOCS = "node.DeleteChildAssocs"; - private static final String QUERY_DELETE_NODE_ASSOCS = "node.DeleteNodeAssocs"; - - /** - * Does a full cleanup of the node if the deleted flag is off. If - * the node is marked as deleted then the cleanup is assumed to be - * unnecessary and the node entry itself is cleaned up. - * - * @param node the node to delete - * @param cascade true to cascade delete - * @param deletedChildAssocIds previously deleted child associations - */ - @SuppressWarnings("unchecked") - private void deleteNodeInternal(Node node, boolean cascade, Set deletedChildAssocIds) - { - final Long nodeId = node.getId(); - - // delete all parent assocs - if (isDebugEnabled) - { - logger.debug("Deleting child assocs of node " + nodeId); - } - // Make sure that the cache is updated - removeParentAssocCacheEntriesForParent(nodeId); - - HibernateCallback deleteParentAssocsCallback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_DELETE_CHILD_ASSOCS) - .setLong("parentId", nodeId); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.executeUpdate(); - } - }; - getHibernateTemplate().execute(deleteParentAssocsCallback); - - // delete all child assocs - if (isDebugEnabled) - { - logger.debug("Deleting parent assocs of node " + nodeId); - } - HibernateCallback deleteChildAssocsCallback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_DELETE_PARENT_ASSOCS) - .setLong("childId", nodeId); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.executeUpdate(); - } - }; - getHibernateTemplate().execute(deleteChildAssocsCallback); - - // delete all node associations to and from - if (isDebugEnabled) - { - logger.debug("Deleting source and target assocs of node " + node.getId()); - } - HibernateCallback deleteNodeAssocsCallback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_DELETE_NODE_ASSOCS) - .setLong("nodeId", nodeId); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.executeUpdate(); - } - }; - getHibernateTemplate().execute(deleteNodeAssocsCallback); - - // Delete deltas - usageDeltaDAO.deleteDeltas(nodeId); - - // Wipe out properties and aspects - node.getProperties().clear(); - node.getAspects().clear(); - - // delete ACLs - - DbAccessControlList dbAcl = node.getAccessControlList(); - node.setAccessControlList(null); - if(dbAcl != null) - { - if(dbAcl.getAclType() == ACLType.DEFINING) - { - getHibernateTemplate().delete(dbAcl); - } - if(dbAcl.getAclType() == ACLType.SHARED) - { - // check unused - Long defining = dbAcl.getInheritsFrom(); - if(getHibernateTemplate().get(DbAccessControlListImpl.class, defining) == null) - { - final Long id = dbAcl.getId(); - HibernateCallback check = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Criteria criteria = getSession().createCriteria(NodeImpl.class, "n"); - criteria.add(Restrictions.eq("n.accessControlList.id", id)); - criteria.setProjection(Projections.rowCount()); - return criteria.list(); - } - }; - List list = (List)getHibernateTemplate().execute(check); - if(list.get(0).intValue() == 0) - { - getHibernateTemplate().delete(dbAcl); - } - } - } - } - - // Mark the node as deleted - node.setDeleted(true); - - // Remove node from cache - parentAssocsCache.remove(nodeId); - if (isDebugParentAssocCacheEnabled) - { - loggerParentAssocsCache.debug("\n" + - "Parent associations cache - Removing entry: \n" + - " Node: " + nodeId); - } - // done - } - private long getCrc(String str) { CRC32 crc = new CRC32(); try { - crc.update(str.getBytes("UTF-8")); // https://issues.alfresco.com/jira/browse/ALFCOM-1335 + crc.update(str.getBytes("UTF-8")); // https://issues.alfresco.com/jira/browse/ALFCOM-1335 } catch (UnsupportedEncodingException e) { @@ -1976,8 +640,9 @@ public class HibernateNodeDaoServiceImpl } return crc.getValue(); } - + private static final String TRUNCATED_NAME_INDICATOR = "~~~"; + private String getShortName(String str) { int length = str.length(); @@ -1992,17 +657,16 @@ public class HibernateNodeDaoServiceImpl return ret.toString(); } } - + /** - * Explicitly flushes the session looking out for {@link #DUPLICATE_CHILD_NAME_EXCEPTIONS exceptions} - * indicating that the child association name constraint has been violated. + * Explicitly flushes the session looking out for {@link #DUPLICATE_CHILD_NAME_EXCEPTIONS exceptions} indicating + * that the child association name constraint has been violated. *

- * NOTE: The Hibernate session will be flushed prior to calling the callback. This is necessary - * to prevent legitimate other contstraint violations from being dressed up as - * {@link DuplicateChildNodeNameException}. + * NOTE: The Hibernate session will be flushed prior to calling the callback. This is necessary to prevent + * legitimate other contstraint violations from being dressed up as {@link DuplicateChildNodeNameException}. * - * @param childAssocChangingCallback the callback in which the child assoc is modified - * @return Returns the callback's result + * @param childAssocChangingCallback the callback in which the child assoc is modified + * @return Returns the callback's result */ private Object writeChildAssocChanges( HibernateCallback childAssocChangingCallback, @@ -2016,21 +680,19 @@ public class HibernateNodeDaoServiceImpl try { Object ret = getHibernateTemplate().execute(childAssocChangingCallback); - // Now flush. Note that we *force* it to flush as the dirty flag will not have been set. + // Now flush. Note that we *force* it to flush as the dirty flag will not have been set. DirtySessionMethodInterceptor.flushSession(getSession(false), true); // No clashes return ret; } catch (Throwable e) { - Throwable constraintViolation = (Throwable) ExceptionStackUtil.getCause( - e, - DUPLICATE_CHILD_NAME_EXCEPTIONS); + Throwable constraintViolation = (Throwable) ExceptionStackUtil.getCause(e, DUPLICATE_CHILD_NAME_EXCEPTIONS); if (constraintViolation == null) { // It was something else - RuntimeException ee = AlfrescoRuntimeException.makeRuntimeException( - e, "Exception while flushing child assoc to database"); + RuntimeException ee = AlfrescoRuntimeException.makeRuntimeException(e, + "Exception while flushing child assoc to database"); throw ee; } else if (constraintViolation instanceof SQLGrammarException) @@ -2043,153 +705,32 @@ public class HibernateNodeDaoServiceImpl else { // It was something else - RuntimeException ee = AlfrescoRuntimeException.makeRuntimeException( - e, "Exception while flushing child assoc to database"); + RuntimeException ee = AlfrescoRuntimeException.makeRuntimeException(e, + "Exception while flushing child assoc to database"); throw ee; } } // We caught an exception that indicates a duplicate child if (isDebugEnabled) { - logger.debug( - "Duplicate child association detected: \n" + - " Parent node: " + parentNodeRef + "\n" + - " Child node name: " + childName, - e); + logger.debug("Duplicate child association detected: \n" + " Parent node: " + parentNodeRef + "\n" + + " Child node name: " + childName, e); } throw new DuplicateChildNodeNameException(parentNodeRef, assocTypeQName, childName); } } - - public Pair newChildAssoc( - Long parentNodeId, - Long childNodeId, - final boolean isPrimary, - final QName assocTypeQName, - final QName assocQName, - String newName) - { - final Node parentNode = (Node) getSession().get(NodeImpl.class, parentNodeId); - final Node childNode = (Node) getSession().get(NodeImpl.class, childNodeId); - - final Pair childNameUnique = getChildNameUnique(assocTypeQName, newName); - - final ChildAssoc assoc = new ChildAssocImpl(); - HibernateCallback newAssocCallback = new HibernateCallback() - { - public Object doInHibernate(Session session) throws HibernateException, SQLException - { - assoc.setTypeQName(qnameDAO, assocTypeQName); - assoc.setChildNodeName(childNameUnique.getFirst()); - assoc.setChildNodeNameCrc(childNameUnique.getSecond()); - assoc.setQName(qnameDAO, assocQName); - assoc.setIsPrimary(isPrimary); - assoc.setIndex(-1); - // maintain inverse sets - assoc.buildAssociation(parentNode, childNode); - // Save it - return session.save(assoc); - } - }; - Long assocId = (Long) writeChildAssocChanges( - newAssocCallback, - parentNode.getNodeRef(), - assocTypeQName, - childNameUnique.getFirst()); - - // Add it to the cache - NodeInfo nodeInfo = parentAssocsCache.get(childNodeId); - if (nodeInfo == null) - { - // There isn't an entry in the cache, so go and make one - nodeInfo = getParentAssocsInternal(childNodeId); - } - else - { - // Copy the list when we add to it - nodeInfo = nodeInfo.addAssoc(assocId, assoc, qnameDAO); - parentAssocsCache.put(childNodeId, nodeInfo); - } - if (isDebugParentAssocCacheEnabled) - { - loggerParentAssocsCache.debug("\n" + - "Parent associations cache - Updating entry: \n" + - " Node: " + childNodeId + "\n" + - " Assocs: " + nodeInfo.getParentAssocs().keySet()); - } - - // If this is a primary association then update the permissions - if (isPrimary) - { - DbAccessControlList inherited = parentNode.getAccessControlList(); - if (inherited == null) - { - // not fixde up yet or unset - } - else - { - // Get the parent's inherited ACLs - DbAccessControlList inheritedAcl = aclDaoComponent.getDbAccessControlList( - aclDaoComponent.getInheritedAccessControlList(inherited.getId())); - childNode.setAccessControlList(inheritedAcl); - } - } - - // Record change ID - recordNodeUpdate(childNode); - // done - return new Pair(assocId, assoc.getChildAssocRef(qnameDAO)); - } - - public void setChildNameUnique(final Long childAssocId, final String childName) - { - /* - * Work out if there has been any change in the name - */ - - final ChildAssoc childAssoc = getChildAssocNotNull(childAssocId); - final Node parentNode = childAssoc.getParent(); - - QName childAssocTypeQName = childAssoc.getTypeQName(qnameDAO); - final Pair childNameUnique = getChildNameUnique(childAssocTypeQName, childName); - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - childAssoc.setChildNodeName(childNameUnique.getFirst()); - childAssoc.setChildNodeNameCrc(childNameUnique.getSecond().longValue()); - return null; - } - }; - writeChildAssocChanges( - callback, - parentNode.getNodeRef(), - childAssoc.getTypeQName(qnameDAO), - childName); - - // Done - if (isDebugEnabled) - { - logger.debug( - "Updated child association: \n" + - " Parent: " + parentNode + "\n" + - " Child Assoc: " + childAssoc); - } - } - /** - * Apply the cm:name to the child association. If the child name is null then - * a GUID is generated as a substitute. + * Apply the cm:name to the child association. If the child name is null then a GUID is generated as + * a substitute. * - * @param childName the cm:name applying to the association. + * @param childName the cm:name applying to the association. */ private Pair getChildNameUnique(QName assocTypeQName, String childName) { - String childNameNewShort; // - long childNameNewCrc = -1L; // By default, they don't compete - + String childNameNewShort; // + long childNameNewCrc = -1L; // By default, they don't compete + if (childName == null) { childNameNewShort = GUID.generate(); @@ -2221,8 +762,8 @@ public class HibernateNodeDaoServiceImpl } return new Pair(childNameNewShort, childNameNewCrc); } - - public Pair updateChildAssoc( + + private Pair updateChildAssoc( Long childAssocId, Long parentNodeId, Long childNodeId, @@ -2240,8 +781,8 @@ public class HibernateNodeDaoServiceImpl final Node newChildNode = getNodeNotNull(childNodeId); final NodeRef newChildNodeRef = newChildNode.getNodeRef(); final Pair childNameUnique = getChildNameUnique(assocTypeQName, childName); - - // Reset the cm:name duplicate handling. This has to be redone, if required. + + // Reset the cm:name duplicate handling. This has to be redone, if required. HibernateCallback updateChildAssocCallback = new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException, SQLException @@ -2259,39 +800,35 @@ public class HibernateNodeDaoServiceImpl return null; } }; - writeChildAssocChanges( - updateChildAssocCallback, - newParentNode.getNodeRef(), - assocTypeQName, - childNameUnique.getFirst()); + writeChildAssocChanges(updateChildAssocCallback, newParentNode.getNodeRef(), assocTypeQName, childNameUnique + .getFirst()); // Record change ID if (oldChildNodeRef.equals(newChildNodeRef)) { - recordNodeUpdate(newChildNode); +// recordNodeUpdate(newChildNode); } else { - recordNodeUpdate(newChildNode); +// recordNodeUpdate(newChildNode); } - + // Update the inherited associations if either the parent or child nodes have changed and // the association is primary - if (isPrimary && ( - !oldParentNode.getId().equals(parentNodeId) || - !oldChildNode.getId().equals(childNodeId)) - ) + if (isPrimary && (!oldParentNode.getId().equals(parentNodeId) || !oldChildNode.getId().equals(childNodeId))) { - if (newChildNode.getAccessControlList() != null) + Long newChildNodeAclId = newChildNode.getAclId(); + if (newChildNodeAclId != null) { - Long targetAclId = newChildNode.getAccessControlList().getId(); + Long targetAclId = newChildNodeAclId; AccessControlListProperties aclProperties = aclDaoComponent.getAccessControlListProperties(targetAclId); Boolean targetAclInherits = aclProperties.getInherits(); if ((targetAclInherits != null) && (targetAclInherits.booleanValue())) { - if (newParentNode.getAccessControlList() != null) + Long newParentNodeAclId = newParentNode.getAclId(); + if (newParentNodeAclId != null) { - Long parentAclId = newParentNode.getAccessControlList().getId(); + Long parentAclId = newParentNodeAclId; Long inheritedAclId = aclDaoComponent.getInheritedAccessControlList(parentAclId); if (aclProperties.getAclType() == ACLType.DEFINING) { @@ -2312,7 +849,10 @@ public class HibernateNodeDaoServiceImpl else if (aclProperties.getAclType() == ACLType.SHARED) { // there is nothing to inherit - newChildNode.setAccessControlList(null); + newChildNode.setAclId(null); + + // TODO - will be refactored out (ensure node.aclId change is flushed) + flush(); } // throw new IllegalStateException("Share bug"); @@ -2321,12 +861,13 @@ public class HibernateNodeDaoServiceImpl } else { - if (newChildNode.getAccessControlList() != null) + // FIXME: dead code ? + if (newChildNodeAclId != null) { - Long parentAcl = newParentNode.getAccessControlList().getId(); + Long parentAcl = newChildNodeAclId; Long inheritedAcl = aclDaoComponent.getInheritedAccessControlList(parentAcl); setFixedAcls(childNodeId, inheritedAcl, true, null); - } + } } } @@ -2338,15 +879,11 @@ public class HibernateNodeDaoServiceImpl } /** - * This code is here, and not in another DAO, in order to avoid unnecessary circular callbacks - * and cyclical dependencies. It would be nice if the ACL code could be separated (or combined) - * but the node tree walking code is best done right here. + * This code is here, and not in another DAO, in order to avoid unnecessary circular callbacks and cyclical + * dependencies. It would be nice if the ACL code could be separated (or combined) but the node tree walking code is + * best done right here. */ - private void setFixedAcls( - final Long nodeId, - final Long mergeFromAclId, - final boolean set, - Set processedNodes) + private void setFixedAcls(final Long nodeId, final Long mergeFromAclId, final boolean set, Set processedNodes) { // ETHREEOH-3088: Cut/Paste into same hierarchy if (processedNodes == null) @@ -2355,22 +892,23 @@ public class HibernateNodeDaoServiceImpl } if (!processedNodes.add(nodeId)) { - logger.error( - "Cyclic parent-child relationship detected: \n" + - " current node: " + nodeId); + logger.error("Cyclic parent-child relationship detected: \n" + " current node: " + nodeId); throw new CyclicChildRelationshipException("Node has been pasted into its own tree.", null); } - + Node mergeFromNode = getNodeNotNull(nodeId); - + if (set) { - DbAccessControlList mergeFromAcl = aclDaoComponent.getDbAccessControlList(mergeFromAclId); - mergeFromNode.setAccessControlList(mergeFromAcl); + AccessControlListProperties mergeFromAcl = aclDaoComponent.getAccessControlListProperties(mergeFromAclId); + mergeFromNode.setAclId(mergeFromAcl.getId()); + + // TODO - will be refactored out (ensure node.aclId change is flushed) + flush(); } final List childNodeIds = new ArrayList(100); - NodeDaoService.ChildAssocRefQueryCallback callback = new NodeDaoService.ChildAssocRefQueryCallback() + NodeDAO.ChildAssocRefQueryCallback callback = new NodeDAO.ChildAssocRefQueryCallback() { public boolean handle( Pair childAssocPair, @@ -2389,14 +927,14 @@ public class HibernateNodeDaoServiceImpl public boolean preLoadNodes() { return true; - } + } }; // Get all child associations with the specific qualified name - getChildAssocs(nodeId, callback, false); +// nodeDAO.getChildAssocs(nodeId, null, (QName) null, (QName) null, Boolean.TRUE, null, callback); for (Long childNodeId : childNodeIds) { Node childNode = getNodeNotNull(childNodeId); - DbAccessControlList acl = childNode.getAccessControlList(); + AccessControlListProperties acl = aclDaoComponent.getAccessControlListProperties(childNode.getAclId()); if (acl == null) { @@ -2410,7 +948,8 @@ public class HibernateNodeDaoServiceImpl else if (acl.getAclType() == ACLType.DEFINING) { @SuppressWarnings("unused") - List newChanges = aclDaoComponent.mergeInheritedAccessControlList(mergeFromAclId, acl.getId()); + List newChanges = aclDaoComponent.mergeInheritedAccessControlList(mergeFromAclId, acl + .getId()); } else { @@ -2419,652 +958,6 @@ public class HibernateNodeDaoServiceImpl } } - public void getChildAssocs(final Long parentNodeId, final ChildAssocRefQueryCallback resultsCallback, final boolean recurse) - { - Node parentNode = getNodeNotNull(parentNodeId); - - ChildAssocRefQueryCallback queryCallback = resultsCallback; - final List childNodeIds = new ArrayList(100); - if (recurse) - { - // In order to recurse, without loading the DB with nested scrollable queries, we have to - // record the IDs of the children coming from the query. This is done by adding our own - // callback to the results iterator and passing values to the client's callback from there. - queryCallback = new ChildAssocRefQueryCallback() - { - public boolean handle( - Pair childAssocPair, - Pair parentNodePair, - Pair childNodePair) - { - // Pass the values to the client code - boolean recurseLocal = resultsCallback.handle(childAssocPair, parentNodePair, childNodePair); - if (recurseLocal) - { - childNodeIds.add(childNodePair.getFirst()); - } - return false; - } - - public boolean preLoadNodes() - { - return resultsCallback.preLoadNodes(); - } - }; - } - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_REFS) - .setLong("parentId", parentNodeId); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults queryResults = null; - try - { - queryResults = (ScrollableResults) getHibernateTemplate().execute(callback); - convertToChildAssocRefs(parentNode, queryResults, queryCallback); - - // Now recurse, if required - if (recurse) - { - for (Long childNodeId : childNodeIds) - { - getChildAssocs(childNodeId, resultsCallback, recurse); - } - } - // Done - } - finally - { - if (queryResults != null) - { - queryResults.close(); - } - } - // Done - } - - public void getChildAssocs(final Long parentNodeId, final QName assocQName, ChildAssocRefQueryCallback resultsCallback) - { - final Pair assocQNameNamespacePair = qnameDAO.getNamespace(assocQName.getNamespaceURI()); - final String assocQNameLocalName = assocQName.getLocalName(); - if (assocQNameNamespacePair == null) - { - // There can't be any matches - return; - } - Node parentNode = getNodeNotNull(parentNodeId); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_REFS_BY_QNAME) - .setLong("parentId", parentNodeId) - .setLong("qnameNamespaceId", assocQNameNamespacePair.getFirst()) - .setString("qnameLocalName", assocQNameLocalName) - .setLong("qnameCrc", ChildAssocImpl.getCrc(assocQName)); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults queryResults = null; - try - { - queryResults = (ScrollableResults) getHibernateTemplate().execute(callback); - convertToChildAssocRefs(parentNode, queryResults, resultsCallback); - } - finally - { - if (queryResults != null) - { - queryResults.close(); - } - } - // Done - } - - public void getChildAssocs(final Long parentNodeId, QName assocTypeQName, Collection childNames, final ChildAssocRefQueryCallback resultsCallback) - { - /* - * The child names are converted to the stardard form (shortened, lower-case) and used directly in an IN clause. - * In order to guarantee uniqueness, the CRC for each matching, stardard-form name is checked for a match before - * the result is passed to the client's callback handler. - */ - - // Shortcut - if (childNames.size() == 0) - { - return; - } - else if (childNames.size() > 1000) - { - throw new IllegalArgumentException("Unable to process more than 1000 child names in getChildAssocs"); - } - final Pair assocTypeQNamePair = qnameDAO.getQName(assocTypeQName); - if (assocTypeQNamePair == null) - { - return; - } - - // Convert the child names and compile the CRC values - final Set crcValues = new HashSet(childNames.size() * 2); - final Set nameValues = new HashSet(childNames.size() * 2); - for (String childName : childNames) - { - String childNameLower = childName.toLowerCase(); - String childNameShort = getShortName(childNameLower); - Long childNameLowerCrc = new Long(getCrc(childNameLower)); - crcValues.add(childNameLowerCrc); - nameValues.add(childNameShort); - } - - Node parentNode = getNodeNotNull(parentNodeId); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_REFS_BY_TYPE_AND_NAME_LIST) - .setLong("parentId", parentNodeId) - .setLong("typeQNameId", assocTypeQNamePair.getFirst()) - .setParameterList("childNodeNameCrcs", crcValues); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - - // Create an extended callback to filter out the crc values - ChildAssocRefQueryCallbackFilter filterCallback = new ChildAssocRefQueryCallbackFilter() - { - public boolean isDesiredRow( - Pair childAssocPair, - Pair parentNodePair, - Pair childNodePair, - String assocChildNodeName, Long assocChildNodeNameCrc) - { - // The CRC value must be in the list - return nameValues.contains(assocChildNodeName); - } - /** - * Defers to the client's handler - */ - public boolean handle(Pair childAssocPair, Pair parentNodePair, Pair childNodePair) - { - return resultsCallback.handle(childAssocPair, parentNodePair, childNodePair); - } - - public boolean preLoadNodes() - { - return resultsCallback.preLoadNodes(); - } - }; - - ScrollableResults queryResults = null; - try - { - queryResults = (ScrollableResults) getHibernateTemplate().execute(callback); - convertToChildAssocRefs(parentNode, queryResults, filterCallback); - } - finally - { - if (queryResults != null) - { - queryResults.close(); - } - } - } - - public void getChildAssocsByTypeQNames( - final Long parentNodeId, - final List assocTypeQNames, - ChildAssocRefQueryCallback resultsCallback) - { - // Convert the type QNames to entities - - final Set assocTypeQNameSet = new HashSet(assocTypeQNames); - final Set assocTypeQNameIds = qnameDAO.convertQNamesToIds(assocTypeQNameSet, false); - // Shortcut if there are no assoc types - if (assocTypeQNameIds.size() == 0) - { - return; - } - - Node parentNode = getNodeNotNull(parentNodeId); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_REFS_BY_TYPEQNAMES) - .setLong("parentId", parentNodeId) - .setParameterList("childAssocTypeQNameIds", assocTypeQNameIds); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults queryResults = null; - try - { - queryResults = (ScrollableResults) getHibernateTemplate().execute(callback); - convertToChildAssocRefs(parentNode, queryResults, resultsCallback); - } - finally - { - if (queryResults != null) - { - queryResults.close(); - } - } - // Done - } - - public void getChildAssocsByTypeQNameAndQName( - final Long parentNodeId, - final QName assocTypeQName, - final QName assocQName, - ChildAssocRefQueryCallback resultsCallback) - { - Node parentNode = getNodeNotNull(parentNodeId); - - final Pair assocTypeQNamePair = qnameDAO.getQName(assocTypeQName); - final Pair assocQNameNamespacePair = qnameDAO.getNamespace(assocQName.getNamespaceURI()); - final String assocQNameLocalName = assocQName.getLocalName(); - // Shortcut if possible - if (assocTypeQNamePair == null || assocQNameNamespacePair == null) - { - return; - } - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_REFS_BY_TYPEQNAME_AND_QNAME) - .setLong("parentId", parentNodeId) - .setLong("typeQNameId", assocTypeQNamePair.getFirst()) - .setLong("qnameNamespaceId", assocQNameNamespacePair.getFirst()) - .setString("qnameLocalName", assocQNameLocalName) - .setLong("qnameCrc", ChildAssocImpl.getCrc(assocQName)); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults queryResults = null; - try - { - queryResults = (ScrollableResults) getHibernateTemplate().execute(callback); - convertToChildAssocRefs(parentNode, queryResults, resultsCallback); - } - finally - { - if (queryResults != null) - { - queryResults.close(); - } - } - // Done - } - - public void getChildAssocsByChildTypes( - final Long parentNodeId, - Set childNodeTypeQNames, - ChildAssocRefQueryCallback resultsCallback) - { - Node parentNode = getNodeNotNull(parentNodeId); - - // Get the IDs for all the QNames we are after - final Set childNodeTypeQNameIds = qnameDAO.convertQNamesToIds(childNodeTypeQNames, false); - // Shortcut if there are no QNames available - if (childNodeTypeQNameIds.size() == 0) - { - return; - } - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOC_REFS_BY_CHILD_TYPEQNAME) - .setLong("parentId", parentNodeId) - .setParameterList("childTypeQNameIds", childNodeTypeQNameIds); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults queryResults = null; - try - { - queryResults = (ScrollableResults) getHibernateTemplate().execute(callback); - convertToChildAssocRefs(parentNode, queryResults, resultsCallback); - } - finally - { - if (queryResults != null) - { - queryResults.close(); - } - } - // Done - } - - public void getPrimaryChildAssocs(final Long parentNodeId, ChildAssocRefQueryCallback resultsCallback) - { - Node parentNode = getNodeNotNull(parentNodeId); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_PRIMARY_CHILD_ASSOCS) - .setLong("parentId", parentNodeId); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults queryResults = null; - try - { - queryResults = (ScrollableResults) getHibernateTemplate().execute(callback); - convertToChildAssocRefs(parentNode, queryResults, resultsCallback); - } - finally - { - if (queryResults != null) - { - queryResults.close(); - } - } - // Done - } - - public void getPrimaryChildAssocsNotInSameStore(final Long parentNodeId, ChildAssocRefQueryCallback resultsCallback) - { - Node parentNode = getNodeNotNull(parentNodeId); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_PRIMARY_CHILD_ASSOCS_NOT_IN_SAME_STORE) - .setLong("parentId", parentNodeId); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults queryResults = null; - try - { - queryResults = (ScrollableResults) getHibernateTemplate().execute(callback); - convertToChildAssocRefs(parentNode, queryResults, resultsCallback); - } - finally - { - if (queryResults != null) - { - queryResults.close(); - } - } - // Done - } - - public Pair getChildAssoc(final Long parentNodeId, final QName assocTypeQName, final String childName) - { - final Pair assocTypeQNamePair = qnameDAO.getQName(assocTypeQName); - // Shortcut - if (assocTypeQNamePair == null) - { - return null; - } - - 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", parentNodeId) - .setLong("typeQNameId", assocTypeQNamePair.getFirst()) - .setLong("childNodeNameCrc", childNameLowerCrc) - .setString("childNodeName", childNameShort); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.uniqueResult(); - } - }; - ChildAssoc childAssoc = (ChildAssoc) getHibernateTemplate().execute(callback); - if (childAssoc == null) - { - return null; - } - else - { - return new Pair(childAssoc.getId(), childAssoc.getChildAssocRef(qnameDAO)); - } - } - - @SuppressWarnings("unchecked") - public Pair getChildAssoc( - final Long parentNodeId, - final Long childNodeId, - final QName assocTypeQName, - final QName assocQName) - { - - final Pair assocTypeQNamePair = qnameDAO.getQName(assocTypeQName); - final Pair assocQNameNamespacePair = qnameDAO.getNamespace(assocQName.getNamespaceURI()); - final String assocQNameLocalName = assocQName.getLocalName(); - // Shortcut if possible - if (assocTypeQNamePair == null || assocQNameNamespacePair == null) - { - return null; - } - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOCS_BY_ALL) - .setLong("parentId", parentNodeId) - .setLong("childId", childNodeId) - .setLong("typeQNameId", assocTypeQNamePair.getFirst()) - .setParameter("qnameNamespaceId", assocQNameNamespacePair.getFirst()) - .setParameter("qnameLocalName", assocQNameLocalName) - .setLong("qnameCrc", ChildAssocImpl.getCrc(assocQName)); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List childAssocs = (List) getHibernateTemplate().execute(callback); - Pair ret = null; - for (ChildAssoc childAssoc : childAssocs) - { - if (ret == null) - { - ret = new Pair(childAssoc.getId(), childAssoc.getChildAssocRef(qnameDAO)); - } - else - { - // Queue remaining assocs for a cleanup - they are duplicate - new ChildAssocDeleteTransactionListener(childAssoc.getId()); - } - } - // Done - return ret; - } - - /** - * Post-transaction removal of duplicate child associations. - * - * @author Derek Hulley - * @since 2.2SP6 - */ - private class ChildAssocDeleteTransactionListener extends TransactionListenerAdapter - { - private final Long childAssocId; - - private ChildAssocDeleteTransactionListener(Long childAssocId) - { - this.childAssocId = childAssocId; - AlfrescoTransactionSupport.bindListener(this); - } - - @Override - public boolean equals(Object obj) - { - if (obj == this) - { - return true; - } - else if (obj == null || !(obj instanceof ChildAssocDeleteTransactionListener)) - { - return false; - } - ChildAssocDeleteTransactionListener that = (ChildAssocDeleteTransactionListener) obj; - return EqualsHelper.nullSafeEquals(this.childAssocId, that.childAssocId); - } - - @Override - public int hashCode() - { - return childAssocId == null ? 0 : childAssocId.hashCode(); - } - - @Override - public void afterCommit() - { - if (transactionService.isReadOnly()) - { - // Can't write to the repo - return; - } - RetryingTransactionCallback deleteCallback = new RetryingTransactionCallback() - { - public Void execute() throws Throwable - { - deleteChildAssoc(childAssocId); - if (logger.isInfoEnabled()) - { - logger.debug("Cleaned up duplicate child assoc: " + childAssocId); - } - return null; - } - }; - try - { - transactionService.getRetryingTransactionHelper().doInTransaction(deleteCallback); - } - catch (Throwable e) - { - // This is the post-commit phase. Exceptions would be absorbed anyway. - logger.warn("Failed to delete duplicate child association with ID " + childAssocId); - } - } - } - - /** - * Columns returned are: - *

-          0 assoc.id,
-          1 assoc.typeQName,
-          2 assoc.qnameNamespace,
-          3 assoc.qnameLocalName,
-          4 assoc.qnameCrc,
-          5 assoc.childNodeName
-          6 assoc.childNodeNameCrc
-          7 assoc.isPrimary,
-          8 assoc.index,
-          9 child.id,
-         10 child.store.key.protocol,
-         11 child.store.key.identifier,
-         12 child.uuid
-     * 
- */ - @SuppressWarnings("unchecked") - private void convertToChildAssocRefs(Node parentNode, ScrollableResults results, ChildAssocRefQueryCallback resultsCallback) - { - Long parentNodeId = parentNode.getId(); - NodeRef parentNodeRef = parentNode.getNodeRef(); - Pair parentNodePair = new Pair(parentNodeId, parentNodeRef); - - List callbackResults = new ArrayList(128); - List childNodeRefs = new ArrayList(128); - - while (results.next()) - { - Object[] row = results.get(); - Long assocId = (Long) row[0]; - QName assocTypeQName = qnameDAO.getQName((Long) row[1]).getSecond(); - String assocQNameNamespace = qnameDAO.getNamespace((Long) row[2]).getSecond(); - String assocQNameLocalName = (String) row[3]; - QName assocQName = QName.createQName(assocQNameNamespace, assocQNameLocalName); - String assocChildNodeName = (String) row[5]; - Long assocChildNodeNameCrc = (Long) row[6]; - Boolean assocIsPrimary = (Boolean) row[7]; - Integer assocIndex = (Integer) row[8]; - Long childNodeId = (Long) row[9]; - String childProtocol = (String) row[10]; - String childIdentifier = (String) row[11]; - String childUuid = (String) row[12]; - NodeRef childNodeRef = new NodeRef(new StoreRef(childProtocol, childIdentifier), childUuid); - ChildAssociationRef assocRef = new ChildAssociationRef( - assocTypeQName, - parentNodeRef, - assocQName, - childNodeRef, - assocIsPrimary.booleanValue(), - assocIndex.intValue()); - Pair assocPair = new Pair(assocId, assocRef); - Pair childNodePair = new Pair(childNodeId, childNodeRef); - // Check if we are doing a filtering callback - if (resultsCallback instanceof ChildAssocRefQueryCallbackFilter) - { - ChildAssocRefQueryCallbackFilter filterCallback = (ChildAssocRefQueryCallbackFilter) resultsCallback; - boolean process = filterCallback.isDesiredRow( - assocPair, - parentNodePair, - childNodePair, - assocChildNodeName, - assocChildNodeNameCrc); - if (!process) - { - // The result is filtered out - continue; - } - } - - callbackResults.add(new Object[] {assocPair, parentNodePair, childNodePair}); - childNodeRefs.add(childNodeRef); - } - - // Cache the nodes - if (resultsCallback.preLoadNodes() && !childNodeRefs.isEmpty()) - { - cacheNodes(childNodeRefs); - } - - // Pass results to callback - for (Object[] callbackResult : callbackResults) - { - resultsCallback.handle( - (Pair) callbackResult[0], - (Pair) callbackResult[1], - (Pair) callbackResult[2]); - } - } - /** * {@inheritDoc} *

@@ -3082,58 +975,19 @@ public class HibernateNodeDaoServiceImpl /** * {@inheritDoc} *

- * Loads properties, aspects, parent associations and the ID-noderef cache. + * Loads properties, aspects, parent associations and the ID-noderef cache */ public void cacheNodes(List nodeRefs) { - /* - * ALF-2712: Performance degradation from 3.1.0 to 3.1.2 - * ALF-2784: Degradation of performance between 3.1.1 and 3.2x (observed in JSF) - * - * There is an obvious cost associated with querying the database to pull back nodes, - * and there is additional cost associated with putting the resultant entries into the - * caches. It is NO MORE expensive to check the cache than it is to put an entry into it - * - and probably cheaper considering cache replication - so we start checking nodes to see - * if they have entries before passing them over for batch loading. - * - * However, when running against a cold cache or doing a first-time query against some - * part of the repo, we will be checking for entries in the cache and consistently getting - * no results. To avoid unnecessary checking when the cache is PROBABLY cold, we - * examine the ratio of hits/misses at regular intervals. - */ - if (nodeRefs.size() < 10) + if (nodeRefs.size() == 0) { - // We only cache where the number of results is potentially - // a problem for the N+1 loading that might result. + // Nothing to cache return; } - int foundCacheEntryCount = 0; - int missingCacheEntryCount = 0; - boolean forceBatch = false; - // Group the nodes by store so that we don't *have* to eagerly join to store to get query performance Map> uuidsByStore = new HashMap>(3); for (NodeRef nodeRef : nodeRefs) { - if (!forceBatch) - { - // Is this node in the cache? - if (this.storeAndNodeIdCache.contains(nodeRef)) - { - foundCacheEntryCount++; // Don't add it to the batch - continue; - } - else - { - missingCacheEntryCount++; // Fall through and add it to the batch - } - if (foundCacheEntryCount + missingCacheEntryCount % 100 == 0) - { - // We force the batch if the number of hits drops below the number of misses - forceBatch = foundCacheEntryCount < missingCacheEntryCount; - } - } - StoreRef storeRef = nodeRef.getStoreRef(); List uuids = (List) uuidsByStore.get(storeRef); if (uuids == null) @@ -3157,14 +1011,14 @@ public class HibernateNodeDaoServiceImpl logger.debug("Pre-loaded " + size + " nodes."); } } - + /** * Loads the nodes into cache using batching. */ private void cacheNodes(StoreRef storeRef, List uuids) { - Store store = getStore(storeRef); // Be fetched from local caches - + Store store = getStore(storeRef); // Be fetched from local caches + int batchSize = 256; List batch = new ArrayList(128); for (String uuid : uuids) @@ -3183,34 +1037,22 @@ public class HibernateNodeDaoServiceImpl cacheNodesNoBatch(store, batch); } } - + /** * Uses a Critera to preload the nodes without batching */ @SuppressWarnings("unchecked") private void cacheNodesNoBatch(Store store, List uuids) { - // Get nodes and properties Criteria criteria = getSession().createCriteria(NodeImpl.class, "node"); criteria.setResultTransformer(Criteria.ROOT_ENTITY); criteria.add(Restrictions.eq("store.id", store.getId())); criteria.add(Restrictions.in("uuid", uuids)); - criteria.setFetchMode("aspects", FetchMode.SELECT); // Don't join to aspects - criteria.setCacheMode(CacheMode.PUT); - criteria.setFlushMode(FlushMode.MANUAL); - criteria.list(); - - // Get nodes and aspects - criteria = getSession().createCriteria(NodeImpl.class, "node"); - criteria.setResultTransformer(Criteria.ROOT_ENTITY); - criteria.add(Restrictions.eq("store.id", store.getId())); - criteria.add(Restrictions.in("uuid", uuids)); - criteria.setFetchMode("properties", FetchMode.SELECT); // Don't join to properties criteria.setCacheMode(CacheMode.PUT); criteria.setFlushMode(FlushMode.MANUAL); List nodeList = criteria.list(); - Set nodeIds = new HashSet(nodeList.size()*2); + Set nodeIds = new HashSet(nodeList.size() * 2); for (Node node : nodeList) { // We have duplicate nodes, so make sure we only process each node once @@ -3221,14 +1063,14 @@ public class HibernateNodeDaoServiceImpl continue; } storeAndNodeIdCache.put(node.getNodeRef(), nodeId); - } - + } + if (nodeIds.size() == 0) { // Can't query return; } - + criteria = getSession().createCriteria(ChildAssocImpl.class, "parentAssoc"); criteria.setResultTransformer(Criteria.ROOT_ENTITY); criteria.add(Restrictions.in("child.id", nodeIds)); @@ -3248,10 +1090,8 @@ public class HibernateNodeDaoServiceImpl parentAssocsOfNode.add(parentAssoc); if (isDebugParentAssocCacheEnabled) { - loggerParentAssocsCache.debug("\n" + - "Parent associations cache - Adding entry: \n" + - " Node: " + nodeId + "\n" + - " Assocs: " + parentAssocsOfNode); + loggerParentAssocsCache.debug("\n" + "Parent associations cache - Adding entry: \n" + " Node: " + + nodeId + "\n" + " Assocs: " + parentAssocsOfNode); } } // Cache NodeInfo for each node @@ -3263,143 +1103,16 @@ public class HibernateNodeDaoServiceImpl { parentAsssocsOfNode = Collections.emptyList(); } - parentAssocsCache.put(nodeId, new NodeInfo(node, qnameDAO, parentAsssocsOfNode)); - } - } - - private Collection> convertToAssocRefs(List queryResults) - { - Collection> refs = new ArrayList>(queryResults.size()); - for (NodeAssoc nodeAssoc : queryResults) - { - Long nodeAssocId = nodeAssoc.getId(); - AssociationRef assocRef = nodeAssoc.getNodeAssocRef(qnameDAO); - refs.add(new Pair(nodeAssocId, assocRef)); + parentAssocsCache.put(nodeId, new NodeInfo(node, null, qnameDAO, parentAsssocsOfNode)); } - return refs; - } - - public void getNodesWithAspect( - final QName aspectQName, - final Long minNodeId, - final int count, - NodeRefQueryCallback resultsCallback) - { - final Pair aspectQNamePair = qnameDAO.getQName(aspectQName); - // Shortcut - if (aspectQNamePair == null) - { - return; - } - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODES_WITH_ASPECT) - .setLong("aspectQNameId", aspectQNamePair.getFirst()) - .setLong("minNodeId", minNodeId) - .setMaxResults(count); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults queryResults = null; - try - { - queryResults = (ScrollableResults) getHibernateTemplate().execute(callback); - processNodeResults(queryResults, resultsCallback); - } - finally - { - if (queryResults != null) - { - queryResults.close(); - } - } - - // Done } - /** - * @deprecated Not performant. Do not use. - */ - public void getNodesWithChildrenInDifferentStore( - final Long storeId, - final Long minNodeId, - final int count, - NodeRefQueryCallback resultsCallback) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODES_WITH_CHILDREN_IN_DIFFERENT_STORE) - .setLong("parentStoreId", storeId) - .setLong("minNodeId", minNodeId) - .setMaxResults(count); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults queryResults = null; - try - { - queryResults = (ScrollableResults) getHibernateTemplate().execute(callback); - processNodeResults(queryResults, resultsCallback); - } - finally - { - if (queryResults != null) - { - queryResults.close(); - } - } - - // Done - } - - public void getChildAssocsWithoutParentAssocsOfType(final Long parentNodeId, final QName assocTypeQName, - ChildAssocRefQueryCallback resultsCallback) - { - Node parentNode = getNodeNotNull(parentNodeId); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - - Query query = session.getNamedQuery( - HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOCS_WITHOUT_PARENT_ASSOCS_OF_TYPE).setLong( - "parentId", parentNodeId).setLong("assocTypeQNameID", - qnameDAO.getOrCreateQName(assocTypeQName).getFirst()); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults queryResults = null; - try - { - queryResults = (ScrollableResults) getHibernateTemplate().execute(callback); - convertToChildAssocRefs(parentNode, queryResults, resultsCallback); - } - finally - { - if (queryResults != null) - { - queryResults.close(); - } - } - // Done - } - /** *

-            Node ID = (Long) row[0];
-            Node Protocol = (String) row[1];
-            Node Identifier = (String) row[2];
-            Node Uuid = (String) row[3];
+     * Node ID = (Long) row[0];
+     * Node Protocol = (String) row[1];
+     * Node Identifier = (String) row[2];
+     * Node Uuid = (String) row[3];
      * 
*/ private void processNodeResults(ScrollableResults queryResults, NodeRefQueryCallback resultsCallback) @@ -3422,123 +1135,9 @@ public class HibernateNodeDaoServiceImpl } } - public void deleteChildAssoc(Long assocId) - { - Set deletedChildAssocIds = new HashSet(10); - ChildAssoc assoc = getChildAssocNotNull(assocId); - deleteChildAssocInternal(assoc, false, deletedChildAssocIds); - } - - @SuppressWarnings("unchecked") - public boolean deleteChildAssoc( - final Long parentNodeId, - final Long childNodeId, - final QName assocTypeQName, - final QName assocQName) - { - final Pair assocTypeQNamePair = qnameDAO.getQName(assocTypeQName); - final Pair assocQNameNamespacePair = qnameDAO.getNamespace(assocQName.getNamespaceURI()); - final String assocQNameLocalName = assocQName.getLocalName(); - - // Shortcut - if (assocTypeQNamePair == null || assocQNameNamespacePair == null) - { - return false; - } - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CHILD_ASSOCS_BY_ALL) - .setLong("parentId", parentNodeId) - .setLong("childId", childNodeId) - .setLong("typeQNameId", assocTypeQNamePair.getFirst()) - .setParameter("qnameNamespaceId", assocQNameNamespacePair.getFirst()) - .setParameter("qnameLocalName", assocQNameLocalName); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List childAssocs = (List) getHibernateTemplate().execute(callback); - // Remove each child association with full cascade - for (ChildAssoc assoc : childAssocs) - { - deleteChildAssocInternal(assoc, false, new HashSet(0)); - } - return (childAssocs.size() > 0); - } - /** - * 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(final ChildAssoc assoc, boolean cascade, Set deletedChildAssocIds) - { - Long childAssocId = assoc.getId(); - - if (deletedChildAssocIds.contains(childAssocId)) - { - if (isDebugEnabled) - { - logger.debug("Ignoring parent-child association " + assoc.getId()); - } - return; - } - - if (isDebugEnabled) - { - logger.debug( - "Deleting parent-child association " + assoc.getId() + - (cascade ? " with" : " without") + " cascade:" + - assoc.getParent().getId() + " -> " + assoc.getChild().getId()); - } - - Node childNode = assoc.getChild(); - Long childNodeId = childNode.getId(); - - // Add remove the child association from the cache - NodeInfo oldNodeInfo = parentAssocsCache.get(childNodeId); - if (oldNodeInfo != null) - { - NodeInfo newNodeInfo = oldNodeInfo.removeAssoc(childAssocId); - parentAssocsCache.put(childNodeId, newNodeInfo); - if (this.isDebugParentAssocCacheEnabled) - { - loggerParentAssocsCache.debug("\n" + - "Parent associations cache - Updating entry: \n" + - " Node: " + childNodeId + "\n" + - " Before: " + oldNodeInfo.getParentAssocs().keySet() + "\n" + - " After: " + newNodeInfo.getParentAssocs().keySet()); - } - } - - // maintain inverse association sets - assoc.removeAssociation(); - // remove instance - getHibernateTemplate().delete(assoc); -// // ensure that we don't attempt to delete it twice -// deletedChildAssocIds.add(childAssocId); -// -// 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 -// */ -// } - } - - /** - * @param childNode the child node - * @return Returns the parent associations without any interpretation + * @param childNode the child node + * @return Returns the parent associations without any interpretation */ @SuppressWarnings("unchecked") private NodeInfo getParentAssocsInternal(final Long childNodeId) @@ -3564,12 +1163,12 @@ public class HibernateNodeDaoServiceImpl { parentAssocsCache.remove(childNodeId); nodeInfo = null; - } + } } // Did we manage to get the parent assocs if (nodeInfo == null) { - // Assume stale data if the node has been deleted + // Assume stale data if the node has been deleted Node node = getNodeNotNull(childNodeId); if (node.getDeleted()) { @@ -3578,819 +1177,34 @@ public class HibernateNodeDaoServiceImpl if (isDebugParentAssocCacheEnabled) { - loggerParentAssocsCache.debug("\n" + - "Parent associations cache - Miss: \n" + - " Node: " + childNodeId + "\n" + - " Assocs: null"); + loggerParentAssocsCache.debug("\n" + "Parent associations cache - Miss: \n" + " Node: " + + childNodeId + "\n" + " Assocs: null"); } HibernateCallback callback = new HibernateCallback() { public Object doInHibernate(Session session) { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_PARENT_ASSOCS) - .setLong("childId", childNodeId); + Query query = session.getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_PARENT_ASSOCS).setLong( + "childId", childNodeId); DirtySessionMethodInterceptor.setQueryFlushMode(session, query); return query.list(); } }; List rows = (List) getHibernateTemplate().execute(callback); - nodeInfo = new NodeInfo(node, qnameDAO, rows); + nodeInfo = new NodeInfo(node, null, qnameDAO, rows); // Populate the cache parentAssocsCache.put(childNodeId, nodeInfo); if (isDebugParentAssocCacheEnabled) { - loggerParentAssocsCache.debug("\n" + - "Parent associations cache - Adding entry: \n" + - " Node: " + childNodeId + "\n" + - " Assocs: " + nodeInfo.getParentAssocs().keySet()); + loggerParentAssocsCache.debug("\n" + "Parent associations cache - Adding entry: \n" + " Node: " + + childNodeId + "\n" + " Assocs: " + nodeInfo.getParentAssocs().keySet()); } } // Done return nodeInfo; } - - /** - * 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 - */ - public void prependPaths( - Pair currentNodePair, - Pair currentRootNodePair, - Path currentPath, - Collection completedPaths, - Stack assocIdStack, - boolean primaryOnly) - throws CyclicChildRelationshipException - { - Long currentNodeId = currentNodePair.getFirst(); - NodeRef currentNodeRef = currentNodePair.getSecond(); - - // Check if we have changed root nodes - StoreRef currentStoreRef = currentNodeRef.getStoreRef(); - if (currentRootNodePair == null || !currentStoreRef.equals(currentRootNodePair.getFirst())) - { - // We've changed stores - Pair rootNodePair = getRootNode(currentStoreRef); - currentRootNodePair = new Pair(currentStoreRef, rootNodePair.getSecond()); - } - - // get the parent associations of the given node - NodeInfo nodeInfo = getParentAssocsInternal(currentNodeId); - - // does the node have parents - boolean hasParents = nodeInfo.getParentAssocs().size() > 0; - // does the current node have a root aspect? - - // look for a root. If we only want the primary root, then ignore all but the top-level root. - if (!(primaryOnly && hasParents) && nodeInfo.isRoot()) // exclude primary search with parents present - { - // create a one-sided assoc ref for the root node and prepend to the stack - // this effectively spoofs the fact that the current node is not below the root - // - we put this assoc in as the first assoc in the path must be a one-sided - // reference pointing to the root node - ChildAssociationRef assocRef = new ChildAssociationRef( - null, - null, - null, - currentRootNodePair.getSecond()); - // create a path to save and add the 'root' assoc - Path pathToSave = new Path(); - Path.ChildAssocElement first = null; - for (Path.Element element: currentPath) - { - if (first == null) - { - first = (Path.ChildAssocElement) element; - } - else - { - pathToSave.append(element); - } - } - if (first != null) - { - // mimic an association that would appear if the current node was below the root node - // or if first beneath the root node it will make the real thing - ChildAssociationRef updateAssocRef = new ChildAssociationRef( - nodeInfo.isStoreRoot() ? ContentModel.ASSOC_CHILDREN : first.getRef().getTypeQName(), - currentRootNodePair.getSecond(), - first.getRef().getQName(), - first.getRef().getChildRef()); - Path.Element newFirst = new Path.ChildAssocElement(updateAssocRef); - pathToSave.prepend(newFirst); - } - - Path.Element element = new Path.ChildAssocElement(assocRef); - pathToSave.prepend(element); - - // store the path just built - completedPaths.add(pathToSave); - } - - if (!hasParents && !nodeInfo.isRoot()) - { - throw new RuntimeException("Node without parents does not have root aspect: " + - currentNodeRef); - } - // walk up each parent association - for (Map.Entry entry: nodeInfo.getParentAssocs().entrySet()) - { - Long assocId = entry.getKey(); - ParentAssocInfo parentAssocInfo = entry.getValue(); - ChildAssociationRef assocRef = parentAssocInfo.getChildAssociationRef(); - // do we consider only primary assocs? - if (primaryOnly && !assocRef.isPrimary()) - { - continue; - } - // Ordering is meaningless here as we are constructing a path upwards - // and have no idea where the node comes in the sibling order or even - // if there are like-pathed siblings. - assocRef.setNthSibling(-1); - // build a path element - Path.Element element = new Path.ChildAssocElement(assocRef); - // create a new path that builds on the current path - Path path = new Path(); - path.append(currentPath); - // prepend element - path.prepend(element); - // get parent node pair - Pair parentNodePair = new Pair(parentAssocInfo.getParentNodeId(), assocRef.getParentRef()); - - // does the association already exist in the stack - if (assocIdStack.contains(assocId)) - { - // the association was present already - logger.error( - "Cyclic parent-child relationship detected: \n" + - " current node: " + currentNodeId + "\n" + - " current path: " + currentPath + "\n" + - " next assoc: " + assocId); - throw new CyclicChildRelationshipException("Node has been pasted into its own tree.", assocRef); - } - - // push the assoc stack, recurse and pop - assocIdStack.push(assocId); - prependPaths(parentNodePair, currentRootNodePair, path, completedPaths, assocIdStack, primaryOnly); - assocIdStack.pop(); - } - // done - } - - /** - * {@inheritDoc} - * - * This includes a check to ensuret that only root nodes don't have primary parents - */ - public Collection> getParentAssocs(final Long childNodeId) - { - NodeInfo nodeInfo = getParentAssocsInternal(childNodeId); - Map parentAssocs = nodeInfo.getParentAssocs(); - Collection> ret = new ArrayList>(parentAssocs.size()); - - for (Map.Entry entry : parentAssocs.entrySet()) - { - Pair childAssocPair = new Pair(entry.getKey(), entry - .getValue().getChildAssociationRef()); - ret.add(childAssocPair); - } - // Done - return ret; - } - - private Set warnedDuplicateParents = new HashSet(3); - /** - * {@inheritDoc} - * - * This method includes a check for multiple primary parent associations. - * The check doesn't fail but will warn (once per instance) of the occurence of - * the error. It is up to the administrator to fix the issue at the moment, but - * the server will not stop working. - */ - public Pair getPrimaryParentAssoc(Long childNodeId) - { - // get the assocs pointing to the node - NodeInfo nodeInfo = getParentAssocsInternal(childNodeId); - Pair primaryAssoc = null; - for (Map.Entry entry : nodeInfo.getParentAssocs().entrySet()) - { - ChildAssociationRef assoc = entry.getValue().getChildAssociationRef(); - // ignore non-primary assocs - if (!assoc.isPrimary()) - { - continue; - } - else if (primaryAssoc != null) - { - // We have found one already. - synchronized(warnedDuplicateParents) - { - boolean added = warnedDuplicateParents.add(childNodeId); - if (added) - { - logger.warn( - "Multiple primary associations: \n" + - " first primary assoc: " + primaryAssoc + "\n" + - " second primary assoc: " + assoc + "\n" + - "When running in a cluster, check that the caches are properly shared."); - } - } - } - primaryAssoc = new Pair(entry.getKey(), assoc); - // we keep looping to hunt out data integrity issues - } - // done - if (primaryAssoc == null) - { - return null; - } - else - { - return primaryAssoc; - } - } - - public Pair newNodeAssoc(Long sourceNodeId, Long targetNodeId, final QName assocTypeQName) - { - final Node sourceNode = getNodeNotNull(sourceNodeId); - final Node targetNode = getNodeNotNull(targetNodeId); - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - // Force a flush here to ensure that the session is not dirty - DirtySessionMethodInterceptor.flushSession(session, true); - - NodeAssoc assoc = new NodeAssocImpl(); - assoc.setTypeQName(qnameDAO, assocTypeQName); - assoc.buildAssociation(sourceNode, targetNode); - session.save(assoc); - - // Flush to catch integrity violations - DirtySessionMethodInterceptor.flushSession(session, true); - - return assoc; - } - }; - - // persist - try - { - NodeAssoc assoc = (NodeAssoc) getHibernateTemplate().execute(callback); - // done - return new Pair(assoc.getId(), assoc.getNodeAssocRef(qnameDAO)); - } - catch (DataIntegrityViolationException e) - { - throw new AssociationExistsException( - sourceNode.getNodeRef(), - targetNode.getNodeRef(), - assocTypeQName, - e); - } - } - - @SuppressWarnings("unchecked") - public Collection> getNodeAssocsToAndFrom(final Long nodeId) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODE_ASSOCS_TO_AND_FROM) - .setLong("nodeId", nodeId); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List results = (List) getHibernateTemplate().execute(callback); - Collection> ret = convertToAssocRefs(results); - return ret; - } - - public Pair getNodeAssoc( - final Long sourceNodeId, - final Long targetNodeId, - final QName assocTypeQName) - { - final Pair assocTypeQNamePair = qnameDAO.getQName(assocTypeQName); - // Shortcut - if (assocTypeQNamePair == null) - { - return null; - } - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODE_ASSOC) - .setLong("sourceId", sourceNodeId) - .setLong("targetId", targetNodeId) - .setLong("assocTypeQNameId", assocTypeQNamePair.getFirst()); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.uniqueResult(); - } - }; - NodeAssoc result = (NodeAssoc) getHibernateTemplate().execute(callback); - if (result == null) - { - return null; - } - Pair ret = new Pair(result.getId(), result.getNodeAssocRef(qnameDAO)); - return ret; - } - - public AssociationRef getNodeAssocOrNull(Long assocId) - { - NodeAssoc result = (NodeAssoc) getHibernateTemplate().get(NodeAssocImpl.class, assocId); - if (result == null) - { - return null; - } - return result.getNodeAssocRef(qnameDAO); - } - - @SuppressWarnings("unchecked") - public Collection> getTargetNodeAssocs(final Long sourceNodeId) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_TARGET_ASSOCS) - .setLong("sourceId", sourceNodeId); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List results = (List) getHibernateTemplate().execute(callback); - Collection> ret = convertToAssocRefs(results); - return ret; - } - - @SuppressWarnings("unchecked") - public Collection> getSourceNodeAssocs(final Long targetNodeId) - { - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_SOURCE_ASSOCS) - .setLong("targetId", targetNodeId); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.list(); - } - }; - List results = (List) getHibernateTemplate().execute(callback); - Collection> ret = convertToAssocRefs(results); - return ret; - } - - public void deleteNodeAssoc(Long assocId) - { - NodeAssoc assoc = (NodeAssoc) getHibernateTemplate().get(NodeAssocImpl.class, assocId); - if (assoc != null) - { - getHibernateTemplate().delete(assoc); - } - } - - public void getPropertyValuesByPropertyAndValue( - final StoreRef storeRef, - final QName propertyQName, - final String value, - final NodePropertyHandler handler) - { - Pair propQNamePair = qnameDAO.getQName(propertyQName); - // Shortcut - if (propQNamePair == null) - { - return; - } - final Long propQNameEntityId = propQNamePair.getFirst(); - // Run the query - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_STRING_AND_STORE) - .setString("storeProtocol", storeRef.getProtocol()) - .setString("storeIdentifier", storeRef.getIdentifier()) - .setParameter("propQNameID", propQNameEntityId) - .setString("propStringValue", value) - ; - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults results = null; - try - { - results = (ScrollableResults) getHibernateTemplate().execute(callback); - // Callback with the results - Session session = getSession(); - while (results.next()) - { - Node node = (Node) results.get(0); - NodeRef nodeRef = node.getNodeRef(); - Long nodeTypeQNameId = node.getTypeQNameId(); - QName nodeTypeQName = qnameDAO.getQName(nodeTypeQNameId).getSecond(); - handler.handle(nodeRef, nodeTypeQName, propertyQName, value); - // Flush if required - DirtySessionMethodInterceptor.flushSession(session); - } - } - finally - { - if (results != null) - { - results.close(); - } - } - } - - public void getContentUrlsForStore( - final StoreRef storeRef, - final ObjectArrayQueryCallback resultsCallback) - { - Pair contentTypeQNamePair = qnameDAO.getQName(ContentModel.TYPE_CONTENT); - Pair contentPropQNamePair = qnameDAO.getQName(ContentModel.PROP_CONTENT); - // Shortcut - if (contentTypeQNamePair == null || contentPropQNamePair == null) - { - return; - } - final Long contentTypeQNameEntityId = contentTypeQNamePair.getFirst(); - final Long contentPropQNameEntityId = contentPropQNamePair.getFirst(); - // Note, we do a left join on owner, so it may be null - Pair ownerPropQNamePair = qnameDAO.getQName(ContentModel.PROP_OWNER); - final Long ownerPropQNameEntityId = - ownerPropQNamePair == null ? new Long(-1L) : ownerPropQNamePair.getFirst(); - - // Query for the 'old' style content properties stored in 'string_value' - HibernateCallback callbackOld = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CONTENT_URLS_FOR_STORE_OLD) - .setString("storeProtocol", storeRef.getProtocol()) - .setString("storeIdentifier", storeRef.getIdentifier()) - .setParameter("ownerPropQNameID", ownerPropQNameEntityId) // cm:owner - .setParameter("contentPropQNameID", contentPropQNameEntityId) // cm:content - .setParameter("contentTypeQNameID", contentTypeQNameEntityId) // cm:content - ; - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults results = null; - try - { - results = (ScrollableResults) getHibernateTemplate().execute(callbackOld); - // Callback with the results - while (results.next()) - { - Object[] arr = new Object[3]; - arr[0] = (String)results.get(0); // owner (can be null) - arr[1] = (String)results.get(1); // creator - arr[2] = (String)results.get(2); // contentdata - resultsCallback.handle(arr); - } - } - finally - { - if (results != null) - { - results.close(); - } - } - - // Query for the 'new' style content properties stored in the 'content_url' table - HibernateCallback callbackNew = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_CONTENT_URLS_FOR_STORE_NEW) - .setString("storeProtocol", storeRef.getProtocol()) - .setString("storeIdentifier", storeRef.getIdentifier()) - .setParameter("ownerPropQNameID", ownerPropQNameEntityId) // cm:owner - .setParameter("contentPropQNameID", contentPropQNameEntityId) // cm:content - .setParameter("contentTypeQNameID", contentTypeQNameEntityId) // cm:content - ; - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - results = null; - try - { - results = (ScrollableResults) getHibernateTemplate().execute(callbackNew); - // Callback with the results - /* - - - - */ - while (results.next()) - { - Long contentDataId = (Long)results.get(2); - // Convert to ContentData - ContentData contentData = contentDataDAO.getContentData(contentDataId).getSecond(); - // Pass down results - Object[] arr = new Object[3]; - arr[0] = (String)results.get(0); // owner (can be null) - arr[1] = (String)results.get(1); // creator - arr[2] = contentData.toString(); - resultsCallback.handle(arr); - } - } - finally - { - if (results != null) - { - results.close(); - } - } - - // Done - } - - public void getUsersWithoutUsageProp( - final StoreRef storeRef, - final ObjectArrayQueryCallback resultsCallback) - { - final Pair sizeCurrentPropQNamePair = qnameDAO.getQName(ContentModel.PROP_SIZE_CURRENT); - final Pair personTypeQNamePair = qnameDAO.getQName(ContentModel.TYPE_PERSON); - if (personTypeQNamePair == null) - { - return; // Shortcut as we join on this - } - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Long personTypeQNameId = personTypeQNamePair.getFirst(); - // We LEFT JOIN on this - Long sizeCurrentPropQNameId = - sizeCurrentPropQNamePair == null ? new Long(-1L) : sizeCurrentPropQNamePair.getFirst(); - - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_USERS_WITHOUT_USAGE_PROP) - .setString("storeProtocol", storeRef.getProtocol()) - .setString("storeIdentifier", storeRef.getIdentifier()) - .setParameter("sizeCurrentPropQNameID", sizeCurrentPropQNameId) // cm:sizeCurrent - .setParameter("personTypeQNameID", personTypeQNameId) // cm:person - .setParameter("isDeleted", false); - ; - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults results = null; - try - { - results = (ScrollableResults) getHibernateTemplate().execute(callback); - // Callback with the results - Session session = getSession(); - while (results.next()) - { - Object[] arr = new Object[1]; - arr[0] = (String)results.get(0); // node uuid - resultsCallback.handle(arr); - // Flush if required - DirtySessionMethodInterceptor.flushSession(session); - } - } - finally - { - if (results != null) - { - results.close(); - } - } - } - - public void getUsersWithoutUsage( - final StoreRef storeRef, - final ObjectArrayQueryCallback resultsCallback) - { - final Pair personTypeQNamePair = qnameDAO.getQName(ContentModel.TYPE_PERSON); - final Pair usernamePropQNamePair = qnameDAO.getQName(ContentModel.PROP_USERNAME); - final Pair sizeCurrentPropQNamePair = qnameDAO.getQName(ContentModel.PROP_SIZE_CURRENT); - if (personTypeQNamePair == null || usernamePropQNamePair == null || sizeCurrentPropQNamePair == null) - { - return; // All joins - } - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_USERS_WITHOUT_USAGE) - .setString("storeProtocol", storeRef.getProtocol()) - .setString("storeIdentifier", storeRef.getIdentifier()) - .setParameter("usernamePropQNameID", usernamePropQNamePair.getFirst()) // cm:username - .setParameter("sizeCurrentPropQNameID", sizeCurrentPropQNamePair.getFirst()) // cm:sizeCurrent - .setParameter("personTypeQNameID", personTypeQNamePair.getFirst()) // cm:person - ; - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults results = null; - try - { - results = (ScrollableResults) getHibernateTemplate().execute(callback); - // Callback with the results - Session session = getSession(); - while (results.next()) - { - Object[] arr = new Object[2]; - arr[0] = (String)results.get(0); // username - arr[1] = (String)results.get(1); // node uuid - resultsCallback.handle(arr); - // Flush if required - DirtySessionMethodInterceptor.flushSession(session); - } - } - finally - { - if (results != null) - { - results.close(); - } - } - - // Done - } - - public void getUsersWithUsage( - final StoreRef storeRef, - final ObjectArrayQueryCallback resultsCallback) - { - final Pair personTypeQNamePair = qnameDAO.getQName(ContentModel.TYPE_PERSON); - final Pair usernamePropQNamePair = qnameDAO.getQName(ContentModel.PROP_USERNAME); - final Pair sizeCurrentPropQNamePair = qnameDAO.getQName(ContentModel.PROP_SIZE_CURRENT); - if (personTypeQNamePair == null || usernamePropQNamePair == null || sizeCurrentPropQNamePair == null) - { - return; // All joins - } - - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_USERS_WITH_USAGE) - .setString("storeProtocol", storeRef.getProtocol()) - .setString("storeIdentifier", storeRef.getIdentifier()) - .setParameter("usernamePropQNameID", usernamePropQNamePair.getFirst()) // cm:username - .setParameter("sizeCurrentPropQNameID", sizeCurrentPropQNamePair.getFirst()) // cm:sizeCurrent - .setParameter("personTypeQNameID", personTypeQNamePair.getFirst()) // cm:person - ; - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults results = null; - try - { - results = (ScrollableResults) getHibernateTemplate().execute(callback); - // Callback with the results - Session session = getSession(); - while (results.next()) - { - Object[] arr = new Object[2]; - arr[0] = (String)results.get(0); // username - arr[1] = (String)results.get(1); // node uuid - resultsCallback.handle(arr); - // Flush if required - DirtySessionMethodInterceptor.flushSession(session); - } - } - finally - { - if (results != null) - { - results.close(); - } - } - - // Done - } - - public void getPropertyValuesByActualType(DataTypeDefinition actualDataTypeDefinition, NodePropertyHandler handler) - { - // get the in-database string representation of the actual type - QName typeQName = actualDataTypeDefinition.getName(); - final int actualTypeOrdinal = PropertyValue.convertToTypeOrdinal(typeQName); - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session - .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_ACTUAL_TYPE) - .setInteger("actualType", actualTypeOrdinal); - DirtySessionMethodInterceptor.setQueryFlushMode(session, query); - return query.scroll(ScrollMode.FORWARD_ONLY); - } - }; - ScrollableResults results = null; - try - { - results = (ScrollableResults) getHibernateTemplate().execute(callback); - - // Loop through, extracting content URLs - TypeConverter converter = DefaultTypeConverter.INSTANCE; - int unflushedCount = 0; - while (results.next()) - { - Node node = (Node) results.get()[0]; - Long nodeTypeQNameId = node.getTypeQNameId(); - QName nodeTypeQName = qnameDAO.getQName(nodeTypeQNameId).getSecond(); - // loop through all the node properties - Map properties = node.getProperties(); - for (Map.Entry entry : properties.entrySet()) - { - PropertyMapKey propertyKey = entry.getKey(); - Long propertyQNameId = propertyKey.getQnameId(); - QName propertyQName = qnameDAO.getQName(propertyQNameId).getSecond(); - NodePropertyValue propertyValue = entry.getValue(); - // 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; - } - Serializable convertedValue = null; - try - { - convertedValue = (Serializable) converter.convert(actualDataTypeDefinition, value); - } - catch (Throwable e) - { - // The value can't be converted - forget it - } - if (convertedValue != null) - { - NodeRef nodeRef = node.getNodeRef(); - handler.handle(nodeRef, nodeTypeQName, propertyQName, convertedValue); - } - } - } - unflushedCount++; - if (unflushedCount >= 1000) - { - // evict all data from the session - getSession().clear(); - unflushedCount = 0; - } - } - } - finally - { - if (results != null) - { - results.close(); - } - } - } - public void getNodesDeletedInOldTxns( final Long minNodeId, long maxCommitTime, @@ -4399,13 +1213,13 @@ public class HibernateNodeDaoServiceImpl { // Get the max transaction ID final Long maxTxnId = getMaxTxnIdByCommitTime(maxCommitTime); - + // Shortcut if (maxTxnId == null) { return; } - + HibernateCallback callback = new HibernateCallback() { public Object doInHibernate(Session session) @@ -4433,7 +1247,7 @@ public class HibernateNodeDaoServiceImpl } // Done } - + /* * Queries for transactions */ @@ -4450,7 +1264,7 @@ public class HibernateNodeDaoServiceImpl private static final String QUERY_GET_TXN_CHANGES_FOR_STORE = "txn.GetTxnChangesForStore"; private static final String QUERY_GET_TXN_CHANGES = "txn.GetTxnChanges"; private static final String QUERY_GET_TXNS_UNUSED = "txn.GetTxnsUnused"; - + public Transaction getTxnById(final long txnId) { HibernateCallback callback = new HibernateCallback() @@ -4458,8 +1272,7 @@ public class HibernateNodeDaoServiceImpl public Object doInHibernate(Session session) { Query query = session.getNamedQuery(QUERY_GET_TXN_BY_ID); - query.setLong("txnId", txnId) - .setReadOnly(true); + query.setLong("txnId", txnId).setReadOnly(true); DirtySessionMethodInterceptor.setQueryFlushMode(session, query); return query.uniqueResult(); } @@ -4468,7 +1281,7 @@ public class HibernateNodeDaoServiceImpl // done return txn; } - + public Long getMinTxnCommitTime() { HibernateCallback callback = new HibernateCallback() @@ -4484,7 +1297,7 @@ public class HibernateNodeDaoServiceImpl // done return (commitTime == null) ? 0L : commitTime; } - + public Long getMaxTxnCommitTime() { HibernateCallback callback = new HibernateCallback() @@ -4500,7 +1313,7 @@ public class HibernateNodeDaoServiceImpl // done return (commitTime == null) ? 0L : commitTime; } - + public Long getMaxTxnIdByCommitTime(final long maxCommitTime) { HibernateCallback callback = new HibernateCallback() @@ -4517,7 +1330,7 @@ public class HibernateNodeDaoServiceImpl // done return txnId; } - + @SuppressWarnings("unchecked") public List getTxnsByMinCommitTime(final List includeTxnIds) { @@ -4530,8 +1343,7 @@ public class HibernateNodeDaoServiceImpl public Object doInHibernate(Session session) { Query query = session.getNamedQuery(QUERY_GET_SELECTED_TXNS_BY_COMMIT_TIME_ASC); - query.setParameterList("includeTxnIds", includeTxnIds) - .setReadOnly(true); + query.setParameterList("includeTxnIds", includeTxnIds).setReadOnly(true); DirtySessionMethodInterceptor.setQueryFlushMode(session, query); return query.list(); } @@ -4548,8 +1360,7 @@ public class HibernateNodeDaoServiceImpl public Object doInHibernate(Session session) { Query query = session.getNamedQuery(QUERY_GET_TXN_UPDATE_COUNT_FOR_STORE); - query.setLong("txnId", txnId) - .setReadOnly(true); + query.setLong("txnId", txnId).setReadOnly(true); DirtySessionMethodInterceptor.setQueryFlushMode(session, query); return query.uniqueResult(); } @@ -4558,7 +1369,7 @@ public class HibernateNodeDaoServiceImpl // done return count.intValue(); } - + public int getTxnDeleteCount(final long txnId) { HibernateCallback callback = new HibernateCallback() @@ -4566,8 +1377,7 @@ public class HibernateNodeDaoServiceImpl public Object doInHibernate(Session session) { Query query = session.getNamedQuery(QUERY_GET_TXN_DELETE_COUNT_FOR_STORE); - query.setLong("txnId", txnId) - .setReadOnly(true); + query.setLong("txnId", txnId).setReadOnly(true); DirtySessionMethodInterceptor.setQueryFlushMode(session, query); return query.uniqueResult(); } @@ -4576,7 +1386,7 @@ public class HibernateNodeDaoServiceImpl // done return count.intValue(); } - + public int getTransactionCount() { HibernateCallback callback = new HibernateCallback() @@ -4584,8 +1394,7 @@ public class HibernateNodeDaoServiceImpl public Object doInHibernate(Session session) { Query query = session.getNamedQuery(QUERY_COUNT_TRANSACTIONS); - query.setMaxResults(1) - .setReadOnly(true); + query.setMaxResults(1).setReadOnly(true); DirtySessionMethodInterceptor.setQueryFlushMode(session, query); return query.uniqueResult(); } @@ -4594,11 +1403,11 @@ public class HibernateNodeDaoServiceImpl // done return count.intValue(); } - + private static final Long TXN_ID_DUD = Long.valueOf(-1L); private static final Long SERVER_ID_DUD = Long.valueOf(-1L); - private static final long MIN_TIME_QUERY_RANGE = 10L * 60L * 1000L; // 10 minutes - + private static final long MIN_TIME_QUERY_RANGE = 10L * 60L * 1000L; // 10 minutes + @SuppressWarnings("unchecked") public List getTxnsByCommitTimeAscending( long fromTimeInclusive, @@ -4614,7 +1423,7 @@ public class HibernateNodeDaoServiceImpl } if (toTimeExclusive < 0L || toTimeExclusive == Long.MAX_VALUE) { - toTimeExclusive = ((long)getMaxTxnCommitTime())+1L; + toTimeExclusive = ((long) getMaxTxnCommitTime()) + 1L; } // Get the time difference required long diffTime = toTimeExclusive - fromTimeInclusive; @@ -4623,7 +1432,7 @@ public class HibernateNodeDaoServiceImpl // There can be no results return Collections.emptyList(); } - + // Make sure that we have at least one entry in the exclude list final List excludeTxnIdsInner = new ArrayList(excludeTxnIds == null ? 1 : excludeTxnIds.size()); if (excludeTxnIds == null || excludeTxnIds.isEmpty()) @@ -4637,7 +1446,7 @@ public class HibernateNodeDaoServiceImpl final List excludeServerIds = new ArrayList(1); if (remoteOnly) { - // Get the current server ID. This can be null if no transactions have been written by + // Get the current server ID. This can be null if no transactions have been written by // a server with this IP address. Long serverId = getServerIdOrNull(); if (serverId == null) @@ -4653,7 +1462,7 @@ public class HibernateNodeDaoServiceImpl { excludeServerIds.add(SERVER_ID_DUD); } - + List results = new ArrayList(count); // Each query must be constrained in the time range, // so query larger and larger sets until enough results are retrieved. @@ -4667,7 +1476,7 @@ public class HibernateNodeDaoServiceImpl queryFromTimeInclusive = queryToTimeExclusive; queryToTimeExclusive += (iteration * MIN_TIME_QUERY_RANGE); queryCount = count - results.size(); - + final long innerQueryFromTimeInclusive = queryFromTimeInclusive; final long innerQueryToTimeExclusive = queryToTimeExclusive; final int innerQueryCount = queryCount; @@ -4676,12 +1485,10 @@ public class HibernateNodeDaoServiceImpl public Object doInHibernate(Session session) { Query query = session.getNamedQuery(QUERY_GET_TXNS_BY_COMMIT_TIME_ASC); - query.setLong("fromTimeInclusive", innerQueryFromTimeInclusive) - .setLong("toTimeExclusive", innerQueryToTimeExclusive) - .setParameterList("excludeTxnIds", excludeTxnIdsInner) - .setParameterList("excludeServerIds", excludeServerIds) - .setMaxResults(innerQueryCount) - .setReadOnly(true); + query.setLong("fromTimeInclusive", innerQueryFromTimeInclusive).setLong("toTimeExclusive", + innerQueryToTimeExclusive).setParameterList("excludeTxnIds", excludeTxnIdsInner) + .setParameterList("excludeServerIds", excludeServerIds).setMaxResults(innerQueryCount) + .setReadOnly(true); return query.list(); } }; @@ -4692,7 +1499,7 @@ public class HibernateNodeDaoServiceImpl // done return results; } - + @SuppressWarnings("unchecked") public List getTxnsByCommitTimeDescending( long fromTimeInclusive, @@ -4708,7 +1515,7 @@ public class HibernateNodeDaoServiceImpl } if (toTimeExclusive < 0L || toTimeExclusive == Long.MAX_VALUE) { - toTimeExclusive = ((long)getMaxTxnCommitTime())+1L; + toTimeExclusive = ((long) getMaxTxnCommitTime()) + 1L; } // Get the time difference required long diffTime = toTimeExclusive - fromTimeInclusive; @@ -4717,7 +1524,7 @@ public class HibernateNodeDaoServiceImpl // There can be no results return Collections.emptyList(); } - + // Make sure that we have at least one entry in the exclude list final List excludeTxnIdsInner = new ArrayList(excludeTxnIds == null ? 1 : excludeTxnIds.size()); if (excludeTxnIds == null || excludeTxnIds.isEmpty()) @@ -4731,7 +1538,7 @@ public class HibernateNodeDaoServiceImpl final List excludeServerIds = new ArrayList(1); if (remoteOnly) { - // Get the current server ID. This can be null if no transactions have been written by + // Get the current server ID. This can be null if no transactions have been written by // a server with this IP address. Long serverId = getServerIdOrNull(); if (serverId == null) @@ -4747,8 +1554,6 @@ public class HibernateNodeDaoServiceImpl { excludeServerIds.add(SERVER_ID_DUD); } - - List results = new ArrayList(count); // Each query must be constrained in the time range, @@ -4763,7 +1568,7 @@ public class HibernateNodeDaoServiceImpl queryToTimeExclusive = queryFromTimeInclusive; queryFromTimeInclusive -= (iteration * MIN_TIME_QUERY_RANGE); queryCount = count - results.size(); - + final long innerQueryFromTimeInclusive = queryFromTimeInclusive; final long innerQueryToTimeExclusive = queryToTimeExclusive; final int innerQueryCount = queryCount; @@ -4772,12 +1577,10 @@ public class HibernateNodeDaoServiceImpl public Object doInHibernate(Session session) { Query query = session.getNamedQuery(QUERY_GET_TXNS_BY_COMMIT_TIME_DESC); - query.setLong("fromTimeInclusive", innerQueryFromTimeInclusive) - .setLong("toTimeExclusive", innerQueryToTimeExclusive) - .setParameterList("excludeTxnIds", excludeTxnIdsInner) - .setParameterList("excludeServerIds", excludeServerIds) - .setMaxResults(innerQueryCount) - .setReadOnly(true); + query.setLong("fromTimeInclusive", innerQueryFromTimeInclusive).setLong("toTimeExclusive", + innerQueryToTimeExclusive).setParameterList("excludeTxnIds", excludeTxnIdsInner) + .setParameterList("excludeServerIds", excludeServerIds).setMaxResults(innerQueryCount) + .setReadOnly(true); return query.list(); } }; @@ -4788,7 +1591,7 @@ public class HibernateNodeDaoServiceImpl // done return results; } - + @SuppressWarnings("unchecked") public List getTxnChangesForStore(final StoreRef storeRef, final long txnId) { @@ -4797,10 +1600,8 @@ public class HibernateNodeDaoServiceImpl 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); + query.setLong("txnId", txnId).setString("protocol", storeRef.getProtocol()).setString("identifier", + storeRef.getIdentifier()).setReadOnly(true); DirtySessionMethodInterceptor.setQueryFlushMode(session, query); return query.list(); } @@ -4816,7 +1617,7 @@ public class HibernateNodeDaoServiceImpl // done return nodeRefs; } - + @SuppressWarnings("unchecked") public List getTxnChanges(final long txnId) { @@ -4825,8 +1626,7 @@ public class HibernateNodeDaoServiceImpl public Object doInHibernate(Session session) { Query query = session.getNamedQuery(QUERY_GET_TXN_CHANGES); - query.setLong("txnId", txnId) - .setReadOnly(true); + query.setLong("txnId", txnId).setReadOnly(true); DirtySessionMethodInterceptor.setQueryFlushMode(session, query); return query.list(); } @@ -4842,7 +1642,7 @@ public class HibernateNodeDaoServiceImpl // done return nodeRefs; } - + @SuppressWarnings("unchecked") public List getTxnsUnused(final Long minTxnId, final long maxCommitTime, final int count) { @@ -4851,10 +1651,8 @@ public class HibernateNodeDaoServiceImpl public Object doInHibernate(Session session) { Query query = session.getNamedQuery(QUERY_GET_TXNS_UNUSED); - query.setReadOnly(true) - .setMaxResults(count) - .setLong("minTxnId", minTxnId) - .setLong("maxCommitTime", maxCommitTime); + query.setReadOnly(true).setMaxResults(count).setLong("minTxnId", minTxnId).setLong("maxCommitTime", + maxCommitTime); DirtySessionMethodInterceptor.setQueryFlushMode(session, query); return query.list(); } @@ -4873,16 +1671,17 @@ public class HibernateNodeDaoServiceImpl } } - //============ PROPERTY HELPER METHODS =================// - - public static Map convertToPersistentProperties( + // ============ PROPERTY HELPER METHODS =================// + + public static Map convertToPersistentProperties( Map in, QNameDAO qnameDAO, LocaleDAO localeDAO, ContentDataDAO contentDataDAO, DictionaryService dictionaryService) { - Map propertyMap = new HashMap(in.size() + 5); + Map propertyMap = new HashMap( + in.size() + 5); for (Map.Entry entry : in.entrySet()) { Serializable value = entry.getValue(); @@ -4894,14 +1693,8 @@ public class HibernateNodeDaoServiceImpl // Get the property definition, if available PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); // Add it to the map - HibernateNodeDaoServiceImpl.addValueToPersistedProperties( - propertyMap, - propertyDef, - HibernateNodeDaoServiceImpl.IDX_NO_COLLECTION, - propertyQNameId, - propertylocaleId, - value, - localeDAO, + HibernateNodeDaoServiceImpl.addValueToPersistedProperties(propertyMap, propertyDef, + HibernateNodeDaoServiceImpl.IDX_NO_COLLECTION, propertyQNameId, propertylocaleId, value, localeDAO, contentDataDAO); } // Done @@ -4909,20 +1702,20 @@ public class HibernateNodeDaoServiceImpl } /** - * The collection index used to indicate that the value is not part of a collection. - * All values from zero up are used for real collection indexes. + * The collection index used to indicate that the value is not part of a collection. All values from zero up are + * used for real collection indexes. */ private static final int IDX_NO_COLLECTION = -1; - + /** - * A method that adds properties to the given map. It copes with collections. - * - * @param propertyDef the property definition (null is allowed) - * @param collectionIndex the index of the property in the collection or -1 if - * we are not yet processing a collection + * A method that adds properties to the given map. It copes with collections. + * + * @param propertyDef the property definition (null is allowed) + * @param collectionIndex the index of the property in the collection or -1 if we are not yet processing a + * collection */ private static void addValueToPersistedProperties( - Map propertyMap, + Map propertyMap, PropertyDefinition propertyDef, int collectionIndex, Long propertyQNameId, @@ -4933,9 +1726,9 @@ public class HibernateNodeDaoServiceImpl { if (value == null) { - // The property is null. Null is null and cannot be massaged any other way. + // The property is null. Null is null and cannot be massaged any other way. NodePropertyValue npValue = HibernateNodeDaoServiceImpl.makeNodePropertyValue(propertyDef, null); - PropertyMapKey npKey = new PropertyMapKey(); + NodePropertyKey npKey = new NodePropertyKey(); npKey.setListIndex(collectionIndex); npKey.setQnameId(propertyQNameId); npKey.setLocaleId(propertyLocaleId); @@ -4944,10 +1737,10 @@ public class HibernateNodeDaoServiceImpl // Done return; } - + // Get or spoof the property datatype QName propertyTypeQName; - if (propertyDef == null) // property not recognised + if (propertyDef == null) // property not recognised { // allow it for now - persisting excess properties can be useful sometimes propertyTypeQName = DataTypeDefinition.ANY; @@ -4958,34 +1751,28 @@ public class HibernateNodeDaoServiceImpl } // A property may appear to be multi-valued if the model definition is loose and - // an unexploded collection is passed in. Otherwise, use the model-defined behaviour + // an unexploded collection is passed in. Otherwise, use the model-defined behaviour // strictly. boolean isMultiValued; if (propertyTypeQName.equals(DataTypeDefinition.ANY)) { // It is multi-valued if required (we are not in a collection and the property is a new collection) - isMultiValued = (value != null) && (value instanceof Collection) && (collectionIndex == IDX_NO_COLLECTION); + isMultiValued = (value != null) && (value instanceof Collection) + && (collectionIndex == IDX_NO_COLLECTION); } else { isMultiValued = propertyDef.isMultiValued(); } - + // Handle different scenarios. // - Do we need to explode a collection? // - Does the property allow collections? if (collectionIndex == IDX_NO_COLLECTION && isMultiValued && !(value instanceof Collection)) { // We are not (yet) processing a collection but the property should be part of a collection - HibernateNodeDaoServiceImpl.addValueToPersistedProperties( - propertyMap, - propertyDef, - 0, - propertyQNameId, - propertyLocaleId, - value, - localeDAO, - contentDataDAO); + HibernateNodeDaoServiceImpl.addValueToPersistedProperties(propertyMap, propertyDef, 0, propertyQNameId, + propertyLocaleId, value, localeDAO, contentDataDAO); } else if (collectionIndex == IDX_NO_COLLECTION && value instanceof Collection) { @@ -4993,22 +1780,19 @@ public class HibernateNodeDaoServiceImpl // Check that multi-valued properties are supported if the property is a collection if (!isMultiValued) { - throw new DictionaryException( - "A single-valued property of this type may not be a collection: \n" + - " Property: " + propertyDef + "\n" + - " Type: " + propertyTypeQName + "\n" + - " Value: " + value); + throw new DictionaryException("A single-valued property of this type may not be a collection: \n" + + " Property: " + propertyDef + "\n" + " Type: " + propertyTypeQName + "\n" + " Value: " + + value); } // We have an allowable collection. @SuppressWarnings("unchecked") Collection collectionValues = (Collection) value; - // Persist empty collections directly. This is handled by the NodePropertyValue. + // Persist empty collections directly. This is handled by the NodePropertyValue. if (collectionValues.size() == 0) { - NodePropertyValue npValue = HibernateNodeDaoServiceImpl.makeNodePropertyValue( - null, + NodePropertyValue npValue = HibernateNodeDaoServiceImpl.makeNodePropertyValue(null, (Serializable) collectionValues); - PropertyMapKey npKey = new PropertyMapKey(); + NodePropertyKey npKey = new NodePropertyKey(); npKey.setListIndex(HibernateNodeDaoServiceImpl.IDX_NO_COLLECTION); npKey.setQnameId(propertyQNameId); npKey.setLocaleId(propertyLocaleId); @@ -5022,34 +1806,22 @@ public class HibernateNodeDaoServiceImpl collectionIndex++; if (collectionValueObj != null && !(collectionValueObj instanceof Serializable)) { - throw new IllegalArgumentException( - "Node properties must be fully serializable, " + - "including values contained in collections. \n" + - " Property: " + propertyDef + "\n" + - " Index: " + collectionIndex + "\n" + - " Value: " + collectionValueObj); + throw new IllegalArgumentException("Node properties must be fully serializable, " + + "including values contained in collections. \n" + " Property: " + propertyDef + "\n" + + " Index: " + collectionIndex + "\n" + " Value: " + collectionValueObj); } Serializable collectionValue = (Serializable) collectionValueObj; try { - HibernateNodeDaoServiceImpl.addValueToPersistedProperties( - propertyMap, - propertyDef, - collectionIndex, - propertyQNameId, - propertyLocaleId, - collectionValue, - localeDAO, + HibernateNodeDaoServiceImpl.addValueToPersistedProperties(propertyMap, propertyDef, + collectionIndex, propertyQNameId, propertyLocaleId, collectionValue, localeDAO, contentDataDAO); } catch (Throwable e) { - throw new AlfrescoRuntimeException( - "Failed to persist collection entry: \n" + - " Property: " + propertyDef + "\n" + - " Index: " + collectionIndex + "\n" + - " Value: " + collectionValue, - e); + throw new AlfrescoRuntimeException("Failed to persist collection entry: \n" + " Property: " + + propertyDef + "\n" + " Index: " + collectionIndex + "\n" + " Value: " + + collectionValue, e); } } } @@ -5060,19 +1832,16 @@ public class HibernateNodeDaoServiceImpl if (value instanceof Collection && !propertyTypeQName.equals(DataTypeDefinition.ANY)) { throw new DictionaryException( - "Collections of collections (Serializable) are only supported by type 'd:any': \n" + - " Property: " + propertyDef + "\n" + - " Type: " + propertyTypeQName + "\n" + - " Value: " + value); + "Collections of collections (Serializable) are only supported by type 'd:any': \n" + + " Property: " + propertyDef + "\n" + " Type: " + propertyTypeQName + "\n" + + " Value: " + value); } // Handle ContentData - // We used to check the property type, but we now handle d:any ContentData as well - if (value instanceof ContentData) + if (value instanceof ContentData && propertyTypeQName.equals(DataTypeDefinition.CONTENT)) { // Needs converting to an ID ContentData contentData = (ContentData) value; - Long contentDataId = contentDataDAO.createContentData(contentData).getFirst(); - value = new ContentDataId(contentDataId); + value = contentDataDAO.createContentData(contentData).getFirst(); } // Handle MLText if (value instanceof MLText) @@ -5087,7 +1856,7 @@ public class HibernateNodeDaoServiceImpl Long mlTextLocaleId = localeDAO.getOrCreateLocalePair(mlTextLocale).getFirst(); // This is persisted against the current locale, but as a d:text instance NodePropertyValue npValue = new NodePropertyValue(DataTypeDefinition.TEXT, mlTextStr); - PropertyMapKey npKey = new PropertyMapKey(); + NodePropertyKey npKey = new NodePropertyKey(); npKey.setListIndex(collectionIndex); npKey.setQnameId(propertyQNameId); npKey.setLocaleId(mlTextLocaleId); @@ -5098,7 +1867,7 @@ public class HibernateNodeDaoServiceImpl else { NodePropertyValue npValue = HibernateNodeDaoServiceImpl.makeNodePropertyValue(propertyDef, value); - PropertyMapKey npKey = new PropertyMapKey(); + NodePropertyKey npKey = new NodePropertyKey(); npKey.setListIndex(collectionIndex); npKey.setQnameId(propertyQNameId); npKey.setLocaleId(propertyLocaleId); @@ -5111,21 +1880,21 @@ public class HibernateNodeDaoServiceImpl /** * Helper method to convert the Serializable value into a full, persistable {@link NodePropertyValue}. *

- * Where the property definition is null, the value will take on the - * {@link DataTypeDefinition#ANY generic ANY} value. + * Where the property definition is null, the value will take on the {@link DataTypeDefinition#ANY generic ANY} + * value. *

- * Collections are NOT supported. These must be split up by the calling code before - * calling this method. Map instances are supported as plain serializable instances. + * Collections are NOT supported. These must be split up by the calling code before calling this method. Map + * instances are supported as plain serializable instances. * - * @param propertyDef the property dictionary definition, may be null - * @param value the value, which will be converted according to the definition - may be null - * @return Returns the persistable property value + * @param propertyDef the property dictionary definition, may be null + * @param value the value, which will be converted according to the definition - may be null + * @return Returns the persistable property value */ private static NodePropertyValue makeNodePropertyValue(PropertyDefinition propertyDef, Serializable value) { // get property attributes final QName propertyTypeQName; - if (propertyDef == null) // property not recognised + if (propertyDef == null) // property not recognised { // allow it for now - persisting excess properties can be useful sometimes propertyTypeQName = DataTypeDefinition.ANY; @@ -5143,16 +1912,14 @@ public class HibernateNodeDaoServiceImpl catch (TypeConversionException e) { throw new TypeConversionException( - "The property value is not compatible with the type defined for the property: \n" + - " property: " + (propertyDef == null ? "unknown" : propertyDef) + "\n" + - " value: " + value + "\n" + - " value type: " + value.getClass(), - e); + "The property value is not compatible with the type defined for the property: \n" + " property: " + + (propertyDef == null ? "unknown" : propertyDef) + "\n" + " value: " + value + "\n" + + " value type: " + value.getClass(), e); } } - + public static Serializable getPublicProperty( - Map propertyValues, + Map propertyValues, QName propertyQName, QNameDAO qnameDAO, LocaleDAO localeDAO, @@ -5168,10 +1935,10 @@ public class HibernateNodeDaoServiceImpl } Long qnameId = qnamePair.getFirst(); // Now loop over the properties and extract those with the given qname ID - SortedMap scratch = new TreeMap(); - for (Map.Entry entry : propertyValues.entrySet()) + SortedMap scratch = new TreeMap(); + for (Map.Entry entry : propertyValues.entrySet()) { - PropertyMapKey propertyKey = entry.getKey(); + NodePropertyKey propertyKey = entry.getKey(); if (propertyKey.getQnameId().equals(qnameId)) { scratch.put(propertyKey, entry.getValue()); @@ -5181,11 +1948,8 @@ public class HibernateNodeDaoServiceImpl if (scratch.size() > 0) { PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName); - Serializable collapsedValue = HibernateNodeDaoServiceImpl.collapsePropertiesWithSameQName( - propertyDef, - scratch, - localeDAO, - contentDataDAO); + Serializable collapsedValue = HibernateNodeDaoServiceImpl.collapsePropertiesWithSameQName(propertyDef, + scratch, localeDAO, contentDataDAO); return collapsedValue; } else @@ -5195,7 +1959,7 @@ public class HibernateNodeDaoServiceImpl } public static Map convertToPublicProperties( - Map propertyValues, + Map propertyValues, QNameDAO qnameDAO, LocaleDAO localeDAO, ContentDataDAO contentDataDAO, @@ -5208,21 +1972,22 @@ public class HibernateNodeDaoServiceImpl return propertyMap; } // We need to process the properties in order - SortedMap sortedPropertyValues = new TreeMap(propertyValues); - // A working map. Ordering is important. - SortedMap scratch = new TreeMap(); + SortedMap sortedPropertyValues = new TreeMap( + propertyValues); + // A working map. Ordering is important. + SortedMap scratch = new TreeMap(); // Iterate (sorted) over the map entries and extract values with the same qname Long currentQNameId = Long.MIN_VALUE; - Iterator> iterator = sortedPropertyValues.entrySet().iterator(); + Iterator> iterator = sortedPropertyValues.entrySet().iterator(); while (true) { Long nextQNameId = null; - PropertyMapKey nextPropertyKey = null; + NodePropertyKey nextPropertyKey = null; NodePropertyValue nextPropertyValue = null; // Record the next entry's values if (iterator.hasNext()) { - Map.Entry entry = iterator.next(); + Map.Entry entry = iterator.next(); nextPropertyKey = entry.getKey(); nextPropertyValue = entry.getValue(); nextQNameId = nextPropertyKey.getQnameId(); @@ -5239,19 +2004,13 @@ public class HibernateNodeDaoServiceImpl { // There is no need to collapse list indexes collapsedValue = HibernateNodeDaoServiceImpl.collapsePropertiesWithSameQNameAndListIndex( - currentPropertyDef, - scratch, - localeDAO, - contentDataDAO); + currentPropertyDef, scratch, localeDAO, contentDataDAO); } else { // There is more than one value so the list indexes need to be collapsed - collapsedValue = HibernateNodeDaoServiceImpl.collapsePropertiesWithSameQName( - currentPropertyDef, - scratch, - localeDAO, - contentDataDAO); + collapsedValue = HibernateNodeDaoServiceImpl.collapsePropertiesWithSameQName(currentPropertyDef, + scratch, localeDAO, contentDataDAO); } // If the property is multi-valued then the output property must be a collection if (currentPropertyDef != null && currentPropertyDef.isMultiValued()) @@ -5284,29 +2043,29 @@ public class HibernateNodeDaoServiceImpl // Done return propertyMap; } - + private static Serializable collapsePropertiesWithSameQName( PropertyDefinition propertyDef, - SortedMap sortedPropertyValues, + SortedMap sortedPropertyValues, LocaleDAO localeDAO, ContentDataDAO contentDataDAO) { Serializable result = null; Collection collectionResult = null; - // A working map. Ordering is not important for this map. - Map scratch = new HashMap(3); + // A working map. Ordering is not important for this map. + Map scratch = new HashMap(3); // Iterate (sorted) over the map entries and extract values with the same list index Integer currentListIndex = Integer.MIN_VALUE; - Iterator> iterator = sortedPropertyValues.entrySet().iterator(); + Iterator> iterator = sortedPropertyValues.entrySet().iterator(); while (true) { Integer nextListIndex = null; - PropertyMapKey nextPropertyKey = null; + NodePropertyKey nextPropertyKey = null; NodePropertyValue nextPropertyValue = null; // Record the next entry's values if (iterator.hasNext()) { - Map.Entry entry = iterator.next(); + Map.Entry entry = iterator.next(); nextPropertyKey = entry.getKey(); nextPropertyValue = entry.getValue(); nextListIndex = nextPropertyKey.getListIndex(); @@ -5316,11 +2075,8 @@ public class HibernateNodeDaoServiceImpl { // We have added something to the scratch properties but the index has just changed Serializable collapsedValue = HibernateNodeDaoServiceImpl.collapsePropertiesWithSameQNameAndListIndex( - propertyDef, - scratch, - localeDAO, - contentDataDAO); - // Store. If there is a value already, then we must build a collection. + propertyDef, scratch, localeDAO, contentDataDAO); + // Store. If there is a value already, then we must build a collection. if (result == null) { result = collapsedValue; @@ -5332,12 +2088,12 @@ public class HibernateNodeDaoServiceImpl } else { - // We already had a result, and now have another. A collection has not been - // started. We start a collection and explicitly keep track of it so that + // We already had a result, and now have another. A collection has not been + // started. We start a collection and explicitly keep track of it so that // we don't get mixed up with collections of collections (ETHREEOH-2064). collectionResult = new ArrayList(20); - collectionResult.add(result); // Add the first result - collectionResult.add(collapsedValue); // Add the new value + collectionResult.add(result); // Add the first result + collectionResult.add(collapsedValue); // Add the new value result = (Serializable) collectionResult; } // Reset @@ -5366,18 +2122,18 @@ public class HibernateNodeDaoServiceImpl // Done return result; } - + /** - * At this level, the properties have the same qname and list index. They can only be separated - * by locale. Typically, MLText will fall into this category as only. + * At this level, the properties have the same qname and list index. They can only be separated by locale. + * Typically, MLText will fall into this category as only. *

- * If there are multiple values then they can only be separated by locale. If they are separated - * by locale, then they have to be text-based. This means that the only way to store them is via - * MLText. Any other multi-locale properties cannot be deserialized. + * If there are multiple values then they can only be separated by locale. If they are separated by locale, then + * they have to be text-based. This means that the only way to store them is via MLText. Any other multi-locale + * properties cannot be deserialized. */ private static Serializable collapsePropertiesWithSameQNameAndListIndex( PropertyDefinition propertyDef, - Map propertyValues, + Map propertyValues, LocaleDAO localeDAO, ContentDataDAO contentDataDAO) { @@ -5387,13 +2143,13 @@ public class HibernateNodeDaoServiceImpl { // Nothing to do } - for (Map.Entry entry : propertyValues.entrySet()) + for (Map.Entry entry : propertyValues.entrySet()) { - PropertyMapKey propertyKey = entry.getKey(); + NodePropertyKey propertyKey = entry.getKey(); NodePropertyValue propertyValue = entry.getValue(); - - if (propertyValuesSize == 1 && - (propertyDef == null || !propertyDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT))) + + if (propertyValuesSize == 1 + && (propertyDef == null || !propertyDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT))) { // This is the only value and it is NOT to be converted to MLText value = HibernateNodeDaoServiceImpl.makeSerializableValue(propertyDef, propertyValue, contentDataDAO); @@ -5422,15 +2178,15 @@ public class HibernateNodeDaoServiceImpl // Done return value; } - + /** * Extracts the externally-visible property from the persistable value. * - * @param propertyDef the model property definition - may be null - * @param propertyValue the persisted property - * @param contentDataDAO component that handles ContentData persistence - * @return Returns the value of the property in the format dictated by the property - * definition, or null if the property value is null + * @param propertyDef the model property definition - may be null + * @param propertyValue the persisted property + * @param contentDataDAO component that handles ContentData persistence + * @return Returns the value of the property in the format dictated by the property definition, or null if the + * property value is null */ private static Serializable makeSerializableValue( PropertyDefinition propertyDef, @@ -5456,25 +2212,9 @@ public class HibernateNodeDaoServiceImpl { Serializable value = propertyValue.getValue(propertyTypeQName); // Handle conversions to and from ContentData - if (value instanceof ContentDataId) + if (propertyTypeQName.equals(DataTypeDefinition.CONTENT) && (value instanceof Long)) { - // ContentData used to be persisted - Long contentDataId = ((ContentDataId) value).getId(); - Pair contentDataPair = contentDataDAO.getContentData(contentDataId); - if (contentDataPair == null) - { - // It is invalid - value = null; - } - else - { - value = contentDataPair.getSecond(); - } - } - else if (propertyTypeQName.equals(DataTypeDefinition.CONTENT) && (value instanceof Long)) - { - // ContentData used to be persisted - Pair contentDataPair = contentDataDAO.getContentData((Long)value); + Pair contentDataPair = contentDataDAO.getContentData((Long) value); if (contentDataPair == null) { // It is invalid @@ -5491,27 +2231,12 @@ public class HibernateNodeDaoServiceImpl catch (TypeConversionException e) { throw new TypeConversionException( - "The property value is not compatible with the type defined for the property: \n" + - " property: " + (propertyDef == null ? "unknown" : propertyDef) + "\n" + - " property value: " + propertyValue, - e); + "The property value is not compatible with the type defined for the property: \n" + " property: " + + (propertyDef == null ? "unknown" : propertyDef) + "\n" + " property value: " + + propertyValue, e); } } - - private class SessionFlusher implements HibernateCallback - { - /* (non-Javadoc) - * @see org.springframework.orm.hibernate3.HibernateCallback#doInHibernate(org.hibernate.Session) - */ - public Object doInHibernate(Session session) throws HibernateException, SQLException - { - DirtySessionMethodInterceptor.flushSession(getSession(), true); - return null; - } - - } - private static class NodeInfo implements Serializable { private static final long serialVersionUID = -2167221525380802365L; @@ -5519,9 +2244,9 @@ public class HibernateNodeDaoServiceImpl private final boolean isStoreRoot; private final Map parentAssocInfo; - public NodeInfo(Node node, QNameDAO qnameDAO, List parents) + public NodeInfo(Node node, NodeDAO nodeDAO, QNameDAO qnameDAO, List parents) { - this.isRoot = hasNodeAspect(qnameDAO, node, ContentModel.ASPECT_ROOT); + this.isRoot = nodeDAO.hasNodeAspect(node.getId(), ContentModel.ASPECT_ROOT); this.isStoreRoot = node.getTypeQName(qnameDAO).equals(ContentModel.TYPE_STOREROOT); this.parentAssocInfo = new HashMap(5); for (Object parent : parents) @@ -5610,5 +2335,5 @@ public class HibernateNodeDaoServiceImpl { return parentNodeId; } - } + } } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/node/index/AVMRemoteSnapshotTrackerTest.java b/source/java/org/alfresco/repo/node/index/AVMRemoteSnapshotTrackerTest.java index 4fde436706..4002ba1df3 100644 --- a/source/java/org/alfresco/repo/node/index/AVMRemoteSnapshotTrackerTest.java +++ b/source/java/org/alfresco/repo/node/index/AVMRemoteSnapshotTrackerTest.java @@ -23,8 +23,7 @@ import java.util.concurrent.ThreadPoolExecutor; import javax.transaction.Status; import javax.transaction.UserTransaction; -import org.alfresco.repo.content.ContentStore; -import org.alfresco.repo.node.db.NodeDaoService; +import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor; import org.alfresco.repo.search.Indexer; import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer; @@ -63,7 +62,7 @@ public class AVMRemoteSnapshotTrackerTest extends BaseSpringTest private Indexer indexer; - private NodeDaoService nodeDaoService; + private NodeDAO nodeDAO; private ThreadPoolExecutor threadPoolExecutor; @@ -86,7 +85,7 @@ public class AVMRemoteSnapshotTrackerTest extends BaseSpringTest nodeService = serviceRegistry.getNodeService(); ftsIndexer = (FullTextSearchIndexer) applicationContext.getBean("LuceneFullTextSearchIndexer"); indexer = (Indexer) applicationContext.getBean("indexerComponent"); - nodeDaoService = (NodeDaoService) applicationContext.getBean("nodeDaoService"); + nodeDAO = (NodeDAO) applicationContext.getBean("nodeDAO"); threadPoolExecutor = (ThreadPoolExecutor) applicationContext.getBean("indexTrackerThreadPoolExecutor"); @@ -186,7 +185,7 @@ public class AVMRemoteSnapshotTrackerTest extends BaseSpringTest tracker.setTransactionService((TransactionServiceImpl) transactionService); tracker.setFtsIndexer(ftsIndexer); tracker.setIndexer(indexer); - tracker.setNodeDaoService(nodeDaoService); + tracker.setNodeDAO(nodeDAO); tracker.setNodeService(nodeService); tracker.setSearcher(searchService); tracker.setThreadPoolExecutor(threadPoolExecutor); diff --git a/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java b/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java index fb26b2a1af..980bd51293 100644 --- a/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java +++ b/source/java/org/alfresco/repo/node/index/AbstractReindexComponent.java @@ -20,7 +20,7 @@ package org.alfresco.repo.node.index; import java.io.PrintWriter; import java.io.StringWriter; -import java.util.ArrayList; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.LinkedBlockingQueue; @@ -31,14 +31,14 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; -import org.alfresco.repo.domain.Transaction; -import org.alfresco.repo.node.db.NodeDaoService; +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.repo.domain.node.Transaction; 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.tenant.TenantService; +import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.TransactionListenerAdapter; import org.alfresco.repo.transaction.TransactionServiceImpl; @@ -52,11 +52,11 @@ 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.springframework.extensions.surf.util.ParameterCheck; import org.alfresco.util.PropertyCheck; import org.alfresco.util.VmShutdownListener; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.ParameterCheck; /** * Abstract helper for reindexing. @@ -86,13 +86,13 @@ public abstract class AbstractReindexComponent implements IndexRecovery /** the component giving direct access to store instances */ protected NodeService nodeService; /** the component giving direct access to transaction instances */ - protected NodeDaoService nodeDaoService; + protected NodeDAO nodeDAO; /** the component that holds the reindex worker threads */ private ThreadPoolExecutor threadPoolExecutor; - private TenantService tenantService; - private List storesToIgnore = new ArrayList(0); - + private TenantService tenantService; + private List storesToIgnore = new ArrayList(0); + private volatile boolean shutdown; private final WriteLock indexerWriteLock; @@ -183,11 +183,11 @@ public abstract class AbstractReindexComponent implements IndexRecovery } /** - * @param nodeDaoService provides access to transaction-related queries + * @param nodeDAO provides access to transaction-related queries */ - public void setNodeDaoService(NodeDaoService nodeDaoService) + public void setNodeDAO(NodeDAO nodeDAO) { - this.nodeDaoService = nodeDaoService; + this.nodeDAO = nodeDAO; } /** @@ -202,21 +202,21 @@ public abstract class AbstractReindexComponent implements IndexRecovery { this.threadPoolExecutor = threadPoolExecutor; } - - public void setTenantService(TenantService tenantService) - { - this.tenantService = tenantService; - } - - public void setStoresToIgnore(List storesToIgnore) - { - this.storesToIgnore = storesToIgnore; - } - - public List getStoresToIgnore() - { - return this.storesToIgnore; - } + + public void setTenantService(TenantService tenantService) + { + this.tenantService = tenantService; + } + + public void setStoresToIgnore(List storesToIgnore) + { + this.storesToIgnore = storesToIgnore; + } + + public List getStoresToIgnore() + { + return this.storesToIgnore; + } /** * Determines if calls to {@link #reindexImpl()} should be wrapped in a transaction or not. @@ -247,7 +247,7 @@ public abstract class AbstractReindexComponent implements IndexRecovery PropertyCheck.mandatory(this, "indexer", this.indexer); PropertyCheck.mandatory(this, "searcher", this.searcher); PropertyCheck.mandatory(this, "nodeService", this.nodeService); - PropertyCheck.mandatory(this, "nodeDaoService", this.nodeDaoService); + PropertyCheck.mandatory(this, "nodeDaoService", this.nodeDAO); PropertyCheck.mandatory(this, "transactionComponent", this.transactionService); if (indexerWriteLock.tryLock()) @@ -335,23 +335,23 @@ public abstract class AbstractReindexComponent implements IndexRecovery storeRefsIterator.remove(); } } - - List storesToIgnore = getStoresToIgnore(); - if (storesToIgnore != null) - { - - storeRefsIterator = storeRefs.iterator(); - while (storeRefsIterator.hasNext()) - { - // Remove stores to ignore - StoreRef storeRef = storeRefsIterator.next(); - if (storesToIgnore.contains(storeRef.toString())) - { - storeRefsIterator.remove(); - } - } - } - + + List storesToIgnore = getStoresToIgnore(); + if (storesToIgnore != null) + { + + storeRefsIterator = storeRefs.iterator(); + while (storeRefsIterator.hasNext()) + { + // Remove stores to ignore + StoreRef storeRef = storeRefsIterator.next(); + if (storesToIgnore.contains(storeRef.toString())) + { + storeRefsIterator.remove(); + } + } + } + // Change the ordering to favour the most common stores if (storeRefs.contains(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE)) { @@ -416,9 +416,9 @@ public abstract class AbstractReindexComponent implements IndexRecovery if (!foundInIndex) { // If none of the stores have the transaction, then that might be because it consists of 0 modifications - int updateCount = nodeDaoService.getTxnUpdateCount(txnId); - - /* Alternative (r15360) + int updateCount = nodeDAO.getTxnUpdateCount(txnId); + + /* Alternative (r15360) // exclude updates in the version store if(updateCount > 0) { @@ -449,9 +449,9 @@ public abstract class AbstractReindexComponent implements IndexRecovery } } - */ - - if ((updateCount > 0) && (! allUpdatedNodesCanBeIgnored(txnId))) + */ + + if ((updateCount > 0) && (! allUpdatedNodesCanBeIgnored(txnId))) { // There were updates, but there is no sign in the indexes result = InIndex.NO; @@ -459,7 +459,7 @@ public abstract class AbstractReindexComponent implements IndexRecovery else { // We're now in the case where there were no updates - int deleteCount = nodeDaoService.getTxnDeleteCount(txnId); + int deleteCount = nodeDAO.getTxnDeleteCount(txnId); if (deleteCount == 0) { // There are no updates or deletes and no entry in the indexes. @@ -541,53 +541,53 @@ public abstract class AbstractReindexComponent implements IndexRecovery } } - protected boolean allUpdatedNodesCanBeIgnored(Long txnId) - { - boolean allUpdatedNodesCanBeIgnored = false; - List storesToIgnore = getStoresToIgnore(); - if ((storesToIgnore != null) && (storesToIgnore.size() > 0) && (txnId != null)) - { - List nodeRefs = nodeDaoService.getTxnChanges(txnId); - - allUpdatedNodesCanBeIgnored = true; - for (NodeRef nodeRef : nodeRefs) - { - if (nodeRef != null) - { - Status nodeStatus = nodeService.getNodeStatus(nodeRef); - if (nodeStatus == null) - { - // it's not there any more - continue; - } - if (! nodeStatus.isDeleted()) - { - // updated node (ie. not deleted) - StoreRef storeRef = nodeRef.getStoreRef(); - if (tenantService != null) - { - storeRef = tenantService.getBaseName(nodeRef.getStoreRef()); - } - - if (! storesToIgnore.contains(storeRef.toString())) - { - allUpdatedNodesCanBeIgnored = false; - break; - } - } - } - } - } - - return allUpdatedNodesCanBeIgnored; - } - + protected boolean allUpdatedNodesCanBeIgnored(Long txnId) + { + boolean allUpdatedNodesCanBeIgnored = false; + List storesToIgnore = getStoresToIgnore(); + if ((storesToIgnore != null) && (storesToIgnore.size() > 0) && (txnId != null)) + { + List nodeRefs = nodeDAO.getTxnChanges(txnId); + + allUpdatedNodesCanBeIgnored = true; + for (NodeRef nodeRef : nodeRefs) + { + if (nodeRef != null) + { + Status nodeStatus = nodeService.getNodeStatus(nodeRef); + if (nodeStatus == null) + { + // it's not there any more + continue; + } + if (! nodeStatus.isDeleted()) + { + // updated node (ie. not deleted) + StoreRef storeRef = nodeRef.getStoreRef(); + if (tenantService != null) + { + storeRef = tenantService.getBaseName(nodeRef.getStoreRef()); + } + + if (! storesToIgnore.contains(storeRef.toString())) + { + allUpdatedNodesCanBeIgnored = false; + break; + } + } + } + } + } + + return allUpdatedNodesCanBeIgnored; + } + private boolean haveNodesBeenRemovedFromIndex(final StoreRef storeRef, final Transaction txn) { final Long txnId = txn.getId(); // 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); + List nodeRefs = nodeDAO.getTxnChangesForStore(storeRef, txnId); boolean foundNodeRef = false; for (NodeRef nodeRef : nodeRefs) { @@ -689,7 +689,7 @@ public abstract class AbstractReindexComponent implements IndexRecovery } // get the node references pertinent to the transaction - List nodeRefs = nodeDaoService.getTxnChanges(txnId); + List nodeRefs = nodeDAO.getTxnChanges(txnId); // reindex each node int nodeCount = 0; for (NodeRef nodeRef : nodeRefs) diff --git a/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java b/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java index cb888da357..9fafadef4d 100644 --- a/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java +++ b/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponent.java @@ -24,10 +24,8 @@ import java.util.Date; import java.util.Iterator; import java.util.List; -import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.model.ContentModel; -import org.alfresco.repo.domain.Transaction; -import org.alfresco.repo.node.index.AbstractReindexComponent.InIndex; +import org.alfresco.repo.domain.node.Transaction; import org.alfresco.repo.node.index.IndexTransactionTracker.IndexTransactionTrackerListener; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.repository.ChildAssociationRef; @@ -36,6 +34,7 @@ import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.NodeRef.Status; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.I18NUtil; /** * Component to check and recover the indexes. By default, the server is @@ -185,12 +184,12 @@ public class FullIndexRecoveryComponent extends AbstractReindexComponent } - List startTxns = nodeDaoService.getTxnsByCommitTimeAscending( + List startTxns = nodeDAO.getTxnsByCommitTimeAscending( Long.MIN_VALUE, Long.MAX_VALUE, 1000, null, false); InIndex startAllPresent = areTxnsInStartSample(startTxns); - List endTxns = nodeDaoService.getTxnsByCommitTimeDescending( + List endTxns = nodeDAO.getTxnsByCommitTimeDescending( Long.MIN_VALUE, Long.MAX_VALUE, 1000, null, false); InIndex endAllPresent = areAllTxnsInEndSample(endTxns); @@ -337,7 +336,7 @@ public class FullIndexRecoveryComponent extends AbstractReindexComponent transactionService.getRetryingTransactionHelper().doInTransaction(deleteWork, true, true); - int txnCount = nodeDaoService.getTransactionCount(); + int txnCount = nodeDAO.getTransactionCount(); // starting String msgStart = I18NUtil.getMessage(MSG_RECOVERY_STARTING, txnCount); logger.info(msgStart); @@ -349,7 +348,7 @@ public class FullIndexRecoveryComponent extends AbstractReindexComponent List lastTxnIds = Collections.emptyList(); while(true) { - List nextTxns = nodeDaoService.getTxnsByCommitTimeAscending( + List nextTxns = nodeDAO.getTxnsByCommitTimeAscending( fromTimeInclusive, toTimeExclusive, MAX_TRANSACTIONS_PER_ITERATION, @@ -447,7 +446,7 @@ public class FullIndexRecoveryComponent extends AbstractReindexComponent public Object execute() throws Exception { // get the node references pertinent to the transaction - List nodeRefs = nodeDaoService.getTxnChanges(txnId); + List nodeRefs = nodeDAO.getTxnChanges(txnId); // reindex each node for (NodeRef nodeRef : nodeRefs) { diff --git a/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponentTest.java b/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponentTest.java index 362219e5b3..bcff946cb3 100644 --- a/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponentTest.java +++ b/source/java/org/alfresco/repo/node/index/FullIndexRecoveryComponentTest.java @@ -25,11 +25,10 @@ import javax.transaction.UserTransaction; import junit.framework.TestCase; import org.alfresco.model.ContentModel; -import org.alfresco.repo.domain.Transaction; -import org.alfresco.repo.node.db.NodeDaoService; +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.repo.domain.node.Transaction; import org.alfresco.repo.node.index.AbstractReindexComponent.InIndex; import org.alfresco.repo.security.authentication.AuthenticationComponent; -import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; @@ -48,22 +47,13 @@ public class FullIndexRecoveryComponentTest extends TestCase private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); private FullIndexRecoveryComponent indexRecoverer; - private AVMFullIndexRecoveryComponent avmIndexRecoveryComponent; - private NodeService nodeService; - private NodeRef rootNodeRef; - private TransactionService transactionService; - - private RetryingTransactionHelper retryingTransactionHelper; - private AuthenticationComponent authenticationComponent; - private UserTransaction testTX; - - private NodeDaoService nodeDaoService; + private NodeDAO nodeDAO; public void setUp() throws Exception { @@ -71,9 +61,8 @@ public class FullIndexRecoveryComponentTest extends TestCase avmIndexRecoveryComponent = (AVMFullIndexRecoveryComponent) ctx.getBean("avmIndexRecoveryComponent"); nodeService = (NodeService) ctx.getBean("nodeService"); transactionService = (TransactionService) ctx.getBean("transactionComponent"); - retryingTransactionHelper = (RetryingTransactionHelper) ctx.getBean("retryingTransactionHelper"); authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent"); - nodeDaoService = (NodeDaoService) ctx.getBean("nodeDaoServiceImpl"); + nodeDAO = (NodeDAO) ctx.getBean("nodeDAO"); testTX = transactionService.getUserTransaction(); testTX.begin(); @@ -142,17 +131,17 @@ public class FullIndexRecoveryComponentTest extends TestCase // - List endTxns = nodeDaoService.getTxnsByCommitTimeDescending( + List endTxns = nodeDAO.getTxnsByCommitTimeDescending( Long.MIN_VALUE, Long.MAX_VALUE, 20, null, false); InIndex endAllPresent = indexRecoverer.areAllTxnsInEndSample(endTxns); assertEquals(InIndex.INDETERMINATE, endAllPresent); - endTxns = nodeDaoService.getTxnsByCommitTimeDescending( + endTxns = nodeDAO.getTxnsByCommitTimeDescending( Long.MIN_VALUE, Long.MAX_VALUE, 21, null, false); endAllPresent = indexRecoverer.areAllTxnsInEndSample(endTxns); assertEquals(InIndex.INDETERMINATE, endAllPresent); - endTxns = nodeDaoService.getTxnsByCommitTimeDescending( + endTxns = nodeDAO.getTxnsByCommitTimeDescending( Long.MIN_VALUE, Long.MAX_VALUE, 22, null, false); endAllPresent = indexRecoverer.areAllTxnsInEndSample(endTxns); assertEquals(InIndex.YES, endAllPresent); diff --git a/source/java/org/alfresco/repo/node/index/IndexTransactionTracker.java b/source/java/org/alfresco/repo/node/index/IndexTransactionTracker.java index 7f82f75115..315d5557b6 100644 --- a/source/java/org/alfresco/repo/node/index/IndexTransactionTracker.java +++ b/source/java/org/alfresco/repo/node/index/IndexTransactionTracker.java @@ -27,12 +27,12 @@ import java.util.Map; import java.util.TreeMap; import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.repo.domain.Transaction; +import org.alfresco.repo.domain.node.Transaction; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.springframework.extensions.surf.util.ISO8601DateFormat; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.ISO8601DateFormat; /** * Component to check and recover the indexes. @@ -284,7 +284,7 @@ public class IndexTransactionTracker extends AbstractReindexComponent { public Long execute() throws Exception { - Transaction txn = nodeDaoService.getTxnById(txnId); + Transaction txn = nodeDAO.getTxnById(txnId); if (txn != null) { return txn.getCommitTimeMs(); @@ -436,7 +436,7 @@ found: while (true) { // Get the most recent transaction before the given look-back - List nextTransactions = nodeDaoService.getTxnsByCommitTimeDescending( + List nextTransactions = nodeDAO.getTxnsByCommitTimeDescending( 0L, toTimeExclusive, 1, @@ -512,7 +512,7 @@ found: // If the batch is full or if there are no more voids, fire the query if (voidTxnIdBatch.size() == VOID_BATCH_SIZE || !voidTxnIdIterator.hasNext()) { - List filledTxns = nodeDaoService.getTxnsByMinCommitTime(voidTxnIdBatch); + List filledTxns = nodeDAO.getTxnsByCommitTimeAscending(voidTxnIdBatch); for (Transaction txn : filledTxns) { if (txn.getCommitTimeMs() == null) // Just coping with Hibernate mysteries @@ -572,7 +572,7 @@ found: private List getNextTransactions(long fromTimeInclusive, long toTimeExclusive, List previousTxnIds) { - List txns = nodeDaoService.getTxnsByCommitTimeAscending( + List txns = nodeDAO.getTxnsByCommitTimeAscending( fromTimeInclusive, toTimeExclusive, maxRecordSetSize, diff --git a/source/java/org/alfresco/repo/node/index/IndexTransactionTrackerTest.java b/source/java/org/alfresco/repo/node/index/IndexTransactionTrackerTest.java index 9c95503f4d..b8885f76fd 100644 --- a/source/java/org/alfresco/repo/node/index/IndexTransactionTrackerTest.java +++ b/source/java/org/alfresco/repo/node/index/IndexTransactionTrackerTest.java @@ -24,6 +24,7 @@ import junit.framework.TestCase; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.ContentStore; +import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.search.Indexer; import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer; @@ -77,13 +78,13 @@ public class IndexTransactionTrackerTest extends TestCase ftsIndexer = (FullTextSearchIndexer) ctx.getBean("LuceneFullTextSearchIndexer"); indexer = (Indexer) ctx.getBean("indexerComponent"); - NodeDaoService nodeDaoService = (NodeDaoService) ctx.getBean("nodeDaoService"); + NodeDAO nodeDAO = (NodeDAO) ctx.getBean("nodeDAO"); TransactionService transactionService = serviceRegistry.getTransactionService(); indexTracker = new IndexTransactionTracker(); indexTracker.setAuthenticationComponent(authenticationComponent); indexTracker.setFtsIndexer(ftsIndexer); indexTracker.setIndexer(indexer); - indexTracker.setNodeDaoService(nodeDaoService); + indexTracker.setNodeDAO(nodeDAO); indexTracker.setNodeService(nodeService); indexTracker.setThreadPoolExecutor(threadPoolExecutor); indexTracker.setSearcher(searchService); diff --git a/source/java/org/alfresco/repo/node/index/MissingContentReindexComponentTest.java b/source/java/org/alfresco/repo/node/index/MissingContentReindexComponentTest.java index f167f5e1f4..ad00a6e4fe 100644 --- a/source/java/org/alfresco/repo/node/index/MissingContentReindexComponentTest.java +++ b/source/java/org/alfresco/repo/node/index/MissingContentReindexComponentTest.java @@ -26,7 +26,7 @@ import org.alfresco.model.ContentModel; import org.alfresco.repo.content.ContentContext; import org.alfresco.repo.content.ContentStore; import org.alfresco.repo.content.filestore.FileContentStore; -import org.alfresco.repo.node.db.NodeDaoService; +import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.search.Indexer; import org.alfresco.repo.search.impl.lucene.AbstractLuceneIndexerImpl; import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer; @@ -80,13 +80,13 @@ public class MissingContentReindexComponentTest extends TestCase ftsIndexer = (FullTextSearchIndexer) ctx.getBean("LuceneFullTextSearchIndexer"); Indexer indexer = (Indexer) ctx.getBean("indexerComponent"); - NodeDaoService nodeDaoService = (NodeDaoService) ctx.getBean("nodeDaoService"); + NodeDAO nodeDAO = (NodeDAO) ctx.getBean("nodeDAO"); TransactionService transactionService = serviceRegistry.getTransactionService(); reindexer = new MissingContentReindexComponent(); reindexer.setAuthenticationComponent(authenticationComponent); reindexer.setFtsIndexer(ftsIndexer); reindexer.setIndexer(indexer); - reindexer.setNodeDaoService(nodeDaoService); + reindexer.setNodeDAO(nodeDAO); reindexer.setNodeService(nodeService); reindexer.setThreadPoolExecutor(threadPoolExecutor); reindexer.setSearcher(searchService); diff --git a/source/java/org/alfresco/repo/props/PropertyValueComponent.java b/source/java/org/alfresco/repo/props/PropertyValueComponent.java deleted file mode 100644 index 63570ee998..0000000000 --- a/source/java/org/alfresco/repo/props/PropertyValueComponent.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.props; - -import java.io.Serializable; - -import org.springframework.dao.DataIntegrityViolationException; - -/** - * A component that gives high-level access to manipulate standalone properties. - *

- * There are two types of properties: shared and unshared. - *

- * Simple, Shared Properties:
- * These properties are globally unique (apart from values that don't have a meaningful key). - * If two different applications attempt to create the same value, then the same ID will - * be returned (after conflict resolution), assuming that the value is not treated as binary - * data. It is not possible to modify or delete these values. You should store types that - * can be converted to and from a well-known type. Complex collections should not be stored - * using this value.
- * Unshared Properties:
- * These properties may be duplicated, modifed and deleted. It is not possible to look - * values up and therefore new IDs are generated for each creation. Complex values can - * be stored in these properties and will be exploded recursively.
- * - * @author Derek Hulley - * @since 3.2 - */ -public interface PropertyValueComponent -{ - /** - * @param id the ID (may not be null) - * @throws DataIntegrityViolationException if the ID is invalid - */ - Serializable getSharedValueById(Long id); - /** - * @param value the value to find the ID for (may be null) - * @return Returns the ID of the shared value or null if it doesn't exist - */ - Long getSharedValueId(Serializable value); - /** - * @param value the value to find the ID for (may be null) - * @return Returns the ID of the shared value (created or not) - */ - Long getOrCreateSharedValue(Serializable value); - - /** - * @param id the ID (may not be null) - * @return Returns the value of the property (never null) - * @throws DataIntegrityViolationException if the ID is invalid - */ - Serializable getUnsharedPropertyById(Long id); - /** - * @param value the value to create (may be null) - * @return Returns the new property's ID - */ - Long createUnsharedProperty(Serializable value); - /** - * @param id the ID of the root property to change (may not be null) - * @param value the new property value - * @throws DataIntegrityViolationException if the ID is invalid - */ - void updateUnsharedProperty(Long id, Serializable value); - /** - * @param id the ID of the root property to delete (may be null) - * @throws DataIntegrityViolationException if the ID is invalid - */ - void deleteUnsharedProperty(Long id); - - /** - * Create a new combination of three unique properties. - * - * @param value1 the first property, which should denote application name or use-case ID - * (null allowed) - * @param value2 the second property, which should denote the context or container value - * (null allowed) - * @param value3 the third property, which should denote the unique value within the context - * of the previous two properties (null allowed) - * @return Returns the ID of the unique property combination for later updates - * @throws PropertyUniqueConstraintViolation if the combination is not unique - */ - Long createPropertyUniqueContext(Serializable value1, Serializable value2, Serializable value3); - /** - * Get the ID of a unique property context. - * - * @see #createPropertyUniqueContext(Serializable, Serializable, Serializable) - */ - Long getPropertyUniqueContext(Serializable value1, Serializable value2, Serializable value3); - /** - * Update a unique property context. - * - * @see #createPropertyUniqueContext(Serializable, Serializable, Serializable) - */ - void updatePropertyUniqueContext(Long id, Serializable value1, Serializable value2, Serializable value3); - /** - * Update a combination of three unique properties. If the before values exist, then they - * are updated to the new values. If the before values don't exist, then the new values - * are created assuming no pre-existence - - * using {@link #createPropertyUniqueContext(Serializable, Serializable, Serializable) create} is better - * if there is no pre-existing set of values. - * - * @param value1Before the first property before (null allowed) - * @param value2Before the second property before (null allowed) - * @param value3Before the third property before (null allowed) - * @param value1 the first property (null allowed) - * @param value2 the second property (null allowed) - * @param value3 the third property (null allowed) - * @return Returns the ID of the unique property combination for later updates - * @throws PropertyUniqueConstraintViolation if the new combination is not unique - */ - Long updatePropertyUniqueContext( - Serializable value1Before, Serializable value2Before, Serializable value3Before, - Serializable value1, Serializable value2, Serializable value3); - /** - * Delete a unique property context. - * - * @see #createPropertyUniqueContext(Serializable, Serializable, Serializable) - */ - void deletePropertyUniqueContext(Long id); - /** - * Delete a combination of three unique properties. It doesn't matter if the unique combination - * already existed or not. - * - * @param values an array of one, two or three values, any of which may be null - * @return Returns the number of unique combinations deleted - */ - int deletePropertyUniqueContexts(Serializable ... values); -} diff --git a/source/java/org/alfresco/repo/props/PropertyValueComponentImpl.java b/source/java/org/alfresco/repo/props/PropertyValueComponentImpl.java deleted file mode 100644 index 7d16c0a161..0000000000 --- a/source/java/org/alfresco/repo/props/PropertyValueComponentImpl.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.props; - -import java.io.Serializable; - -import org.alfresco.repo.domain.propval.PropertyValueDAO; -import org.alfresco.util.Pair; -import org.alfresco.util.PropertyCheck; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This component provides a clearer distinction between shared and unshared properties and - * avoids the need to access the DAO, which is much more obscure and potentially harmful. - * - * @author Derek Hulley - * @since 3.2 - */ -public class PropertyValueComponentImpl implements PropertyValueComponent -{ - private static final Log logger = LogFactory.getLog(PropertyValueComponentImpl.class); - - private PropertyValueDAO propertyValueDAO; - - /** - * Set the underlying DAO that manipulates the database data - */ - public void setPropertyValueDAO(PropertyValueDAO propertyValueDAO) - { - this.propertyValueDAO = propertyValueDAO; - } - - /** - * Ensures that all necessary properties have been set - */ - public void init() - { - PropertyCheck.mandatory(this, "propertyValueDAO", propertyValueDAO); - } - - /** - * @return If the pair value is not null, returns the first value (ID) - */ - private Long getEntityPairId(Pair pair) - { - if (pair == null) - { - return null; - } - else - { - return pair.getFirst(); - } - } - - /** - * @return If the pair value is not null, returns the second value (value) - */ - private Serializable getEntityPairValue(Pair pair) - { - if (pair == null) - { - return null; - } - else - { - return pair.getSecond(); - } - } - - /** - * {@inheritDoc} - */ - public Serializable getSharedValueById(Long id) - { - Pair pair = propertyValueDAO.getPropertyValueById(id); - return getEntityPairValue(pair); - } - /** - * {@inheritDoc} - */ - public Long getSharedValueId(Serializable value) - { - Pair pair = propertyValueDAO.getPropertyValue(value); - return getEntityPairId(pair); - } - /** - * {@inheritDoc} - */ - public Long getOrCreateSharedValue(Serializable value) - { - Pair pair = propertyValueDAO.getOrCreatePropertyValue(value); - return getEntityPairId(pair); - } - - /** - * {@inheritDoc} - */ - public Serializable getUnsharedPropertyById(Long id) - { - return propertyValueDAO.getPropertyById(id); - } - /** - * {@inheritDoc} - */ - public Long createUnsharedProperty(Serializable value) - { - return propertyValueDAO.createProperty(value); - } - /** - * {@inheritDoc} - */ - public void updateUnsharedProperty(Long id, Serializable value) - { - propertyValueDAO.updateProperty(id, value); - } - /** - * {@inheritDoc} - */ - public void deleteUnsharedProperty(Long id) - { - propertyValueDAO.deleteProperty(id); - } - - /** - * {@inheritDoc} - */ - public Long createPropertyUniqueContext(Serializable value1, Serializable value2, Serializable value3) - { - Long id = propertyValueDAO.createPropertyUniqueContext(value1, value2, value3); - // Done - if (logger.isDebugEnabled()) - { - logger.debug( - "Created unique property context: \n" + - " ID: " + id + "\n" + - " Value1: " + value1 + "\n" + - " Value2: " + value2 + "\n" + - " Value3: " + value3); - } - return id; - } - /** - * {@inheritDoc} - */ - public Long getPropertyUniqueContext(Serializable value1, Serializable value2, Serializable value3) - { - return propertyValueDAO.getPropertyUniqueContext(value1, value2, value3); - } - /** - * {@inheritDoc} - */ - public void updatePropertyUniqueContext(Long id, Serializable value1, Serializable value2, Serializable value3) - { - propertyValueDAO.updatePropertyUniqueContext(id, value1, value2, value3); - // Done - if (logger.isDebugEnabled()) - { - logger.debug( - "Updated unique property context: \n" + - " ID: " + id + "\n" + - " Value1: " + value1 + "\n" + - " Value2: " + value2 + "\n" + - " Value3: " + value3); - } - } - /** - * {@inheritDoc} - */ - public Long updatePropertyUniqueContext( - Serializable value1Before, Serializable value2Before, Serializable value3Before, - Serializable value1, Serializable value2, Serializable value3) - { - Long id = getPropertyUniqueContext(value1Before, value2Before, value3Before); - if (id == null) - { - // It didn't exist before, so just create it - id = createPropertyUniqueContext(value1, value2, value3); - } - else - { - // Update itUpdated - updatePropertyUniqueContext(id, value1, value2, value3); - } - // Done - if (logger.isDebugEnabled()) - { - logger.debug( - "Updated unique property context: \n" + - " Value1 Before: " + value1Before + "\n" + - " Value2 Before: " + value2Before + "\n" + - " Value3 Before: " + value3Before + "\n" + - " Value1: " + value1 + "\n" + - " Value2: " + value2 + "\n" + - " Value3: " + value3); - } - return id; - } - /** - * {@inheritDoc} - */ - public void deletePropertyUniqueContext(Long id) - { - propertyValueDAO.deletePropertyUniqueContext(id); - // Done - if (logger.isDebugEnabled()) - { - logger.debug( - "Deleted unique property context: \n" + - " ID: " + id); - } - } - /** - * {@inheritDoc} - */ - public int deletePropertyUniqueContexts(Serializable ... values) - { - int deleted = propertyValueDAO.deletePropertyUniqueContext(values); - // Done - if (logger.isDebugEnabled()) - { - logger.debug( - "Deleted " + deleted + " unique property contexts: \n" + - " Values: " + values); - } - return deleted; - } -} diff --git a/source/java/org/alfresco/repo/props/PropertyValueComponentTest.java b/source/java/org/alfresco/repo/props/PropertyValueComponentTest.java deleted file mode 100644 index 8b4a75fc45..0000000000 --- a/source/java/org/alfresco/repo/props/PropertyValueComponentTest.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.props; - -import junit.framework.TestCase; - -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.ApplicationContextHelper; -import org.alfresco.util.GUID; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.context.ApplicationContext; - -/** - * @see PropertyValueComponent - * - * @author Derek Hulley - * @since 3.2 - */ -public class PropertyValueComponentTest extends TestCase -{ - private static final Log logger = LogFactory.getLog(PropertyValueComponentTest.class); - - private ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); - - private TransactionService transactionService; - private PropertyValueComponent propertyValueComponent; - - @Override - public void setUp() - { - transactionService = (TransactionService) ctx.getBean("transactionService"); - propertyValueComponent = (PropertyValueComponent) ctx.getBean("propertyValueComponent"); - } - - public void testSetUp() - { - } - - public void testUniqueContext_UpdateFromNothing() - { - // The non-existent source properties - final String value1 = GUID.generate(); - final String value2 = GUID.generate(); - final String value3 = GUID.generate(); - // The target properties - final String context = getName(); - final StoreRef store = StoreRef.STORE_REF_WORKSPACE_SPACESSTORE; - final String uuid1 = GUID.generate(); - final String uuid2 = GUID.generate(); - - RetryingTransactionCallback updateCallback = new RetryingTransactionCallback() - { - public Long execute() throws Throwable - { - return propertyValueComponent.updatePropertyUniqueContext( - value1, value2, value3, - context, store, uuid1); - } - }; - final Long id1 = transactionService.getRetryingTransactionHelper().doInTransaction(updateCallback); - // Now attempt to create the context again and check for failure - RetryingTransactionCallback updateAgainCallback = new RetryingTransactionCallback() - { - public Long execute() throws Throwable - { - return propertyValueComponent.updatePropertyUniqueContext( - context, store, uuid1, - context, store, uuid2); - } - }; - final Long id2 = transactionService.getRetryingTransactionHelper().doInTransaction(updateAgainCallback); - assertEquals("The ID should be reused for the update", id1, id2); - // Now create the uuid1 again (should work) - final Long id3 = transactionService.getRetryingTransactionHelper().doInTransaction(updateCallback); - assertNotSame("Should have created a new instance", id1, id3); - - // Now test failure - RetryingTransactionCallback updateFailureCallback = new RetryingTransactionCallback() - { - public Long execute() throws Throwable - { - return propertyValueComponent.updatePropertyUniqueContext( - context, store, uuid1, - context, store, uuid2); - } - }; - try - { - transactionService.getRetryingTransactionHelper().doInTransaction(updateFailureCallback); - fail("Expected to get a PropertyUniqueConstraintViolation"); - } - catch (PropertyUniqueConstraintViolation e) - { - // Expected - if (logger.isDebugEnabled()) - { - logger.debug("Expected exception: " + e.getMessage()); - } - } - - // Delete everything for the store and check that both are creatable again - RetryingTransactionCallback deleteStoreCallback = new RetryingTransactionCallback() - { - public Void execute() throws Throwable - { - propertyValueComponent.deletePropertyUniqueContexts(context, store); - propertyValueComponent.createPropertyUniqueContext(context, store, uuid1); - propertyValueComponent.createPropertyUniqueContext(context, store, uuid2); - return null; - } - }; - transactionService.getRetryingTransactionHelper().doInTransaction(deleteStoreCallback); - - // Delete everything for the context and check that both are creatable again - RetryingTransactionCallback deleteContextCallback = new RetryingTransactionCallback() - { - public Void execute() throws Throwable - { - propertyValueComponent.deletePropertyUniqueContexts(context); - propertyValueComponent.createPropertyUniqueContext(context, store, uuid1); - propertyValueComponent.createPropertyUniqueContext(context, store, uuid2); - return null; - } - }; - transactionService.getRetryingTransactionHelper().doInTransaction(deleteContextCallback); - } -} diff --git a/source/java/org/alfresco/repo/remote/AttributeServiceRemote.java b/source/java/org/alfresco/repo/remote/AttributeServiceRemote.java deleted file mode 100644 index dc4296f251..0000000000 --- a/source/java/org/alfresco/repo/remote/AttributeServiceRemote.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.remote; - -import java.util.List; -import java.util.Map; - -import org.alfresco.repo.attributes.Attribute; -import org.alfresco.service.cmr.attributes.AttrQuery; -import org.alfresco.service.cmr.attributes.AttributeService; -import org.alfresco.service.cmr.remote.AttributeServiceTransport; -import org.alfresco.util.Pair; - -/** - * Client side AttributeService implementation. - * @author britt - */ -public class AttributeServiceRemote implements AttributeService -{ - private AttributeServiceTransport fTransport; - - private ClientTicketHolder fTicketHolder; - - public AttributeServiceRemote() - { - } - - public void setAttributeServiceTransport(AttributeServiceTransport transport) - { - fTransport = transport; - } - - public void setClientTicketHolder(ClientTicketHolder holder) - { - fTicketHolder = holder; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#addAttribute(java.lang.String, org.alfresco.repo.attributes.Attribute) - */ - public void addAttribute(String path, Attribute value) - { - fTransport.addAttribute(fTicketHolder.getTicket(), path, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#addAttribute(java.util.List, org.alfresco.repo.attributes.Attribute) - */ - public void addAttribute(List keys, Attribute value) - { - fTransport.addAttribute(fTicketHolder.getTicket(), keys, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#getAttribute(java.lang.String) - */ - public Attribute getAttribute(String path) - { - return fTransport.getAttribute(fTicketHolder.getTicket(), path); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#getAttribute(java.util.List) - */ - public Attribute getAttribute(List keys) - { - return fTransport.getAttribute(fTicketHolder.getTicket(), keys); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#getKeys(java.lang.String) - */ - public List getKeys(String path) - { - return fTransport.getKeys(fTicketHolder.getTicket(), path); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#getKeys(java.util.List) - */ - public List getKeys(List keys) - { - return fTransport.getKeys(fTicketHolder.getTicket(), keys); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#query(java.lang.String, org.alfresco.service.cmr.attributes.AttrQuery) - */ - public List> query(String path, AttrQuery query) - { - return fTransport.query(fTicketHolder.getTicket(), path, query); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#query(java.util.List, org.alfresco.service.cmr.attributes.AttrQuery) - */ - public List> query(List keys, - AttrQuery query) - { - return fTransport.query(fTicketHolder.getTicket(), keys, query); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#removeAttribute(java.lang.String, java.lang.String) - */ - public void removeAttribute(String path, String name) - { - fTransport.removeAttribute(fTicketHolder.getTicket(), path, name); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#removeAttribute(java.util.List, java.lang.String) - */ - public void removeAttribute(List keys, String name) - { - fTransport.removeAttribute(fTicketHolder.getTicket(), keys, name); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#removeAttribute(java.lang.String, int) - */ - public void removeAttribute(String path, int index) - { - fTransport.removeAttribute(fTicketHolder.getTicket(), path, index); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#removeAttribute(java.util.List, int) - */ - public void removeAttribute(List keys, int index) - { - fTransport.removeAttribute(fTicketHolder.getTicket(), keys, index); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#setAttribute(java.lang.String, java.lang.String, org.alfresco.repo.attributes.Attribute) - */ - public void setAttribute(String path, String name, Attribute value) - { - fTransport.setAttribute(fTicketHolder.getTicket(), path, name, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#setAttribute(java.util.List, java.lang.String, org.alfresco.repo.attributes.Attribute) - */ - public void setAttribute(List keys, String name, Attribute value) - { - fTransport.setAttribute(fTicketHolder.getTicket(), keys, name, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#setAttribute(java.lang.String, int, org.alfresco.repo.attributes.Attribute) - */ - public void setAttribute(String path, int index, Attribute value) - { - fTransport.setAttribute(fTicketHolder.getTicket(), path, index, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#setAttribute(java.util.List, int, org.alfresco.repo.attributes.Attribute) - */ - public void setAttribute(List keys, int index, Attribute value) - { - fTransport.setAttribute(fTicketHolder.getTicket(), keys, index, value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#exists(java.util.List) - */ - public boolean exists(List keys) - { - return fTransport.exists(fTicketHolder.getTicket(), keys); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#exists(java.lang.String) - */ - public boolean exists(String path) - { - return fTransport.exists(fTicketHolder.getTicket(), path); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#getCount(java.util.List) - */ - public int getCount(List keys) - { - return fTransport.getCount(fTicketHolder.getTicket(), keys); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#getCount(java.lang.String) - */ - public int getCount(String path) - { - return fTransport.getCount(fTicketHolder.getTicket(), path); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#addAttributes(java.util.List, java.util.List) - */ - public void addAttributes(List keys, List values) - { - fTransport.addAttributes(fTicketHolder.getTicket(), keys, values); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#addAttributes(java.lang.String, java.util.List) - */ - public void addAttributes(String path, List values) - { - fTransport.addAttributes(fTicketHolder.getTicket(), path, values); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#setAttributes(java.util.List, java.util.Map) - */ - public void setAttributes(List keys, Map entries) - { - fTransport.setAttributes(fTicketHolder.getTicket(), keys, entries); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#setAttributes(java.lang.String, java.util.Map) - */ - public void setAttributes(String path, Map entries) - { - fTransport.setAttributes(fTicketHolder.getTicket(), path, entries); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#removeEntries(java.util.List, org.alfresco.service.cmr.attributes.AttrQuery) - */ - public void removeEntries(List keys, AttrQuery query) - { - fTransport.removeEntries(fTicketHolder.getTicket(), keys, query); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttributeService#removeEntries(java.lang.String, org.alfresco.service.cmr.attributes.AttrQuery) - */ - public void removeEntries(String path, AttrQuery query) - { - fTransport.removeEntries(fTicketHolder.getTicket(), path, query); - } -} diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/CreateNodeRuleTrigger.java b/source/java/org/alfresco/repo/rule/ruletrigger/CreateNodeRuleTrigger.java index 35be108c85..2e5631f9ef 100644 --- a/source/java/org/alfresco/repo/rule/ruletrigger/CreateNodeRuleTrigger.java +++ b/source/java/org/alfresco/repo/rule/ruletrigger/CreateNodeRuleTrigger.java @@ -46,9 +46,6 @@ import org.apache.commons.logging.LogFactory; public class CreateNodeRuleTrigger extends RuleTriggerAbstractBase implements NodeServicePolicies.OnCreateNodePolicy { - /** - * The logger - */ private static Log logger = LogFactory.getLog(CreateNodeRuleTrigger.class); private static final String POLICY = "onCreateNode"; @@ -63,8 +60,6 @@ public class CreateNodeRuleTrigger extends RuleTriggerAbstractBase /** * Set whether this is a class behaviour or not - * - * @param isClassBehaviour */ public void setIsClassBehaviour(boolean isClassBehaviour) { @@ -73,8 +68,6 @@ public class CreateNodeRuleTrigger extends RuleTriggerAbstractBase /** * Set the rule service - * - * @param ruleService rule service */ public void setRuleService(RuntimeRuleService ruleService) { @@ -82,8 +75,8 @@ public class CreateNodeRuleTrigger extends RuleTriggerAbstractBase } /** - * @see org.alfresco.repo.rule.ruletrigger.RuleTrigger#registerRuleTrigger() - */ + * {@inheritDoc} + */ public void registerRuleTrigger() { if (isClassBehaviour == true) @@ -142,9 +135,6 @@ public class CreateNodeRuleTrigger extends RuleTriggerAbstractBase /** * On add aspect behaviour - * - * @param nodeRef - * @param aspectTypeQName */ public void onAddAspect(NodeRef nodeRef, QName aspectTypeQName) { @@ -165,9 +155,6 @@ public class CreateNodeRuleTrigger extends RuleTriggerAbstractBase /** * On remove aspect behaviour - * - * @param nodeRef - * @param aspectTypeQName */ public void onRemoveAspect(NodeRef nodeRef, QName aspectTypeQName) { diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/OnCreateChildAssociationRuleTrigger.java b/source/java/org/alfresco/repo/rule/ruletrigger/OnCreateChildAssociationRuleTrigger.java index 818d934dfc..2344831b1e 100644 --- a/source/java/org/alfresco/repo/rule/ruletrigger/OnCreateChildAssociationRuleTrigger.java +++ b/source/java/org/alfresco/repo/rule/ruletrigger/OnCreateChildAssociationRuleTrigger.java @@ -18,9 +18,11 @@ */ package org.alfresco.repo.rule.ruletrigger; +import java.util.Set; + import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.policy.JavaBehaviour; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.repo.transaction.TransactionalResourceHelper; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; @@ -93,14 +95,16 @@ public class OnCreateChildAssociationRuleTrigger // then we don't want to trigger any associated rules. // // See http://issues.alfresco.com/browse/AR-1544 - if (AlfrescoTransactionSupport.getResource(childAssocRef.getChildRef().toString()+"rename") == null) + Set nodeRefRenameSet = TransactionalResourceHelper.getSet(RULE_TRIGGER_NODESET); + String marker = childAssocRef.getChildRef().toString()+"rename"; + if (!nodeRefRenameSet.contains(marker)) { triggerRules(childAssocRef.getParentRef(), childAssocRef.getChildRef()); } else { // Remove the marker - AlfrescoTransactionSupport.unbindResource(childAssocRef.getChildRef().toString()+"rename"); + nodeRefRenameSet.remove(marker); } } } diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/OnPropertyUpdateRuleTrigger.java b/source/java/org/alfresco/repo/rule/ruletrigger/OnPropertyUpdateRuleTrigger.java index 276e61afd1..31042fcbc4 100644 --- a/source/java/org/alfresco/repo/rule/ruletrigger/OnPropertyUpdateRuleTrigger.java +++ b/source/java/org/alfresco/repo/rule/ruletrigger/OnPropertyUpdateRuleTrigger.java @@ -22,10 +22,11 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.policy.JavaBehaviour; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.repo.transaction.TransactionalResourceHelper; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.cmr.repository.ChildAssociationRef; @@ -128,10 +129,10 @@ public class OnPropertyUpdateRuleTrigger extends RuleTriggerAbstractBase logger.debug("OnPropertyUpdate rule triggered fired; nodeRef=" + nodeRef.toString() + "; triggerParentRules=" + this.triggerParentRules); } - Object createdNodeRef = AlfrescoTransactionSupport.getResource(nodeRef.toString()); + Set nodeRefSet = TransactionalResourceHelper.getSet(RULE_TRIGGER_NODESET); // Only try and trigger the rules if a non protected propety has been modified - if (createdNodeRef == null && havePropertiesBeenModified(nodeRef, before, after) == true) + if (!nodeRefSet.contains(nodeRef.toString()) && havePropertiesBeenModified(nodeRef, before, after) == true) { if (triggerParentRules == true) { diff --git a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTrigger.java b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTrigger.java index ad7a605b9c..a295b5e5df 100644 --- a/source/java/org/alfresco/repo/rule/ruletrigger/RuleTrigger.java +++ b/source/java/org/alfresco/repo/rule/ruletrigger/RuleTrigger.java @@ -27,6 +27,9 @@ import org.alfresco.service.cmr.rule.RuleType; */ public interface RuleTrigger { + /** Key to look up a Set of String values controlling the firing of rules */ + public static final String RULE_TRIGGER_NODESET = "RuleTrigger.NodeSet"; + /** * Register the rule trigger */ diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java index a7f0319354..d9add53798 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneIndexerImpl.java @@ -594,7 +594,7 @@ public class ADMLuceneIndexerImpl extends AbstractLuceneIndexerImpl imp List docs = new ArrayList(); ChildAssociationRef qNameRef = null; Map properties = nodeService.getProperties(nodeRef); - NodeRef.Status nodeStatus = nodeService.getNodeStatus(nodeRef); + NodeRef.Status nodeStatus = nodeService.getNodeStatus(nodeRef); // DH: Let me know if this field gets dropped (performance) Collection directPaths = new LinkedHashSet(nodeService.getPaths(nodeRef, false)); Collection> categoryPaths = getCategoryPaths(nodeRef, properties); diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java index cc98b8a53e..a4383c0e30 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java @@ -27,6 +27,7 @@ import java.io.ObjectOutputStream; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; @@ -205,7 +206,7 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener private Date testDate; - private NodeBulkLoader hibernateL1CacheBulkLoader; + private NodeBulkLoader nodeBulkLoader; private QueryEngine queryEngine; @@ -261,7 +262,7 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener tenantService = (TenantService) ctx.getBean("tenantService"); queryEngine = (QueryEngine) ctx.getBean("adm.luceneQueryEngineImpl"); - hibernateL1CacheBulkLoader = (NodeBulkLoader) ctx.getBean("nodeDaoServiceImpl"); + nodeBulkLoader = (NodeBulkLoader) ctx.getBean("nodeDAO"); serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); @@ -425,15 +426,22 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener MLText desc1 = new MLText(); desc1.addValue(Locale.ENGLISH, "Alfresco tutorial"); desc1.addValue(Locale.US, "Alfresco tutorial"); - + + Date explicitCreatedDate = new Date(); + Thread.sleep(2000); + properties.put(ContentModel.PROP_CONTENT, new ContentData(null, "text/plain", 0L, "UTF-8", Locale.UK)); properties.put(ContentModel.PROP_DESCRIPTION, desc1); - properties.put(ContentModel.PROP_CREATED, new Date()); - + properties.put(ContentModel.PROP_CREATED, explicitCreatedDate); + + // note: cm:content - hence auditable aspect will be applied with any missing mandatory properties (cm:modified, cm:creator, cm:modifier) n14 = nodeService.createNode(n13, ASSOC_TYPE_QNAME, QName.createQName("{namespace}fourteen"), ContentModel.TYPE_CONTENT, properties).getChildRef(); // nodeService.addAspect(n14, DictionaryBootstrap.ASPECT_QNAME_CONTENT, // properties); - + + assertEquals(explicitCreatedDate, nodeService.getProperty(n14, ContentModel.PROP_CREATED)); + + // note: cm:thumbnail - hence auditable aspect will be applied with mandatory properties (cm:created, cm:modified, cm:creator, cm:modifier) n15 = nodeService.createNode(n13, ASSOC_TYPE_QNAME, QName.createQName("{namespace}fifteen"), ContentModel.TYPE_THUMBNAIL, getOrderProperties()).getChildRef(); ContentWriter writer = contentService.getWriter(n14, ContentModel.PROP_CONTENT, true); @@ -458,13 +466,6 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener nodeService.addChild(n13, n14, ASSOC_TYPE_QNAME, QName.createQName("{namespace}common")); documentOrder = new NodeRef[] { rootNodeRef, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n3, n1, n2 }; - - // TODO: Why was the cm:auditable aspect added here? - // By adding it, the auditable properties were set automatically. - // nodeService.addAspect(n3, ContentModel.ASPECT_AUDITABLE, null); - // nodeService.addAspect(n1, ContentModel.ASPECT_AUDITABLE, null); - nodeService.setProperty(n1, ContentModel.PROP_MODIFIED, new Date(new Date().getTime() - 1000 * 60 * 60)); - // nodeService.addAspect(n2, ContentModel.ASPECT_AUDITABLE, null); } private double orderDoubleCount = -0.11d; @@ -1224,10 +1225,10 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener ftsQueryWithCount(searcher, "cm:content:brown", 1); ftsQueryWithCount(searcher, "ANDY:brown", 1); ftsQueryWithCount(searcher, "ANDY", "brown", 1); - - // test date ranges - ftsQueryWithCount(searcher, "modified:*", 2); - ftsQueryWithCount(searcher, "modified:[MIN TO NOW]", 2); + + // test date ranges - note: expected 2 results = n14 (cm:content) and n15 (cm:thumbnail) + ftsQueryWithCount(searcher, "modified:*", 2, Arrays.asList(new NodeRef[]{n14,n15})); + ftsQueryWithCount(searcher, "modified:[MIN TO NOW]", 2, Arrays.asList(new NodeRef[]{n14,n15})); } public void ftsQueryWithCount(ADMLuceneSearcherImpl searcher, String query, int count) @@ -1277,6 +1278,25 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener } results.close(); } + + public void ftsQueryWithCount(ADMLuceneSearcherImpl searcher, String query, int count, List expectedList) + { + ResultSet results = searcher.query(rootNodeRef.getStoreRef(), SearchService.LANGUAGE_FTS_ALFRESCO, query, null); + for (ResultSetRow row : results) + { + System.out.println("" + row.getScore() + nodeService.getProperty(row.getNodeRef(), ContentModel.PROP_NAME)); + } + assertEquals(count, results.length()); + + List actualList = results.getNodeRefs(); + + for (NodeRef expected : expectedList) + { + assertTrue("did not find "+expected, actualList.contains(expected)); + } + + results.close(); + } public void testOverWritetoZeroSize() throws Exception { @@ -1392,7 +1412,7 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener private void getCold(ADMLuceneSearcherImpl searcher, int n) { - hibernateL1CacheBulkLoader.clear(); + nodeBulkLoader.clear(); long start; @@ -1449,7 +1469,7 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener private void getCold10(ADMLuceneSearcherImpl searcher, int n) { - hibernateL1CacheBulkLoader.clear(); + nodeBulkLoader.clear(); long start; @@ -1478,7 +1498,7 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener private void getCold100(ADMLuceneSearcherImpl searcher, int n) { - hibernateL1CacheBulkLoader.clear(); + nodeBulkLoader.clear(); long start; @@ -1507,7 +1527,7 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener private void getCold1000(ADMLuceneSearcherImpl searcher, int n) { - hibernateL1CacheBulkLoader.clear(); + nodeBulkLoader.clear(); long start; @@ -1536,7 +1556,7 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener private void getCold10000(ADMLuceneSearcherImpl searcher, int n) { - hibernateL1CacheBulkLoader.clear(); + nodeBulkLoader.clear(); long start; @@ -3935,26 +3955,35 @@ public class ADMLuceneTest extends TestCase implements DictionaryListener // short and long field ranges + // note: expected 2 results = n14 (cm:content) and n15 (cm:thumbnail) + sDate = df.format(date); results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "\\@cm\\:CrEaTeD:[MIN TO " + sDate + "]", null); + assertTrue("n14 not in results", (results.getNodeRef(0).equals(n14) || results.getNodeRef(1).equals(n14))); + assertTrue("n15 not in results", (results.getNodeRef(0).equals(n15) || results.getNodeRef(1).equals(n15))); assertEquals(2, results.length()); results.close(); - + sDate = df.format(date); results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "\\@cm\\:created:[MIN TO NOW]", null); + assertTrue("n14 not in results", (results.getNodeRef(0).equals(n14) || results.getNodeRef(1).equals(n14))); + assertTrue("n15 not in results", (results.getNodeRef(0).equals(n15) || results.getNodeRef(1).equals(n15))); assertEquals(2, results.length()); results.close(); sDate = df.format(date); results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "\\@cm\\:created:[MIN TO TODAY]", null); - assertEquals(2, results.length()); - results.close(); - + assertTrue("n14 not in results", (results.getNodeRef(0).equals(n14) || results.getNodeRef(1).equals(n14))); + assertTrue("n15 not in results", (results.getNodeRef(0).equals(n15) || results.getNodeRef(1).equals(n15))); + assertEquals(2, results.length()); results.close(); + sDate = df.format(date); results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "\\@" + escapeQName(ContentModel.PROP_CREATED) + ":[MIN TO " + sDate + "]", null); + assertTrue("n14 not in results", (results.getNodeRef(0).equals(n14) || results.getNodeRef(1).equals(n14))); + assertTrue("n15 not in results", (results.getNodeRef(0).equals(n15) || results.getNodeRef(1).equals(n15))); assertEquals(2, results.length()); results.close(); - + // Date ranges // Test date collapses but date time does not diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationContext.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationContext.java index 8258904d8c..58c9ad8add 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationContext.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationContext.java @@ -18,8 +18,6 @@ */ package org.alfresco.repo.security.authentication; -import org.alfresco.service.Auditable; - import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.UserDetails; diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationContextImpl.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationContextImpl.java index 5e9bbfee9f..87298c9957 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationContextImpl.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationContextImpl.java @@ -26,7 +26,6 @@ import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; import net.sf.acegisecurity.providers.dao.User; import org.alfresco.repo.tenant.TenantService; -import org.alfresco.service.cmr.security.PermissionService; /** * @author Andy Hind diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java index 86605ff5c1..62c4cc2067 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationServiceImpl.java @@ -18,7 +18,6 @@ */ package org.alfresco.repo.security.authentication; -import java.lang.reflect.Method; import java.util.Collections; import java.util.Set; @@ -26,8 +25,6 @@ import org.alfresco.repo.audit.AuditComponent; import org.alfresco.repo.management.subsystems.ActivateableBean; import org.alfresco.repo.security.authentication.AuthenticationComponent.UserNameValidationMode; import org.alfresco.service.cmr.security.AuthenticationService; -import org.aopalliance.intercept.MethodInvocation; -import org.springframework.aop.framework.ReflectiveMethodInvocation; public class AuthenticationServiceImpl extends AbstractAuthenticationService implements ActivateableBean { diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java b/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java index a29b573207..a3ced88020 100644 --- a/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java +++ b/source/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java @@ -33,11 +33,11 @@ import java.util.regex.Pattern; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.domain.permissions.AclDAO; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.search.impl.lucene.LuceneQueryParser; -import org.alfresco.repo.security.permissions.impl.AclDaoComponent; import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.ChildAssociationRef; @@ -90,7 +90,7 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor /** System Container ref cache (Tennant aware) */ private Map systemContainerRefs = new ConcurrentHashMap(4); - private AclDaoComponent aclDao; + private AclDAO aclDao; private PolicyComponent policyComponent; @@ -148,7 +148,7 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor this.tenantService = tenantService; } - public void setAclDao(AclDaoComponent aclDao) + public void setAclDAO(AclDAO aclDao) { this.aclDao = aclDao; } @@ -900,8 +900,12 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor { if (isAuthority) { - // Fix any ACLs - aclDao.updateAuthority(authBefore, authAfter); + if (authBefore != null) + { + // Fix any ACLs + aclDao.renameAuthority(authBefore, authAfter); + } + // Fix primary association local name QName newAssocQName = QName.createQName("cm", authAfter, namespacePrefixResolver); diff --git a/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java b/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java index 689531aab8..d2451f421e 100644 --- a/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java +++ b/source/java/org/alfresco/repo/security/authority/AuthorityServiceTest.java @@ -31,10 +31,10 @@ import javax.transaction.UserTransaction; import junit.framework.TestCase; import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.permissions.AclDAO; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.MutableAuthenticationDao; -import org.alfresco.repo.security.permissions.impl.AclDaoComponent; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; @@ -69,7 +69,7 @@ public class AuthorityServiceTest extends TestCase private UserTransaction tx; - private AclDaoComponent aclDaoComponent; + private AclDAO aclDaoComponent; private NodeService nodeService; @@ -88,7 +88,7 @@ public class AuthorityServiceTest extends TestCase pubAuthorityService = (AuthorityService) ctx.getBean("AuthorityService"); personService = (PersonService) ctx.getBean("personService"); authenticationDAO = (MutableAuthenticationDao) ctx.getBean("authenticationDao"); - aclDaoComponent = (AclDaoComponent) ctx.getBean("aclDaoComponent"); + aclDaoComponent = (AclDAO) ctx.getBean("aclDAO"); nodeService = (NodeService) ctx.getBean("nodeService"); authenticationComponentImpl.setSystemUserAsCurrentUser(); diff --git a/source/java/org/alfresco/repo/security/permissions/AccessControlListProperties.java b/source/java/org/alfresco/repo/security/permissions/AccessControlListProperties.java index 90c22812f6..98a7aab6b2 100644 --- a/source/java/org/alfresco/repo/security/permissions/AccessControlListProperties.java +++ b/source/java/org/alfresco/repo/security/permissions/AccessControlListProperties.java @@ -18,7 +18,6 @@ */ package org.alfresco.repo.security.permissions; -import java.io.Serializable; /** * Properties for an access control list @@ -26,7 +25,7 @@ import java.io.Serializable; * @author andyh * */ -public interface AccessControlListProperties extends Serializable +public interface AccessControlListProperties { /** * Get the ACL ID diff --git a/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlListProperties.java b/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlListProperties.java index 52938967bc..8667dc47f3 100644 --- a/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlListProperties.java +++ b/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlListProperties.java @@ -26,12 +26,7 @@ package org.alfresco.repo.security.permissions; */ public class SimpleAccessControlListProperties implements AccessControlListProperties { - /** - * - */ - private static final long serialVersionUID = 6476760867405494520L; - - private String aclId; + private Long id; private ACLType aclType; @@ -43,38 +38,54 @@ public class SimpleAccessControlListProperties implements AccessControlListPrope private Boolean versioned; - private Long id; + private String aclId; + + // Default constructor + public SimpleAccessControlListProperties() + { + } + + public SimpleAccessControlListProperties(AccessControlListProperties props) + { + this.id = props.getId(); + this.aclType = props.getAclType(); + this.aclVersion = props.getAclVersion(); + this.inherits = props.getInherits(); + this.latest = props.isLatest(); + this.versioned = props.isVersioned(); + this.aclId = props.getAclId(); + } public String getAclId() { return aclId; } - + public ACLType getAclType() { return aclType; } - + public Long getAclVersion() { return aclVersion; } - + public Boolean getInherits() { return inherits; } - + public Boolean isLatest() { return latest; } - + public Boolean isVersioned() { return versioned; } - + /** * Set the acl id * @param aclId @@ -83,7 +94,7 @@ public class SimpleAccessControlListProperties implements AccessControlListPrope { this.aclId = aclId; } - + /** * Set the acl type * @param aclType @@ -92,7 +103,7 @@ public class SimpleAccessControlListProperties implements AccessControlListPrope { this.aclType = aclType; } - + /** * Set the acl version * @param aclVersion @@ -101,7 +112,7 @@ public class SimpleAccessControlListProperties implements AccessControlListPrope { this.aclVersion = aclVersion; } - + /** * Set inheritance * @param inherits @@ -110,7 +121,7 @@ public class SimpleAccessControlListProperties implements AccessControlListPrope { this.inherits = inherits; } - + /** * Set latest * @param latest @@ -119,7 +130,7 @@ public class SimpleAccessControlListProperties implements AccessControlListPrope { this.latest = latest; } - + /** * Set versioned * @param versioned @@ -128,12 +139,12 @@ public class SimpleAccessControlListProperties implements AccessControlListPrope { this.versioned = versioned; } - + public Long getId() { return id; } - + /** * Set the id * @param id @@ -142,7 +153,4 @@ public class SimpleAccessControlListProperties implements AccessControlListPrope { this.id = id; } - - - } diff --git a/source/java/org/alfresco/repo/security/permissions/impl/AbstractPermissionTest.java b/source/java/org/alfresco/repo/security/permissions/impl/AbstractPermissionTest.java index ace264a57f..848f71ec35 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/AbstractPermissionTest.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/AbstractPermissionTest.java @@ -28,6 +28,8 @@ import javax.transaction.UserTransaction; import junit.framework.TestCase; import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.node.NodeDAO; +import org.alfresco.repo.domain.permissions.AclDAO; import org.alfresco.repo.node.db.NodeDaoService; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; @@ -88,9 +90,9 @@ public class AbstractPermissionTest extends TestCase protected AuthorityDAO authorityDAO; - protected NodeDaoService nodeDaoService; + protected NodeDAO nodeDAO; - protected AclDaoComponent aclDaoComponent; + protected AclDAO aclDaoComponent; protected RetryingTransactionHelper retryingTransactionHelper; @@ -122,8 +124,8 @@ public class AbstractPermissionTest extends TestCase authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName()); authenticationDAO = (MutableAuthenticationDao) applicationContext.getBean("authenticationDao"); - nodeDaoService = (NodeDaoService) applicationContext.getBean("nodeDaoService"); - aclDaoComponent = (AclDaoComponent) applicationContext.getBean("aclDaoComponent"); + nodeDAO = (NodeDAO) applicationContext.getBean("nodeDAO"); + aclDaoComponent = (AclDAO) applicationContext.getBean("aclDAO"); retryingTransactionHelper = (RetryingTransactionHelper) applicationContext.getBean("retryingTransactionHelper"); diff --git a/source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponent.java b/source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponent.java deleted file mode 100644 index 481212420b..0000000000 --- a/source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponent.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.security.permissions.impl; - -import java.util.List; -import java.util.Set; - -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.hibernate.DirtySessionAnnotation; -import org.alfresco.repo.domain.hibernate.AclDaoComponentImpl.Indirection; -import org.alfresco.repo.security.permissions.ACLCopyMode; -import org.alfresco.repo.security.permissions.AccessControlEntry; -import org.alfresco.repo.security.permissions.AccessControlList; -import org.alfresco.repo.security.permissions.AccessControlListProperties; -import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties; -import org.alfresco.repo.transaction.TransactionalDao; - -/** - * DAO component for creating, deleting, manipulating and finding ACLs and associated ACEs and anc ACE context. - * - * @author andyh - */ -public interface AclDaoComponent extends TransactionalDao -{ - /** - * Temp support to get a DBAccessControlList to wire up ... - * - * @param id - * @return - */ - @DirtySessionAnnotation(markDirty=false) - DbAccessControlList getDbAccessControlList(Long id); - - - /** - * Get an ACL id. - * - * @param id - * @return - */ - @DirtySessionAnnotation(markDirty=false) - public AccessControlList getAccessControlList(Long id); - - /** - * Delete an ACL - * - * @param id - * @return - the id of all ACLs affected - */ - @DirtySessionAnnotation(markDirty=false) - public List deleteAccessControlList(Long id); - - /** - * Delete the ACEs in position 0 (those set directly on the ACL and not inherited) Cleans up existing acls - * - * @param id - * @return - the id of all ACLs affected - */ - @DirtySessionAnnotation(markDirty=false) - public List deleteLocalAccessControlEntries(Long id); - - /** - * Delete the ACEs in position > 0 (those not set directly on the ACL but inherited) No affect on any other acl - * - * @param id - * @return - the id of all ACLs affected - */ - @DirtySessionAnnotation(markDirty=false) - public List deleteInheritedAccessControlEntries(Long id); - - /** - * Mark all ACEs that reference this authority as no longer valid - the authority has been deleted - * - * @param authority - * @return - the id of all ACLs affected - */ - @DirtySessionAnnotation(markDirty=false) - public List invalidateAccessControlEntries(String authority); - - /** - * Delete all ACEs that reference this authority as no longer valid. THIS DOES NOT CAUSE ANY ACL TO VERSION - * - * @param authority - * @return - the id of all ACLs affected - */ - @DirtySessionAnnotation(markDirty=false) - public List deleteAccessControlEntries(String authority); - - /** - * Delete some locally set ACLs according to the pattern - * - * @param id - * @param pattern - - * non null elements are used for the match - * @return - the id of all ACLs affected - */ - @DirtySessionAnnotation(markDirty=false) - public List deleteAccessControlEntries(Long id, AccessControlEntry pattern); - - /** - * Add an access control entry - * - * @param id - * @param ace - * @return - the id of all ACLs affected - */ - @DirtySessionAnnotation(markDirty=false) - public List setAccessControlEntry(Long id, AccessControlEntry ace); - - /** - * Add an access control entry - * - * @param id - * @param ace - * @return - the id of all ACLs affected - */ - @DirtySessionAnnotation(markDirty=false) - public List setAccessControlEntries(Long id, List aces); - - /** - * Enable inheritance - * - * @param id - * @param parent - * @return - */ - @DirtySessionAnnotation(markDirty=false) - public List enableInheritance(Long id, Long parent); - - /** - * Disable inheritance - * - * @param id - * @param setInheritedOnAcl - * @return - */ - @DirtySessionAnnotation(markDirty=false) - public List disableInheritance(Long id, boolean setInheritedOnAcl); - - /** - * Get the ACL properties - * - * @param id - * @return - the id of all ACLs affected - */ - @DirtySessionAnnotation(markDirty=false) - public AccessControlListProperties getAccessControlListProperties(Long id); - - /** - * Create a new ACL with the given properties. Unset properties are assigned defaults. - * - * @param properties - * @return - */ - @DirtySessionAnnotation(markDirty=false) - public Long createAccessControlList(AccessControlListProperties properties); - - @DirtySessionAnnotation(markDirty=false) - public Long createAccessControlList(AccessControlListProperties properties, List aces, Long inherited); - - /** - * Get the id of the ACL inherited from the one given - * May return null if there is nothing to inherit -> OLD world where nodes have thier own ACL and we wlak the parent chain - * - * @param id - * @return - */ - @DirtySessionAnnotation(markDirty=false) - public Long getInheritedAccessControlList(Long id); - - /** - * Merge inherited ACEs in to target - the merged ACEs will go in at thier current position +1 - * - * @param inherited - * @param target - * @return - */ - @DirtySessionAnnotation(markDirty=false) - public List mergeInheritedAccessControlList(Long inherited, Long target); - - @DirtySessionAnnotation(markDirty=false) - public DbAccessControlList getDbAccessControlListCopy(Long toCopy, Long toInheritFrom, ACLCopyMode mode); - - @DirtySessionAnnotation(markDirty=false) - public Long getCopy(Long toCopy, Long toInheritFrom, ACLCopyMode mode); - - @DirtySessionAnnotation(markDirty=false) - public List getAvmNodesByACL(Long id); - - @DirtySessionAnnotation(markDirty=false) - public List getAvmIndirections(); - - /** - * hibernate lifecycle support - * @param id - */ - @DirtySessionAnnotation(markDirty=false) - public void onDeleteAccessControlList(final long id); - - @DirtySessionAnnotation(markDirty=false) - public void updateAuthority(String before, String after); - - @DirtySessionAnnotation(markDirty=false) - public void createAuthority(String authority); - - - /** - * @return - */ - @DirtySessionAnnotation(markDirty=false) - boolean supportsProgressTracking(); - - - /** - * @return - */ - @DirtySessionAnnotation(markDirty=false) - Long getDmNodeCount(); - - - /** - * @return - */ - @DirtySessionAnnotation(markDirty=false) - Long getMaxAclId(); - - - /** - * @param max - * @return - */ - @DirtySessionAnnotation(markDirty=false) - Long getDmNodeCountWithNewACLS(Long max); - - - /** - * @return - */ - @DirtySessionAnnotation(markDirty=false) - Long getNewInStore(); - - /** - * @return - */ - @DirtySessionAnnotation(markDirty=false) - SimpleAccessControlListProperties getDefaultProperties(); -} diff --git a/source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponentTest.java b/source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponentTest.java index 569ccea070..95c2fd578a 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponentTest.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponentTest.java @@ -31,6 +31,7 @@ import javax.transaction.UserTransaction; import junit.framework.TestCase; import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.permissions.AclDAO; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.MutableAuthenticationDao; @@ -59,7 +60,6 @@ import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.EqualsHelper; import org.springframework.context.ApplicationContext; -import org.springframework.orm.hibernate3.LocalSessionFactoryBean; public class AclDaoComponentTest extends TestCase { @@ -75,8 +75,6 @@ public class AclDaoComponentTest extends TestCase private MutableAuthenticationDao authenticationDAO; - protected LocalSessionFactoryBean sessionFactory; - protected NodeRef rootNodeRef; protected NamespacePrefixResolver namespacePrefixResolver; @@ -93,7 +91,7 @@ public class AclDaoComponentTest extends TestCase protected AuthorityService authorityService; - private AclDaoComponent aclDaoComponent; + private AclDAO aclDaoComponent; private UserTransaction testTX; @@ -107,7 +105,7 @@ public class AclDaoComponentTest extends TestCase public void setUp() throws Exception { - aclDaoComponent = (AclDaoComponent) applicationContext.getBean("aclDaoComponent"); + aclDaoComponent = (AclDAO) applicationContext.getBean("aclDAO"); nodeService = (NodeService) applicationContext.getBean("nodeService"); dictionaryService = (DictionaryService) applicationContext.getBean(ServiceRegistry.DICTIONARY_SERVICE @@ -200,7 +198,19 @@ public class AclDaoComponentTest extends TestCase { return permissionModelDAO.getPermissionReference(null, permission); } - + + public void testCreateDefault() + { + // Create default ACL (type=DEFINING, inherits=true, versioned=false) + Long id = aclDaoComponent.createAccessControlList(); + + AccessControlListProperties aclProps = aclDaoComponent.getAccessControlListProperties(id); + assertEquals(aclProps.getAclType(), ACLType.DEFINING); + assertEquals(aclProps.getAclVersion(), Long.valueOf(1l)); + assertEquals(aclProps.getInherits(), Boolean.TRUE); + assertEquals(aclProps.isVersioned(), Boolean.FALSE); + } + public void testCreateDefining() { SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); @@ -212,7 +222,6 @@ public class AclDaoComponentTest extends TestCase assertEquals(aclProps.getAclType(), ACLType.DEFINING); assertEquals(aclProps.getAclVersion(), Long.valueOf(1l)); assertEquals(aclProps.getInherits(), Boolean.TRUE); - } public void testCreateShared() @@ -293,7 +302,6 @@ public class AclDaoComponentTest extends TestCase ace1.setAccessStatus(AccessStatus.ALLOWED); ace1.setAceType(ACEType.ALL); ace1.setAuthority("andy"); - ace1.setContext(null); ace1.setPermission(new SimplePermissionReference(QName.createQName("uri", "local"), "Read")); ace1.setPosition(null); aclDaoComponent.setAccessControlEntry(id, ace1); @@ -324,7 +332,6 @@ public class AclDaoComponentTest extends TestCase ace2.setAccessStatus(AccessStatus.ALLOWED); ace2.setAceType(ACEType.ALL); ace2.setAuthority("paul"); - ace2.setContext(null); ace2.setPermission(new SimplePermissionReference(QName.createQName("uri", "local"), "Write")); ace2.setPosition(null); aclDaoComponent.setAccessControlEntry(id, ace2); @@ -372,7 +379,6 @@ public class AclDaoComponentTest extends TestCase ace1.setAccessStatus(AccessStatus.ALLOWED); ace1.setAceType(ACEType.ALL); ace1.setAuthority("andy"); - ace1.setContext(null); ace1.setPermission(new SimplePermissionReference(QName.createQName("uri", "local"), "Write")); ace1.setPosition(null); aclDaoComponent.setAccessControlEntry(def1, ace1); @@ -450,7 +456,6 @@ public class AclDaoComponentTest extends TestCase ace2.setAccessStatus(AccessStatus.ALLOWED); ace2.setAceType(ACEType.ALL); ace2.setAuthority("paul"); - ace2.setContext(null); ace2.setPermission(new SimplePermissionReference(QName.createQName("uri", "local"), "Write")); ace2.setPosition(null); aclDaoComponent.setAccessControlEntry(def4, ace2); @@ -497,7 +502,7 @@ public class AclDaoComponentTest extends TestCase assertEquals(aclDaoComponent.getAccessControlList(shared6_3).getEntries().size(), 2); assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_3).getEntries(), ace1, 11)); assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_3).getEntries(), ace2, 5)); - + aclDaoComponent.disableInheritance(def4, false); assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); @@ -1061,12 +1066,10 @@ public class AclDaoComponentTest extends TestCase properties.setVersioned(true); Long defined = aclDaoComponent.createAccessControlList(properties); - SimpleAccessControlEntry ace1 = new SimpleAccessControlEntry(); ace1.setAccessStatus(AccessStatus.ALLOWED); ace1.setAceType(ACEType.ALL); ace1.setAuthority("offski"); - ace1.setContext(null); ace1.setPermission(new SimplePermissionReference(QName.createQName("uri", "local"), "P1")); ace1.setPosition(null); @@ -1074,7 +1077,6 @@ public class AclDaoComponentTest extends TestCase ace2.setAccessStatus(AccessStatus.ALLOWED); ace2.setAceType(ACEType.ALL); ace2.setAuthority("offski"); - ace2.setContext(null); ace2.setPermission(new SimplePermissionReference(QName.createQName("uri", "local"), "P2")); ace2.setPosition(null); @@ -1082,7 +1084,6 @@ public class AclDaoComponentTest extends TestCase ace3.setAccessStatus(AccessStatus.ALLOWED); ace3.setAceType(ACEType.ALL); ace3.setAuthority("keepski"); - ace3.setContext(null); ace3.setPermission(new SimplePermissionReference(QName.createQName("uri", "local"), "P3")); ace3.setPosition(null); @@ -1162,7 +1163,6 @@ public class AclDaoComponentTest extends TestCase ace1.setAccessStatus(AccessStatus.ALLOWED); ace1.setAceType(ACEType.ALL); ace1.setAuthority("andy"); - ace1.setContext(null); ace1.setPermission(new SimplePermissionReference(QName.createQName("uri", "local"), "Read")); ace1.setPosition(null); List changes = aclDaoComponent.setAccessControlEntry(id, ace1); @@ -1229,7 +1229,6 @@ public class AclDaoComponentTest extends TestCase ace1.setAccessStatus(AccessStatus.ALLOWED); ace1.setAceType(ACEType.ALL); ace1.setAuthority("andy"); - ace1.setContext(null); ace1.setPermission(new SimplePermissionReference(QName.createQName("uri", "local"), "Read")); ace1.setPosition(null); List changes = aclDaoComponent.setAccessControlEntry(i_1, ace1); @@ -1280,6 +1279,7 @@ public class AclDaoComponentTest extends TestCase aclDaoComponent.mergeInheritedAccessControlList(s_1_2, i_1_2_4); Long i_1_2_4_5 = aclDaoComponent.createAccessControlList(properties); Long s_1_2_4_5 = aclDaoComponent.getInheritedAccessControlList(i_1_2_4_5); + assertNotNull(s_1_2_4_5); aclDaoComponent.mergeInheritedAccessControlList(s_1_2_4, i_1_2_4_5); Long i_1_3_6 = aclDaoComponent.createAccessControlList(properties); @@ -1298,7 +1298,6 @@ public class AclDaoComponentTest extends TestCase ace1.setAccessStatus(AccessStatus.ALLOWED); ace1.setAceType(ACEType.ALL); ace1.setAuthority("andy"); - ace1.setContext(null); ace1.setPermission(new SimplePermissionReference(QName.createQName("uri", "local"), "Read")); ace1.setPosition(null); List changes = aclDaoComponent.setAccessControlEntry(i_1_3, ace1); @@ -1347,7 +1346,6 @@ public class AclDaoComponentTest extends TestCase ace1.setAccessStatus(AccessStatus.ALLOWED); ace1.setAceType(ACEType.ALL); ace1.setAuthority("andy"); - ace1.setContext(null); ace1.setPermission(new SimplePermissionReference(QName.createQName("uri", "local"), "Read")); ace1.setPosition(null); List changes = aclDaoComponent.setAccessControlEntry(id, ace1); @@ -1382,7 +1380,6 @@ public class AclDaoComponentTest extends TestCase ace1.setAccessStatus(AccessStatus.ALLOWED); ace1.setAceType(ACEType.ALL); ace1.setAuthority("andy"); - ace1.setContext(null); ace1.setPermission(new SimplePermissionReference(QName.createQName("uri", "local"), "Read")); ace1.setPosition(null); @@ -1390,7 +1387,6 @@ public class AclDaoComponentTest extends TestCase ace2.setAccessStatus(AccessStatus.ALLOWED); ace2.setAceType(ACEType.ALL); ace2.setAuthority("andy"); - ace2.setContext(null); ace2.setPermission(new SimplePermissionReference(QName.createQName("uri", "local"), "Read")); ace2.setPosition(null); diff --git a/source/java/org/alfresco/repo/security/permissions/impl/ExceptionTranslatorMethodInterceptor.java b/source/java/org/alfresco/repo/security/permissions/impl/ExceptionTranslatorMethodInterceptor.java index 3fe8260ead..bee84c5b0a 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/ExceptionTranslatorMethodInterceptor.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/ExceptionTranslatorMethodInterceptor.java @@ -22,6 +22,7 @@ import org.alfresco.repo.security.permissions.AccessDeniedException; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.dao.TransientDataAccessResourceException; /** * Interceptor to translate and possibly I18Nize exceptions thrown by service calls. @@ -46,6 +47,11 @@ public class ExceptionTranslatorMethodInterceptor implements MethodInterceptor { throw new AccessDeniedException(MSG_ACCESS_DENIED, ade); } + catch (TransientDataAccessResourceException e) + { + // this usually occurs when the server is in read-only mode + throw new AccessDeniedException(MSG_READ_ONLY, e); + } catch (InvalidDataAccessApiUsageException e) { // this usually occurs when the server is in read-only mode 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 a532cc91cf..a08587983d 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java @@ -33,6 +33,7 @@ import org.alfresco.model.ContentModel; import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.avm.AVMRepository; import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.domain.permissions.AclDAO; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.security.authentication.AuthenticationUtil; @@ -123,7 +124,7 @@ public class PermissionServiceImpl extends AbstractLifecycleBean implements Perm private PolicyComponent policyComponent; - private AclDaoComponent aclDaoComponent; + private AclDAO aclDaoComponent; private PermissionReference allPermissionReference; @@ -212,7 +213,7 @@ public class PermissionServiceImpl extends AbstractLifecycleBean implements Perm * * @param aclDaoComponent */ - public void setAclDaoComponent(AclDaoComponent aclDaoComponent) + public void setAclDAO(AclDAO aclDaoComponent) { this.aclDaoComponent = aclDaoComponent; } 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 c36ab32fa7..e0c59e7556 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java @@ -67,41 +67,247 @@ public class PermissionServiceTest extends AbstractPermissionTest { runAs("admin"); NodeRef one = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); - permissionService.setPermission(one, "andy", PermissionService.CONTRIBUTOR, true); + permissionService.setPermission(one, "andy", PermissionService.READ, true); NodeRef two = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}two"), ContentModel.TYPE_FOLDER).getChildRef(); + permissionService.setPermission(two, "andy", PermissionService.WRITE, true); + NodeRef three = nodeService.createNode(one, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}two"), ContentModel.TYPE_FOLDER).getChildRef(); + + NodeRef test = nodeService.createNode(one, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test"), ContentModel.TYPE_FOLDER).getChildRef(); + // test has shared acl + + + // under 1 + // start runAs("andy"); assertEquals("andy", authenticationComponent.getCurrentUserName()); - assertTrue(permissionService.hasPermission(test, PermissionService.CONTRIBUTOR) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + //under 2 + // def parent -> def parent runAs("admin"); - permissionService.setInheritParentPermissions(test, false); - - runAs("andy"); - assertEquals("andy", authenticationComponent.getCurrentUserName()); - assertTrue(permissionService.hasPermission(test, PermissionService.CONTRIBUTOR) == AccessStatus.DENIED); - - runAs("admin"); - ChildAssociationRef newAssoc = nodeService.moveNode(test, two, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); - assertTrue(nodeService.exists(test)); - assertTrue(nodeService.exists(one)); - assertTrue(nodeService.exists(two)); - nodeDaoService.getNodePair(test); - nodeDaoService.getNodePair(one); - nodeDaoService.getNodePair(two); + nodeService.moveNode(test, two, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); assertEquals(two, nodeService.getPrimaryParent(test).getParentRef()); runAs("andy"); assertEquals("andy", authenticationComponent.getCurrentUserName()); - assertTrue(permissionService.hasPermission(test, PermissionService.CONTRIBUTOR) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.ALLOWED); + + // under 3 + // def parent -> shared parent + runAs("admin"); + nodeService.moveNode(test, three, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + assertEquals(three, nodeService.getPrimaryParent(test).getParentRef()); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + + //under 2 + // shared parent -> def parent + runAs("admin"); + nodeService.moveNode(test, two, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + assertEquals(two, nodeService.getPrimaryParent(test).getParentRef()); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.ALLOWED); + + //under 1 + // def parent -> def parent + runAs("admin"); + nodeService.moveNode(test, one, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + assertEquals(one, nodeService.getPrimaryParent(test).getParentRef()); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + + + // test has defining acl + + runAs("admin"); + permissionService.setPermission(test, "andy", PermissionService.CHANGE_PERMISSIONS, true); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + // 2 + runAs("admin"); + nodeService.moveNode(test, two, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + assertEquals(two, nodeService.getPrimaryParent(test).getParentRef()); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + // 3 + runAs("admin"); + nodeService.moveNode(test, three, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + assertEquals(three, nodeService.getPrimaryParent(test).getParentRef()); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + // 2 + runAs("admin"); + nodeService.moveNode(test, two, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + assertEquals(two, nodeService.getPrimaryParent(test).getParentRef()); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + // 1 + runAs("admin"); + nodeService.moveNode(test, one, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + assertEquals(one, nodeService.getPrimaryParent(test).getParentRef()); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + // 1 inherit runAs("admin"); permissionService.setInheritParentPermissions(test, true); runAs("andy"); assertEquals("andy", authenticationComponent.getCurrentUserName()); - assertTrue(permissionService.hasPermission(test, PermissionService.CONTRIBUTOR) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + runAs("admin"); + permissionService.setInheritParentPermissions(test, false); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + runAs("admin"); + permissionService.setInheritParentPermissions(test, true); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + // 2 inherit + + runAs("admin"); + nodeService.moveNode(test, two, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + assertEquals(two, nodeService.getPrimaryParent(test).getParentRef()); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + + runAs("admin"); + permissionService.setInheritParentPermissions(test, true); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + runAs("admin"); + permissionService.setInheritParentPermissions(test, false); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + runAs("admin"); + permissionService.setInheritParentPermissions(test, true); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + // 3 inherit + + runAs("admin"); + nodeService.moveNode(test, three, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + assertEquals(three, nodeService.getPrimaryParent(test).getParentRef()); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + runAs("admin"); + permissionService.setInheritParentPermissions(test, true); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.ALLOWED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + runAs("admin"); + permissionService.setInheritParentPermissions(test, false); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + // move to 2 without inherit + + runAs("admin"); + nodeService.moveNode(test, two, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + assertEquals(two, nodeService.getPrimaryParent(test).getParentRef()); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + + // move to 3 without inherit + + runAs("admin"); + nodeService.moveNode(test, three, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + assertEquals(three, nodeService.getPrimaryParent(test).getParentRef()); + + runAs("andy"); + assertEquals("andy", authenticationComponent.getCurrentUserName()); + assertTrue(permissionService.hasPermission(test, PermissionService.READ) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.WRITE) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(test, PermissionService.CHANGE_PERMISSIONS) == AccessStatus.ALLOWED); + } public void testChangePersonUid() @@ -891,7 +1097,15 @@ public class PermissionServiceTest extends AbstractPermissionTest 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"); + + assertTrue(permissionService.hasPermission(rootNodeRef, getPermission(PermissionService.READ)) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.READ)) == AccessStatus.DENIED); + assertTrue(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.DENIED); + + runAs(AuthenticationUtil.getAdminUserName()); + permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ), "andy", AccessStatus.ALLOWED)); runAs("andy"); @@ -945,7 +1159,7 @@ public class PermissionServiceTest extends AbstractPermissionTest @SuppressWarnings("unused") private void printPermissions(NodeRef nodeRef, String path) { - Long id = nodeDaoService.getNodePair(nodeRef).getFirst(); + Long id = nodeDAO.getNodePair(nodeRef).getFirst(); System.out.println(path + " has " + id); for (AccessControlEntry entry : aclDaoComponent.getAccessControlList(id).getEntries()) { @@ -2678,6 +2892,109 @@ public class PermissionServiceTest extends AbstractPermissionTest // assertEquals(1, permissionService.getAllSetPermissionsForAuthority("andy").get(n10).size()); } + + public void test_DefiningShared_AclUpdatePerformance() + { + runAs("admin"); + NodeRef one = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + permissionService.setPermission(one, "andy", PermissionService.READ, true); + NodeRef two = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}two"), ContentModel.TYPE_FOLDER).getChildRef(); + permissionService.setPermission(two, "andy", PermissionService.WRITE, true); + NodeRef test = nodeService.createNode(one, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test"), ContentModel.TYPE_FOLDER).getChildRef(); + + // test has shared acl + + + long start = System.nanoTime(); + for(int i = 0; i < 1000; i++) + { + nodeService.moveNode(test, two, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + nodeService.moveNode(test, one, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + } + long end = System.nanoTime(); + + //assertTrue("Time was "+(end - start)/1000000000.0f, end == start); + } + + + public void test_DefiningDefining_AclUpdatePerformance() + { + runAs("admin"); + NodeRef one = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + permissionService.setPermission(one, "andy", PermissionService.READ, true); + permissionService.setPermission(one, "bob", PermissionService.READ, true); + permissionService.setPermission(one, "cat", PermissionService.READ, true); + permissionService.setPermission(one, "dog", PermissionService.READ, true); + permissionService.setPermission(one, "emu", PermissionService.READ, true); + permissionService.setPermission(one, "fox", PermissionService.READ, true); + NodeRef two = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}two"), ContentModel.TYPE_FOLDER).getChildRef(); + permissionService.setPermission(two, "andy", PermissionService.WRITE, true); + NodeRef test = nodeService.createNode(one, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test"), ContentModel.TYPE_FOLDER).getChildRef(); + permissionService.setPermission(test, "andy", PermissionService.CHANGE_PERMISSIONS, true); + + // test has shared acl + + + long start = System.nanoTime(); + for(int i = 0; i < 1000; i++) + { + nodeService.moveNode(test, two, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + nodeService.moveNode(test, one, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}test")); + } + long end = System.nanoTime(); + + //assertTrue("Time was "+(end - start)/1000000000.0f, end == start); + + } + + + public void testAclInsertionPerformanceShared() + { + NodeRef parent = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + for(int i = 0; i < 10000; i++) + { + nodeService.createNode(parent, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}child"+i), ContentModel.TYPE_FOLDER).getChildRef(); + } + long start = System.nanoTime(); + permissionService.setPermission(new SimplePermissionEntry(parent, getPermission(PermissionService.CONSUMER), "andy", AccessStatus.ALLOWED)); + long end = System.nanoTime(); + + //assertTrue("Time was "+(end - start)/1000000000.0f, end == start); + } + + public void testAclInsertionPerformanceDefining() + { + NodeRef parent = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + for(int i = 0; i < 10000; i++) + { + NodeRef created = nodeService.createNode(parent, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}child"+i), ContentModel.TYPE_FOLDER).getChildRef(); + permissionService.setPermission(new SimplePermissionEntry(created, getPermission(PermissionService.CONSUMER), "bob", AccessStatus.ALLOWED)); + } + long start = System.nanoTime(); + permissionService.setPermission(new SimplePermissionEntry(parent, getPermission(PermissionService.CONSUMER), "andy", AccessStatus.ALLOWED)); + long end = System.nanoTime(); + + //assertTrue("Time was "+(end - start)/1000000000.0f, end == start); + } + + public void testAclInsertionPerformanceMixed() + { + NodeRef parent = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); + for(int i = 0; i < 10000; i++) + { + NodeRef created = nodeService.createNode(parent, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}child"+i), ContentModel.TYPE_FOLDER).getChildRef(); + if(i % 2 == 0) + { + permissionService.setPermission(new SimplePermissionEntry(created, getPermission(PermissionService.CONSUMER), "bob", AccessStatus.ALLOWED)); + } + } + long start = System.nanoTime(); + permissionService.setPermission(new SimplePermissionEntry(parent, getPermission(PermissionService.CONSUMER), "andy", AccessStatus.ALLOWED)); + long end = System.nanoTime(); + + //assertTrue("Time was "+(end - start)/1000000000.0f, end == start); + } + public void xtestFindNodesByPermission() { diff --git a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java index fbb0f1d842..202c36e6ac 100644 --- a/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java +++ b/source/java/org/alfresco/repo/security/person/PersonServiceImpl.java @@ -33,6 +33,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; import org.alfresco.repo.cache.SimpleCache; +import org.alfresco.repo.domain.permissions.AclDAO; import org.alfresco.repo.node.NodeServicePolicies; import org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy; import org.alfresco.repo.node.NodeServicePolicies.OnCreateNodePolicy; @@ -42,7 +43,6 @@ import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.security.authentication.AuthenticationException; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.permissions.PermissionServiceSPI; -import org.alfresco.repo.security.permissions.impl.AclDaoComponent; import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.TransactionListenerAdapter; @@ -129,9 +129,12 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per private boolean includeAutoCreated = false; - private AclDaoComponent aclDao; + private AclDAO aclDao; private PermissionsManager permissionsManager; + + // Behaviours + JavaBehaviour onUpdatePropertiesBehaviour; /** a transactionally-safe cache to be injected */ private SimpleCache> personCache; @@ -191,10 +194,13 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per BeforeDeleteNodePolicy.QNAME, ContentModel.TYPE_PERSON, new JavaBehaviour(this, "beforeDeleteNode")); + + onUpdatePropertiesBehaviour = new JavaBehaviour(this, "onUpdateProperties"); + this.policyComponent.bindClassBehaviour( OnUpdatePropertiesPolicy.QNAME, ContentModel.TYPE_PERSON, - new JavaBehaviour(this, "onUpdateProperties")); + onUpdatePropertiesBehaviour); } public UserNameMatcher getUserNameMatcher() @@ -237,7 +243,7 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per this.homeFolderManager = homeFolderManager; } - public void setAclDao(AclDaoComponent aclDao) + public void setAclDAO(AclDAO aclDao) { this.aclDao = aclDao; } @@ -448,32 +454,40 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per { // Get the duplicates in a form that can be read by the transaction work anonymous instance final Set postTxnDuplicates = getPostTxnDuplicates(); - + RetryingTransactionCallback processDuplicateWork = new RetryingTransactionCallback() { public Object execute() throws Throwable { - - if (duplicateMode.equalsIgnoreCase(SPLIT)) + try { - // Allow UIDs to be updated in this transaction - AlfrescoTransactionSupport.bindResource(KEY_ALLOW_UID_UPDATE, Boolean.TRUE); - split(postTxnDuplicates); - s_logger.info("Split duplicate person objects"); - } - else if (duplicateMode.equalsIgnoreCase(DELETE)) - { - delete(postTxnDuplicates); - s_logger.info("Deleted duplicate person objects"); - } - else - { - if (s_logger.isDebugEnabled()) + onUpdatePropertiesBehaviour.disable(); + + if (duplicateMode.equalsIgnoreCase(SPLIT)) { - s_logger.debug("Duplicate person objects exist"); + // Allow UIDs to be updated in this transaction + AlfrescoTransactionSupport.bindResource(KEY_ALLOW_UID_UPDATE, Boolean.TRUE); + split(postTxnDuplicates); + s_logger.info("Split duplicate person objects"); + } + else if (duplicateMode.equalsIgnoreCase(DELETE)) + { + delete(postTxnDuplicates); + s_logger.info("Deleted duplicate person objects"); + } + else + { + if (s_logger.isDebugEnabled()) + { + s_logger.debug("Duplicate person objects exist"); + } } } - + finally + { + onUpdatePropertiesBehaviour.enable(); + } + // Done return null; } @@ -684,8 +698,10 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per properties.put(ContentModel.PROP_USERNAME, userName); properties.put(ContentModel.PROP_SIZE_CURRENT, 0L); - NodeRef personRef = nodeService.createNode(getPeopleContainer(), ContentModel.ASSOC_CHILDREN, QName.createQName("cm", userName.toLowerCase(), namespacePrefixResolver), // Lowercase: - // ETHREEOH-1431 + NodeRef personRef = nodeService.createNode( + getPeopleContainer(), + ContentModel.ASSOC_CHILDREN, + QName.createQName("cm", userName.toLowerCase(), namespacePrefixResolver), // Lowercase: ContentModel.TYPE_PERSON, properties).getChildRef(); if (zones != null) @@ -1018,8 +1034,12 @@ public class PersonServiceImpl extends TransactionListenerAdapter implements Per // Only allow UID update if we are in the special split processing txn or we are just changing case if (AlfrescoTransactionSupport.getResource(KEY_ALLOW_UID_UPDATE) != null || uidBefore.equalsIgnoreCase(uidAfter)) { - // Fix any ACLs - aclDao.updateAuthority(uidBefore, uidAfter); + if (uidBefore != null) + { + // Fix any ACLs + aclDao.renameAuthority(uidBefore, uidAfter); + } + // Fix primary association local name QName newAssocQName = QName.createQName("cm", uidAfter.toLowerCase(), namespacePrefixResolver); diff --git a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java index 408bd5ac93..5bf58bb9b4 100644 --- a/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java +++ b/source/java/org/alfresco/repo/security/sync/ChainingUserRegistrySynchronizer.java @@ -36,9 +36,6 @@ import java.util.TreeMap; import java.util.TreeSet; import org.alfresco.model.ContentModel; -import org.alfresco.repo.attributes.Attribute; -import org.alfresco.repo.attributes.LongAttributeValue; -import org.alfresco.repo.attributes.MapAttributeValue; import org.alfresco.repo.batch.BatchProcessor; import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker; import org.alfresco.repo.lock.JobLockService; @@ -1321,13 +1318,13 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl return this.transactionService.getRetryingTransactionHelper().doInTransaction( new RetryingTransactionCallback() { - public Long execute() throws Throwable { - Attribute attribute = ChainingUserRegistrySynchronizer.this.attributeService - .getAttribute(ChainingUserRegistrySynchronizer.ROOT_ATTRIBUTE_PATH + '/' + label + '/' - + zoneId); - return attribute == null ? -1 : attribute.getLongValue(); + Long updateTime = (Long) attributeService.getAttribute( + ChainingUserRegistrySynchronizer.ROOT_ATTRIBUTE_PATH, + label, + zoneId); + return updateTime == null ? -1 : updateTime; } }, true, splitTxns); } @@ -1346,30 +1343,16 @@ public class ChainingUserRegistrySynchronizer extends AbstractLifecycleBean impl * true, the attribute is persisted in a new transaction for increased performance and * reliability. */ - private void setMostRecentUpdateTime(final String label, final String zoneId, final long lastModifiedMillis, - boolean splitTxns) + private void setMostRecentUpdateTime(final String label, final String zoneId, final long lastModifiedMillis, boolean splitTxns) { - final String path = ChainingUserRegistrySynchronizer.ROOT_ATTRIBUTE_PATH + '/' + label; this.transactionService.getRetryingTransactionHelper().doInTransaction( new RetryingTransactionHelper.RetryingTransactionCallback() { - public Object execute() throws Throwable { - if (!ChainingUserRegistrySynchronizer.this.attributeService.exists(path)) - { - if (!ChainingUserRegistrySynchronizer.this.attributeService - .exists(ChainingUserRegistrySynchronizer.ROOT_ATTRIBUTE_PATH)) - { - ChainingUserRegistrySynchronizer.this.attributeService.setAttribute("", - ChainingUserRegistrySynchronizer.ROOT_ATTRIBUTE_PATH, new MapAttributeValue()); - } - ChainingUserRegistrySynchronizer.this.attributeService.setAttribute( - ChainingUserRegistrySynchronizer.ROOT_ATTRIBUTE_PATH, label, - new MapAttributeValue()); - } - ChainingUserRegistrySynchronizer.this.attributeService.setAttribute(path, zoneId, - new LongAttributeValue(lastModifiedMillis)); + attributeService.setAttribute( + Long.valueOf(lastModifiedMillis), + ChainingUserRegistrySynchronizer.ROOT_ATTRIBUTE_PATH, label, zoneId); return null; } }, false, splitTxns); diff --git a/source/java/org/alfresco/repo/tagging/TaggingServiceImpl.java b/source/java/org/alfresco/repo/tagging/TaggingServiceImpl.java index 672d90daf6..e71b89d9f2 100644 --- a/source/java/org/alfresco/repo/tagging/TaggingServiceImpl.java +++ b/source/java/org/alfresco/repo/tagging/TaggingServiceImpl.java @@ -216,16 +216,34 @@ public class TaggingServiceImpl implements TaggingService, updateAllScopeTags(nodeRef, assocRef.getParentRef(), isAdd); } } + @SuppressWarnings("unchecked") private void updateAllScopeTags(NodeRef nodeRef, NodeRef parentNodeRef, Boolean isAdd) { if (parentNodeRef != null) { + Map> allQueuedUpdates = (Map>)AlfrescoTransactionSupport.getResource(TAG_UPDATES); + Map nodeQueuedUpdates = null; + if (allQueuedUpdates != null) + { + nodeQueuedUpdates = allQueuedUpdates.get(nodeRef); + } + List tags = getTags(nodeRef); Map tagUpdates = new HashMap(tags.size()); for (String tag : tags) { tagUpdates.put(tag, isAdd); - } + + if (nodeQueuedUpdates != null) + { + Boolean queuedOp = (Boolean)nodeQueuedUpdates.get(tag); + if ((queuedOp != null) && (queuedOp.booleanValue() == isAdd.booleanValue())) + { + // dequeue - will be handled synchronously + nodeQueuedUpdates.remove(tag); + } + } + } updateTagScope(parentNodeRef, tagUpdates, false); } } diff --git a/source/java/org/alfresco/repo/tagging/TaggingServiceImplTest.java b/source/java/org/alfresco/repo/tagging/TaggingServiceImplTest.java index afe6af5e9d..703e3d1609 100644 --- a/source/java/org/alfresco/repo/tagging/TaggingServiceImplTest.java +++ b/source/java/org/alfresco/repo/tagging/TaggingServiceImplTest.java @@ -26,7 +26,6 @@ import java.util.Map; import javax.transaction.UserTransaction; -import org.alfresco.cmis.mapping.CheckinCommentProperty; import org.alfresco.model.ContentModel; import org.alfresco.repo.action.AsynchronousActionExecutionQueuePolicies; import org.alfresco.repo.jscript.ClasspathScriptLocation; @@ -37,7 +36,6 @@ import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.service.cmr.action.Action; import org.alfresco.service.cmr.action.ActionService; import org.alfresco.service.cmr.coci.CheckOutCheckInService; -import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.CopyService; import org.alfresco.service.cmr.repository.NodeRef; @@ -99,7 +97,7 @@ public class TaggingServiceImplTest extends BaseAlfrescoSpringTest this.nodeService = (NodeService) this.applicationContext.getBean("NodeService"); this.copyService = (CopyService) this.applicationContext.getBean("CopyService"); this.contentService = (ContentService) this.applicationContext.getBean("ContentService"); - this.checkOutCheckInService = (CheckOutCheckInService) this.applicationContext.getBean("checkOutCheckInService"); + this.checkOutCheckInService = (CheckOutCheckInService) this.applicationContext.getBean("CheckoutCheckinService"); this.authenticationService = (MutableAuthenticationService) this.applicationContext.getBean("authenticationService"); this.actionService = (ActionService)this.applicationContext.getBean("ActionService"); this.transactionService = (TransactionService)this.applicationContext.getBean("transactionComponent"); @@ -543,7 +541,6 @@ public class TaggingServiceImplTest extends BaseAlfrescoSpringTest NodeRef tagBar = taggingService.createTag(folder.getStoreRef(), "Bar"); List tagsList = new ArrayList(); - List children; // Create two containers marked as tag scopes @@ -644,10 +641,7 @@ public class TaggingServiceImplTest extends BaseAlfrescoSpringTest // Check out the node // Tags should be doubled up. (We don't care about ContentModel.ASPECT_WORKING_COPY // because it isn't applied at suitable times to take not of) - UserTransaction tx = this.transactionService.getUserTransaction(); - tx.begin(); NodeRef checkedOutDoc = checkOutCheckInService.checkout(taggedDoc); - tx.commit(); waitForActionExecution(); assertEquals(3, taggingService.findTagScope(container1).getTags().size()); @@ -663,10 +657,7 @@ public class TaggingServiceImplTest extends BaseAlfrescoSpringTest // And check it back in again // Tags should go back to how they were - tx = this.transactionService.getUserTransaction(); - tx.begin(); checkOutCheckInService.checkin(checkedOutDoc, null); - tx.commit(); waitForActionExecution(); assertEquals(3, taggingService.findTagScope(container1).getTags().size()); diff --git a/source/java/org/alfresco/repo/template/AVMTemplateNode.java b/source/java/org/alfresco/repo/template/AVMTemplateNode.java index e3222ed6d3..9a1a20b280 100644 --- a/source/java/org/alfresco/repo/template/AVMTemplateNode.java +++ b/source/java/org/alfresco/repo/template/AVMTemplateNode.java @@ -29,12 +29,12 @@ import java.util.Set; import org.alfresco.model.WCMModel; import org.alfresco.repo.avm.AVMNodeConverter; -import org.alfresco.repo.avm.util.AVMUtil; import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.audit.AuditInfo; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.cmr.avm.locking.AVMLock; +import org.alfresco.service.cmr.avm.locking.AVMLockingService.LockState; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; @@ -47,9 +47,9 @@ import org.alfresco.service.namespace.NamespacePrefixResolverProvider; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QNameMap; import org.alfresco.util.Pair; -import org.springframework.extensions.surf.util.URLEncoder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.URLEncoder; import org.xml.sax.InputSource; import freemarker.ext.dom.NodeModel; @@ -66,12 +66,11 @@ import freemarker.ext.dom.NodeModel; * * @author Kevin Roast */ +@SuppressWarnings("serial") public class AVMTemplateNode extends BasePermissionsNode implements NamespacePrefixResolverProvider { private static Log logger = LogFactory.getLog(AVMTemplateNode.class); - private final static String NAMESPACE_BEGIN = "" + QName.NAMESPACE_BEGIN; - /** Cached values */ private NodeRef nodeRef; private String name; @@ -273,9 +272,10 @@ public class AVMTemplateNode extends BasePermissionsNode implements NamespacePre */ public boolean getIsLocked() { - AVMLock lock = this.services.getAVMLockingService().getLock( - getWebProject(), path.substring(path.indexOf("/"))); - return (lock != null); + String currentUser = AuthenticationUtil.getFullyAuthenticatedUser(); + LockState lockStatus = this.services.getAVMLockingService().getLockState( + getWebProject(), path.substring(path.indexOf("/")), currentUser); + return lockStatus != LockState.NO_LOCK; } /** @@ -283,17 +283,10 @@ public class AVMTemplateNode extends BasePermissionsNode implements NamespacePre */ public boolean getIsLockOwner() { - boolean lockOwner = false; - - AVMLock lock = this.services.getAVMLockingService().getLock( - getWebProject(), path.substring(path.indexOf("/"))); - if (lock != null) - { - List lockUsers = lock.getOwners(); - lockOwner = (lockUsers.contains(this.services.getAuthenticationService().getCurrentUserName())); - } - - return lockOwner; + String currentUser = AuthenticationUtil.getFullyAuthenticatedUser(); + LockState lockStatus = this.services.getAVMLockingService().getLockState( + getWebProject(), path.substring(path.indexOf("/")), currentUser); + return lockStatus == LockState.LOCK_OWNER; } /** @@ -369,6 +362,7 @@ public class AVMTemplateNode extends BasePermissionsNode implements NamespacePre /** * @see org.alfresco.repo.template.TemplateProperties#getProperties() */ + @SuppressWarnings("unchecked") public Map getProperties() { if (!this.propsRetrieved) diff --git a/source/java/org/alfresco/repo/tenant/MultiTAdminServiceImpl.java b/source/java/org/alfresco/repo/tenant/MultiTAdminServiceImpl.java index e778040aac..0a095a86f2 100644 --- a/source/java/org/alfresco/repo/tenant/MultiTAdminServiceImpl.java +++ b/source/java/org/alfresco/repo/tenant/MultiTAdminServiceImpl.java @@ -20,11 +20,14 @@ package org.alfresco.repo.tenant; import java.io.File; import java.io.PrintWriter; +import java.io.Serializable; import java.io.StringWriter; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Properties; -import java.util.Set; import java.util.regex.Pattern; import javax.transaction.UserTransaction; @@ -32,12 +35,7 @@ import javax.transaction.UserTransaction; import net.sf.acegisecurity.providers.encoding.PasswordEncoder; import org.alfresco.error.AlfrescoRuntimeException; -import org.springframework.extensions.surf.util.I18NUtil; import org.alfresco.repo.admin.RepoModelDefinition; -import org.alfresco.repo.attributes.BooleanAttributeValue; -import org.alfresco.repo.attributes.MapAttribute; -import org.alfresco.repo.attributes.MapAttributeValue; -import org.alfresco.repo.attributes.StringAttributeValue; import org.alfresco.repo.content.TenantRoutingFileContentStore; import org.alfresco.repo.dictionary.DictionaryComponent; import org.alfresco.repo.importer.ImporterBootstrap; @@ -50,6 +48,7 @@ import org.alfresco.repo.usage.UserUsageTrackingComponent; import org.alfresco.repo.workflow.WorkflowDeployer; import org.alfresco.service.cmr.admin.RepoAdminService; import org.alfresco.service.cmr.attributes.AttributeService; +import org.alfresco.service.cmr.attributes.AttributeService.AttributeQueryCallback; import org.alfresco.service.cmr.module.ModuleService; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; @@ -57,7 +56,7 @@ import org.alfresco.service.cmr.view.RepositoryExporterService; import org.alfresco.service.cmr.workflow.WorkflowDefinition; import org.alfresco.service.cmr.workflow.WorkflowService; import org.alfresco.service.transaction.TransactionService; -import org.springframework.extensions.surf.util.ParameterCheck; +import org.alfresco.util.EqualsHelper; import org.alfresco.util.PropertyCheck; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -65,6 +64,8 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.extensions.surf.util.I18NUtil; +import org.springframework.extensions.surf.util.ParameterCheck; /** * MT Admin Service Implementation. @@ -219,7 +220,7 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo private static final String TENANTS_ATTRIBUTE_PATH = "alfresco-tenants"; private static final String TENANT_ATTRIBUTE_ENABLED = "enabled"; - private static final String TENANT_ROOT_CONTENT_STORE_DIR = "rootContentStoreDir"; + private static final String TENANT_ATTRIBUTE_ROOT_CONTENT_STORE_DIR = "rootContentStoreDir"; private List tenantDeployers = new ArrayList(); @@ -476,36 +477,35 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo private void putTenantAttributes(String tenantDomain, Tenant tenant) { - if (! attributeService.exists(TENANTS_ATTRIBUTE_PATH)) - { - // bootstrap - attributeService.setAttribute("", TENANTS_ATTRIBUTE_PATH, new MapAttributeValue()); - } + Map tenantAttributes = new HashMap(7); + tenantAttributes.put(TENANT_ATTRIBUTE_ENABLED, new Boolean(tenant.isEnabled())); + tenantAttributes.put(TENANT_ATTRIBUTE_ROOT_CONTENT_STORE_DIR, tenant.getRootContentStoreDir()); - MapAttribute tenantProps = new MapAttributeValue(); - tenantProps.put(TENANT_ATTRIBUTE_ENABLED, new BooleanAttributeValue(tenant.isEnabled())); - tenantProps.put(TENANT_ROOT_CONTENT_STORE_DIR, new StringAttributeValue(tenant.getRootContentStoreDir())); - - attributeService.setAttribute(TENANTS_ATTRIBUTE_PATH, tenantDomain, tenantProps); + attributeService.setAttribute( + (Serializable) tenantAttributes, + TENANTS_ATTRIBUTE_PATH, tenantDomain); // update tenant status cache ((MultiTServiceImpl)tenantService).putTenant(tenantDomain, tenant); } + @SuppressWarnings("unchecked") private Tenant getTenantAttributes(String tenantDomain) { - if (attributeService.exists(TENANTS_ATTRIBUTE_PATH+"/"+tenantDomain)) - { - MapAttribute map = (MapAttribute)attributeService.getAttribute(TENANTS_ATTRIBUTE_PATH+"/"+tenantDomain); - if (map != null) - { - return new Tenant(tenantDomain, - map.get(TENANT_ATTRIBUTE_ENABLED).getBooleanValue(), - map.get(TENANT_ROOT_CONTENT_STORE_DIR).getStringValue()); - } + Map tenantAttributes = (Map) attributeService.getAttribute( + TENANTS_ATTRIBUTE_PATH, + tenantDomain); + if (tenantAttributes == null) + { + return null; + } + else + { + Boolean enabled = (Boolean) tenantAttributes.get(TENANT_ATTRIBUTE_ENABLED); + String storeDir = (String) tenantAttributes.get(TENANT_ATTRIBUTE_ROOT_CONTENT_STORE_DIR); + Tenant tenant = new Tenant(tenantDomain, enabled.booleanValue(), storeDir); + return tenant; } - - return null; } public void enableTenant(String tenantDomain) @@ -724,23 +724,33 @@ public class MultiTAdminServiceImpl implements TenantAdminService, ApplicationCo */ public List getAllTenants() { - MapAttribute map = (MapAttribute)attributeService.getAttribute(TENANTS_ATTRIBUTE_PATH); + final List tenants = new ArrayList(); - List tenants = new ArrayList(); - - if (map != null) + AttributeQueryCallback callback = new AttributeQueryCallback() { - // note: getAllTenants is called first, by TenantDeployer - hence need to initialise the TenantService status cache - Set tenantDomains = map.keySet(); - - for (String tenantDomain : tenantDomains) - { - Tenant tenant = getTenantAttributes(tenantDomain); - tenants.add(new Tenant(tenantDomain, tenant.isEnabled(), tenant.getRootContentStoreDir())); - } - } - - return tenants; // list of tenants or empty list + @SuppressWarnings("unchecked") + public boolean handleAttribute(Long id, Serializable value, Serializable[] keys) + { + if (keys.length != 3 || !EqualsHelper.nullSafeEquals(keys[0], TENANTS_ATTRIBUTE_PATH) || keys[1] == null) + { + logger.warn("Unexpected tenant attribute: \n" + + " id: " + id + "\n" + + " keys: " + Arrays.toString(keys) + "\n" + + " value: " + value); + return true; + } + String tenantDomain = (String) keys[1]; + Map tenantAttributes = (Map) value; + Boolean enabled = (Boolean) tenantAttributes.get(TENANT_ATTRIBUTE_ENABLED); + String storeDir = (String) tenantAttributes.get(TENANT_ATTRIBUTE_ROOT_CONTENT_STORE_DIR); + Tenant tenant = new Tenant(tenantDomain, enabled.booleanValue(), storeDir); + tenants.add(tenant); + // Continue + return true; + } + }; + attributeService.getAttributes(callback, TENANTS_ATTRIBUTE_PATH); + return tenants; } private void importBootstrapSystemTenantStore(String tenantDomain, File directorySource) diff --git a/source/java/org/alfresco/repo/transaction/CheckTransactionAdvice.java b/source/java/org/alfresco/repo/transaction/CheckTransactionAdvice.java index ff1c727160..4fd40f51a6 100644 --- a/source/java/org/alfresco/repo/transaction/CheckTransactionAdvice.java +++ b/source/java/org/alfresco/repo/transaction/CheckTransactionAdvice.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,35 +14,36 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.transaction; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; - -/** - * A wrapper that checks that a transaction is present. - * - * @author Derek Hulley - * @since 2.2.1 - */ -public class CheckTransactionAdvice implements MethodInterceptor -{ - public CheckTransactionAdvice() - { - } - public Object invoke(final MethodInvocation methodInvocation) throws Throwable - { - // Just check for any transaction - if (AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_NONE) - { - String methodName = methodInvocation.getMethod().getName(); - String className = methodInvocation.getMethod().getDeclaringClass().getName(); - throw new AlfrescoRuntimeException("A transaction has not be started for method " + methodName + " on " + className); - } - return methodInvocation.proceed(); - } -} + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.transaction; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +/** + * A wrapper that checks that a transaction is present. + * + * @author Derek Hulley + * @since 2.2.1 + */ +public class CheckTransactionAdvice implements MethodInterceptor +{ + public CheckTransactionAdvice() + { + } + public Object invoke(final MethodInvocation methodInvocation) throws Throwable + { + // Just check for any transaction + if (AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_NONE) + { + String methodName = methodInvocation.getMethod().getName(); + String className = methodInvocation.getMethod().getDeclaringClass().getName(); + throw new AlfrescoRuntimeException( + "A transaction has not be started for method '" + methodName + "' on " + className); + } + return methodInvocation.proceed(); + } +} diff --git a/source/java/org/alfresco/repo/transaction/TransactionAwareSingleton.java b/source/java/org/alfresco/repo/transaction/TransactionAwareSingleton.java index 7e0c2f916b..947c249998 100644 --- a/source/java/org/alfresco/repo/transaction/TransactionAwareSingleton.java +++ b/source/java/org/alfresco/repo/transaction/TransactionAwareSingleton.java @@ -22,6 +22,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; +import org.alfresco.util.GUID; + /** * A transactionally-safe storage class for singleton objects. Changes to the singleton * are only visibly promoted when the transaction is committed. @@ -40,14 +42,14 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; */ public class TransactionAwareSingleton extends TransactionListenerAdapter { - private static final String TRANSACTION_KEY = "TransactionAwareSingleton.storage"; - + private final String txnKey; private final ReadLock singletonReadLock; private final WriteLock singletonWriteLock; private Object singletonValue; public TransactionAwareSingleton() { + txnKey = GUID.generate(); ReentrantReadWriteLock serverReadWriteLock = new ReentrantReadWriteLock(); singletonReadLock = serverReadWriteLock.readLock(); singletonWriteLock = serverReadWriteLock.writeLock(); @@ -88,7 +90,7 @@ public class TransactionAwareSingleton extends TransactionListenerAdapter public T get() { // an in-transaction value overrides the singleton - TransactionStorage storage = (TransactionStorage) AlfrescoTransactionSupport.getResource(TRANSACTION_KEY); + TransactionStorage storage = (TransactionStorage) AlfrescoTransactionSupport.getResource(txnKey); if (storage != null) { return (T) storage.newValue; @@ -109,12 +111,12 @@ public class TransactionAwareSingleton extends TransactionListenerAdapter public void put(T value) { // the value is changing - TransactionStorage storage = (TransactionStorage) AlfrescoTransactionSupport.getResource(TRANSACTION_KEY); + TransactionStorage storage = (TransactionStorage) AlfrescoTransactionSupport.getResource(txnKey); if (storage == null) { // it has not changed before storage = new TransactionStorage(); - AlfrescoTransactionSupport.bindResource(TRANSACTION_KEY, storage); + AlfrescoTransactionSupport.bindResource(txnKey, storage); // listen to the transaction AlfrescoTransactionSupport.bindListener(this); } @@ -126,7 +128,7 @@ public class TransactionAwareSingleton extends TransactionListenerAdapter */ public void afterCommit() { - TransactionStorage storage = (TransactionStorage) AlfrescoTransactionSupport.getResource(TRANSACTION_KEY); + TransactionStorage storage = (TransactionStorage) AlfrescoTransactionSupport.getResource(txnKey); if (storage != null) { // the value was overridden diff --git a/source/java/org/alfresco/repo/transaction/TransactionServiceImplTest.java b/source/java/org/alfresco/repo/transaction/TransactionServiceImplTest.java index fa6b7da929..988342af91 100644 --- a/source/java/org/alfresco/repo/transaction/TransactionServiceImplTest.java +++ b/source/java/org/alfresco/repo/transaction/TransactionServiceImplTest.java @@ -33,6 +33,7 @@ import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.util.ApplicationContextHelper; import org.springframework.context.ApplicationContext; import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.dao.TransientDataAccessResourceException; import org.springframework.transaction.PlatformTransactionManager; /** @@ -137,7 +138,13 @@ public class TransactionServiceImplTest extends TestCase { @SuppressWarnings("unused") int i = 0; - // expected + // expected this ... + } + catch (TransientDataAccessResourceException e) + { + @SuppressWarnings("unused") + int i = 0; + // or this } finally { diff --git a/source/java/org/alfresco/repo/transfer/AbstractNodeFilter.java b/source/java/org/alfresco/repo/transfer/AbstractNodeFilter.java index de1ff44a8f..0a0336cc24 100644 --- a/source/java/org/alfresco/repo/transfer/AbstractNodeFilter.java +++ b/source/java/org/alfresco/repo/transfer/AbstractNodeFilter.java @@ -31,7 +31,7 @@ import org.springframework.extensions.surf.util.ParameterCheck; * injected into them and their init operations invoked at the appropriate time. * * @author Brian - * @since 3.3 + * @since 3.4 */ public abstract class AbstractNodeFilter implements NodeFilter { diff --git a/source/java/org/alfresco/repo/transfer/manifest/package-info.java b/source/java/org/alfresco/repo/transfer/manifest/package-info.java index 119be1b6a0..9b433fc2e9 100644 --- a/source/java/org/alfresco/repo/transfer/manifest/package-info.java +++ b/source/java/org/alfresco/repo/transfer/manifest/package-info.java @@ -3,6 +3,6 @@ *

* XMLTransferManifestWriter writes the transfer manifest. XMLTransferManifestReader reads the transfer manifest and calls the * TransferManifestProcessor as the read progresses. These classes are designed to stream content through, processing each node at a time, and not hold a large data objects in memory. - * @since 3.3 + * @since 3.4 */ package org.alfresco.repo.transfer.manifest; diff --git a/source/java/org/alfresco/repo/usage/ContentUsageImpl.java b/source/java/org/alfresco/repo/usage/ContentUsageImpl.java index 177334f7e8..2c99882e19 100644 --- a/source/java/org/alfresco/repo/usage/ContentUsageImpl.java +++ b/source/java/org/alfresco/repo/usage/ContentUsageImpl.java @@ -1,599 +1,600 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.usage; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.node.NodeServicePolicies; -import org.alfresco.repo.policy.JavaBehaviour; -import org.alfresco.repo.policy.PolicyComponent; -import org.alfresco.repo.security.authentication.AuthenticationContext; -import org.alfresco.repo.tenant.TenantService; -import org.alfresco.repo.transaction.AlfrescoTransactionSupport; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -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.OwnableService; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.cmr.usage.ContentQuotaException; -import org.alfresco.service.cmr.usage.ContentUsageService; -import org.alfresco.service.cmr.usage.UsageService; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.springframework.extensions.surf.util.ParameterCheck; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Implements Content Usage service and policies/behaviour. - * - */ -public class ContentUsageImpl implements ContentUsageService, - NodeServicePolicies.OnUpdatePropertiesPolicy, - NodeServicePolicies.BeforeDeleteNodePolicy, - NodeServicePolicies.OnAddAspectPolicy, - NodeServicePolicies.OnCreateNodePolicy -{ - // Logger - private static Log logger = LogFactory.getLog(ContentUsageImpl.class); - - /** Key to the deleted nodes */ - private static final String KEY_DELETED_NODES = "contentUsage.deletedNodes"; - - /** Key to the created nodes */ - private static final String KEY_CREATED_NODES = "contentUsage.createdNodes"; - - private NodeService nodeService; - private PersonService personService; - private PolicyComponent policyComponent; - private UsageService usageService; - private AuthenticationContext authenticationContext; - private TenantService tenantService; - - private boolean enabled = true; - - private List stores; - - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - public void setPersonService(PersonService personService) - { - this.personService = personService; - } - - public void setUsageService(UsageService usageService) - { - this.usageService = usageService; - } - - public void setPolicyComponent(PolicyComponent policyComponent) - { - this.policyComponent = policyComponent; - } - - public void setAuthenticationContext(AuthenticationContext authenticationContext) - { - this.authenticationContext = authenticationContext; - } - - public void setTenantService(TenantService tenantService) - { - this.tenantService = tenantService; - } - - public void setEnabled(boolean enabled) - { - this.enabled = enabled; - } - - public void setStores(List stores) - { - this.stores = stores; - } - - public List getStores() - { - return this.stores; - } - - /** - * The initialise method - */ - public void init() - { - if (enabled) - { - // Register interest in the onUpdateProperties policy - for content - policyComponent.bindClassBehaviour( - QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"), - ContentModel.TYPE_CONTENT, - new JavaBehaviour(this, "onUpdateProperties")); - - // Register interest in the beforeDeleteNode policy - for content - policyComponent.bindClassBehaviour( - QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"), - ContentModel.TYPE_CONTENT, - new JavaBehaviour(this, "beforeDeleteNode")); - - // Register interest in the onCreateNode policy - for content - policyComponent.bindClassBehaviour( - QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"), - ContentModel.TYPE_CONTENT, - new JavaBehaviour(this, "onCreateNode")); - - // Register interest in the onAddAspect policy - for ownable - policyComponent.bindClassBehaviour( - QName.createQName(NamespaceService.ALFRESCO_URI, "onAddAspect"), - ContentModel.ASPECT_OWNABLE, - new JavaBehaviour(this, "onAddAspect")); - } - } - - @SuppressWarnings("unchecked") - private void recordDelete(NodeRef nodeRef) - { - Set deletedNodes = (Set)AlfrescoTransactionSupport.getResource(KEY_DELETED_NODES); - if (deletedNodes == null) - { - deletedNodes = new HashSet(); - AlfrescoTransactionSupport.bindResource(KEY_DELETED_NODES, deletedNodes); - } - deletedNodes.add(tenantService.getName(nodeRef)); - - Set updatedNodes = (Set)AlfrescoTransactionSupport.getResource(KEY_CREATED_NODES); - if (updatedNodes != null) - { - updatedNodes.remove(tenantService.getName(nodeRef)); - } - } - - @SuppressWarnings("unchecked") - private boolean alreadyDeleted(NodeRef nodeRef) - { - Set deletedNodes = (Set)AlfrescoTransactionSupport.getResource(KEY_DELETED_NODES); - if (deletedNodes != null) - { - for (NodeRef deletedNodeRef : deletedNodes) - { - if (deletedNodeRef.equals(nodeRef)) - { - if (logger.isDebugEnabled()) logger.debug("alreadyDeleted: nodeRef="+nodeRef); - return true; - } - } - } - return false; - } - - public void onCreateNode(ChildAssociationRef childAssocRef) - { - NodeRef nodeRef = childAssocRef.getChildRef(); - if (stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString()) && (! alreadyCreated(nodeRef))) - { - // TODO use data dictionary to get content property - ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); - - if (contentData != null) - { - long contentSize = contentData.getSize(); - - // Get owner/creator - String owner = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_OWNER); - if ((owner == null) || (owner.equals(OwnableService.NO_OWNER))) - { - owner = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_CREATOR); - } - - if (contentSize != 0 && owner != null) - { - // increment usage if node is being created - if (logger.isDebugEnabled()) logger.debug("onCreateNode: nodeRef="+nodeRef+", owner="+owner+", contentSize="+contentSize); - incrementUserUsage(owner, contentSize, nodeRef); - recordCreate(nodeRef); - } - } - } - } - - @SuppressWarnings("unchecked") - private void recordCreate(NodeRef nodeRef) - { - Set createdNodes = (Set)AlfrescoTransactionSupport.getResource(KEY_CREATED_NODES); - if (createdNodes == null) - { - createdNodes = new HashSet(); - AlfrescoTransactionSupport.bindResource(KEY_CREATED_NODES, createdNodes); - } - createdNodes.add(tenantService.getName(nodeRef)); - } - - @SuppressWarnings("unchecked") - private boolean alreadyCreated(NodeRef nodeRef) - { - Set createdNodes = (Set)AlfrescoTransactionSupport.getResource(KEY_CREATED_NODES); - if (createdNodes != null) - { - for (NodeRef createdNodeRef : createdNodes) - { - if (createdNodeRef.equals(nodeRef)) - { - if (logger.isDebugEnabled()) logger.debug("alreadyCreated: nodeRef="+nodeRef); - return true; - } - } - } - return false; - } - - /** - * Called after a node's properties have been changed. - * - * @param nodeRef reference to the updated node - * @param before the node's properties before the change - * @param after the node's properties after the change - */ - public void onUpdateProperties( - NodeRef nodeRef, - Map before, - Map after) - { - if (stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString()) && (! alreadyCreated(nodeRef))) - { - // Check for change in content size - - // TODO use data dictionary to get content property - ContentData contentDataBefore = (ContentData)before.get(ContentModel.PROP_CONTENT); - Long contentSizeBefore = (contentDataBefore == null ? null : contentDataBefore.getSize()); - ContentData contentDataAfter = (ContentData)after.get(ContentModel.PROP_CONTENT); - Long contentSizeAfter = (contentDataAfter == null ? null : contentDataAfter.getSize()); - - // Check for change in owner/creator - String ownerBefore = (String)before.get(ContentModel.PROP_OWNER); - if ((ownerBefore == null) || (ownerBefore.equals(OwnableService.NO_OWNER))) - { - ownerBefore = (String)before.get(ContentModel.PROP_CREATOR); - } - String ownerAfter = (String)after.get(ContentModel.PROP_OWNER); - if ((ownerAfter == null) || (ownerAfter.equals(OwnableService.NO_OWNER))) - { - ownerAfter = (String)after.get(ContentModel.PROP_CREATOR); - } - - // check change in size (and possibly owner) - if (contentSizeBefore == null && contentSizeAfter != null && contentSizeAfter != 0 && ownerAfter != null) - { - // new size has been added - note: ownerBefore does not matter since the contentSizeBefore is null - if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateSize (null -> "+contentSizeAfter+"): nodeRef="+nodeRef+", ownerAfter="+ownerAfter); - incrementUserUsage(ownerAfter, contentSizeAfter, nodeRef); - } - else if (contentSizeAfter == null && contentSizeBefore != null && contentSizeBefore != 0 && ownerBefore != null) - { - // old size has been removed - note: ownerAfter does not matter since contentSizeAfter is null - if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateSize ("+contentSizeBefore+" -> null): nodeRef="+nodeRef+", ownerBefore="+ownerBefore); - decrementUserUsage(ownerBefore, contentSizeBefore, nodeRef); - } - else if (contentSizeBefore != null && contentSizeAfter != null) - { - if (contentSizeBefore.equals(contentSizeAfter) == false) - { - // size has changed (and possibly owner) - if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateSize ("+contentSizeBefore+" -> "+contentSizeAfter+"): nodeRef="+nodeRef+", ownerBefore="+ownerBefore+", ownerAfter="+ownerAfter); - - if (contentSizeBefore != 0 && ownerBefore != null) - { - decrementUserUsage(ownerBefore, contentSizeBefore, nodeRef); - } - if (contentSizeAfter != 0 && ownerAfter != null) - { - incrementUserUsage(ownerAfter, contentSizeAfter, nodeRef); - } - } - else - { - // same size - check change in owner only - if (ownerBefore == null && ownerAfter != null && contentSizeAfter != 0 && ownerAfter != null) - { - // new owner has been added - if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateOwner (null -> "+ownerAfter+"): nodeRef="+nodeRef+", contentSize="+contentSizeAfter); - incrementUserUsage(ownerAfter, contentSizeAfter, nodeRef); - } - else if (ownerAfter == null && ownerBefore != null && contentSizeBefore != 0) - { - // old owner has been removed - if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateOwner ("+ownerBefore+" -> null): nodeRef="+nodeRef+", contentSize="+contentSizeBefore); - decrementUserUsage(ownerBefore, contentSizeBefore, nodeRef); - } - else if (ownerBefore != null && ownerAfter != null && ownerBefore.equals(ownerAfter) == false) - { - // owner has changed (size has not) - if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateOwner ("+ownerBefore+" -> "+ownerAfter+"): nodeRef="+nodeRef+", contentSize="+contentSizeBefore); - - if (contentSizeBefore != 0) - { - decrementUserUsage(ownerBefore, contentSizeBefore, nodeRef); - } - if (contentSizeAfter != 0) - { - incrementUserUsage(ownerAfter, contentSizeAfter, nodeRef); - } - } - } - } - } - } - - /** - * Called before a node is deleted. - * - * @param nodeRef the node reference - */ - public void beforeDeleteNode(NodeRef nodeRef) - { - if (stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString()) && (! alreadyDeleted(nodeRef))) - { - // TODO use data dictionary to get content property - ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); - - if (contentData != null) - { - long contentSize = contentData.getSize(); - - // Get owner/creator - String owner = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_OWNER); - if ((owner == null) || (owner.equals(OwnableService.NO_OWNER))) - { - owner = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_CREATOR); - } - - if (contentSize != 0 && owner != null) - { - // decrement usage if node is being deleted - if (logger.isDebugEnabled()) logger.debug("beforeDeleteNode: nodeRef="+nodeRef+", owner="+owner+", contentSize="+contentSize); - decrementUserUsage(owner, contentSize, nodeRef); - recordDelete(nodeRef); - } - } - } - } - - /** - * Called after an cm:ownable aspect has been added to a node - * - * @param nodeRef the node to which the aspect was added - * @param aspectTypeQName the type of the aspect - */ - public void onAddAspect(NodeRef nodeRef, QName aspectTypeQName) - { - if ((stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString())) && - (aspectTypeQName.equals(ContentModel.ASPECT_OWNABLE))) - { - String newOwner = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_OWNER); - String creator = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_CREATOR); - - if ((newOwner != null) && (! newOwner.equals(creator))) - { - if (newOwner.equals(OwnableService.NO_OWNER)) - { - // usage has to be applied somewhere, default back to creator for now - newOwner = creator; - } - - ContentData content = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); - - Map before = new HashMap(2); - Map after = new HashMap(2); - - after.put(ContentModel.PROP_OWNER, newOwner); - after.put(ContentModel.PROP_CONTENT, content); - - before.put(ContentModel.PROP_CREATOR, creator); - before.put(ContentModel.PROP_CONTENT, content); - - onUpdateProperties(nodeRef, before, after); - } - } - } - - private void incrementUserUsage(String userName, long contentSize, NodeRef contentNodeRef) - { - if (! authenticationContext.isSystemUserName(userName)) - { - // increment usage - add positive delta - if (logger.isDebugEnabled()) logger.debug("incrementUserUsage: username="+userName+", contentSize="+contentSize+", contentNodeRef="+contentNodeRef); - - long currentSize = getUserUsage(userName); - long quotaSize = getUserQuota(userName); - - long newSize = currentSize + contentSize; - - // check whether user's quota exceeded - if ((quotaSize != -1) && (newSize > quotaSize)) - { - if (logger.isWarnEnabled()) - { - logger.warn("User (" + userName + ") quota exceeded: content=" + contentSize + - ", usage=" + currentSize + - ", quota=" + quotaSize); - } - throw new ContentQuotaException("User quota exceeded"); - } - - NodeRef personNodeRef = getPerson(userName); - if (personNodeRef != null) - { - usageService.insertDelta(personNodeRef, contentSize); - } - } - } - - private void decrementUserUsage(String userName, long contentSize, NodeRef contentNodeRef) - { - if (! authenticationContext.isSystemUserName(userName)) - { - // decrement usage - add negative delta - if (logger.isDebugEnabled()) logger.debug("decrementUserUsage: username="+userName+", contentSize="+contentSize+", contentNodeRef="+contentNodeRef); - - long currentSize = getUserUsage(userName); - - long newSize = currentSize + contentSize; - - if (newSize < 0) - { - if (logger.isDebugEnabled()) - { - logger.debug("User (" + userName + ") has negative usage (" + newSize + ") - reset to 0"); - } - } - - NodeRef personNodeRef = getPerson(userName); - if (personNodeRef != null) - { - usageService.insertDelta(personNodeRef, (-contentSize)); - } - } - } - - /** - * Set user's usage. Should only be called by background (collapse) job ! - * - * @param userName - * @param currentUsage - */ - public void setUserStoredUsage(NodeRef personNodeRef, long currentUsage) - { - if (personNodeRef != null) - { - nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, new Long(currentUsage)); - } - } - - public long getUserStoredUsage(NodeRef personNodeRef) - { - Long currentUsage = null; - if (personNodeRef != null) - { - currentUsage = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT); - } - - return (currentUsage == null ? -1 : currentUsage); - } - - public long getUserUsage(String userName) { - return getUserUsage(userName, false); - } - - public long getUserUsage(String userName, boolean removeDeltas) - { - ParameterCheck.mandatoryString("userName", userName); - - long currentUsage = -1; - - NodeRef personNodeRef = getPerson(userName); - if (personNodeRef != null) - { - currentUsage = getUserStoredUsage(personNodeRef); - } - - if (currentUsage != -1) - { - long deltaSize = removeDeltas ? usageService.getAndRemoveTotalDeltaSize(personNodeRef) : - usageService.getTotalDeltaSize(personNodeRef); - // add any deltas to the currentUsage, removing them if required - currentUsage = currentUsage + deltaSize; - - if (currentUsage < 0) - { - if (logger.isWarnEnabled()) - { - logger.warn("User usage ("+ userName+") is negative ("+currentUsage+") overriding to 0"); - } - currentUsage = 0; - } - } - - return currentUsage; - } - - /** - * Set user's current quota. - * Usually called by Web Client (Admin Console) if admin is changing/setting a user's quota. - * - * @param userName - * @param currentQuota - */ - public void setUserQuota(String userName, long currentQuota) - { - NodeRef personNodeRef = getPerson(userName); - if (personNodeRef != null) - { - nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_QUOTA, new Long(currentQuota)); - } - } - - public long getUserQuota(String userName) - { - Long currentQuota = null; - - NodeRef personNodeRef = getPerson(userName); - if (personNodeRef != null) - { - currentQuota = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_QUOTA); - } - - return (currentQuota == null ? -1 : currentQuota); - } - - public boolean getEnabled() - { - return enabled; - } - - private NodeRef getPerson(String userName) - { - NodeRef personNodeRef = null; - try - { - personNodeRef = personService.getPerson(userName); - } - catch (RuntimeException e) - { - // workaround for ETHREEOH-1457 where existing tenants (created using 3.0.1) may have been bootstrapped with creator set - // to super admin (eg. "admin") rather than "System@xxx". This workaround should remain until we patch any such existing tenants - if (tenantService.isEnabled()) - { - personNodeRef = null; - } - else - { - throw e; - } - } - return personNodeRef; - } -} +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.usage; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.node.NodeServicePolicies; +import org.alfresco.repo.policy.JavaBehaviour; +import org.alfresco.repo.policy.PolicyComponent; +import org.alfresco.repo.security.authentication.AuthenticationContext; +import org.alfresco.repo.tenant.TenantService; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +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.OwnableService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.usage.ContentQuotaException; +import org.alfresco.service.cmr.usage.ContentUsageService; +import org.alfresco.service.cmr.usage.UsageService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.ParameterCheck; + +/** + * Implements Content Usage service and policies/behaviour. + * + */ +public class ContentUsageImpl implements ContentUsageService, + NodeServicePolicies.OnUpdatePropertiesPolicy, + NodeServicePolicies.BeforeDeleteNodePolicy, + //NodeServicePolicies.OnAddAspectPolicy, + NodeServicePolicies.OnCreateNodePolicy +{ + // Logger + private static Log logger = LogFactory.getLog(ContentUsageImpl.class); + + /** Key to the deleted nodes */ + private static final String KEY_DELETED_NODES = "contentUsage.deletedNodes"; + + /** Key to the created nodes */ + private static final String KEY_CREATED_NODES = "contentUsage.createdNodes"; + + private NodeService nodeService; + private PersonService personService; + private PolicyComponent policyComponent; + private UsageService usageService; + private AuthenticationContext authenticationContext; + private TenantService tenantService; + + private boolean enabled = true; + + private List stores; + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + public void setPersonService(PersonService personService) + { + this.personService = personService; + } + + public void setUsageService(UsageService usageService) + { + this.usageService = usageService; + } + + public void setPolicyComponent(PolicyComponent policyComponent) + { + this.policyComponent = policyComponent; + } + + public void setAuthenticationContext(AuthenticationContext authenticationContext) + { + this.authenticationContext = authenticationContext; + } + + public void setTenantService(TenantService tenantService) + { + this.tenantService = tenantService; + } + + public void setEnabled(boolean enabled) + { + this.enabled = enabled; + } + + public void setStores(List stores) + { + this.stores = stores; + } + + public List getStores() + { + return this.stores; + } + + /** + * The initialise method + */ + public void init() + { + if (enabled) + { + // Register interest in the onUpdateProperties policy - for content + policyComponent.bindClassBehaviour( + QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateProperties"), + ContentModel.TYPE_CONTENT, + new JavaBehaviour(this, "onUpdateProperties")); + + // Register interest in the beforeDeleteNode policy - for content + policyComponent.bindClassBehaviour( + QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"), + ContentModel.TYPE_CONTENT, + new JavaBehaviour(this, "beforeDeleteNode")); + + // Register interest in the onCreateNode policy - for content + policyComponent.bindClassBehaviour( + QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"), + ContentModel.TYPE_CONTENT, + new JavaBehaviour(this, "onCreateNode")); + + /* + // Register interest in the onAddAspect policy - for ownable + policyComponent.bindClassBehaviour( + QName.createQName(NamespaceService.ALFRESCO_URI, "onAddAspect"), + ContentModel.ASPECT_OWNABLE, + new JavaBehaviour(this, "onAddAspect")); + */ + } + } + + @SuppressWarnings("unchecked") + private void recordDelete(NodeRef nodeRef) + { + Set deletedNodes = (Set)AlfrescoTransactionSupport.getResource(KEY_DELETED_NODES); + if (deletedNodes == null) + { + deletedNodes = new HashSet(); + AlfrescoTransactionSupport.bindResource(KEY_DELETED_NODES, deletedNodes); + } + deletedNodes.add(tenantService.getName(nodeRef)); + + Set updatedNodes = (Set)AlfrescoTransactionSupport.getResource(KEY_CREATED_NODES); + if (updatedNodes != null) + { + updatedNodes.remove(tenantService.getName(nodeRef)); + } + } + + @SuppressWarnings("unchecked") + private boolean alreadyDeleted(NodeRef nodeRef) + { + Set deletedNodes = (Set)AlfrescoTransactionSupport.getResource(KEY_DELETED_NODES); + if (deletedNodes != null) + { + for (NodeRef deletedNodeRef : deletedNodes) + { + if (deletedNodeRef.equals(nodeRef)) + { + if (logger.isDebugEnabled()) logger.debug("alreadyDeleted: nodeRef="+nodeRef); + return true; + } + } + } + return false; + } + + public void onCreateNode(ChildAssociationRef childAssocRef) + { + NodeRef nodeRef = childAssocRef.getChildRef(); + if (stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString()) && (! alreadyCreated(nodeRef))) + { + // TODO use data dictionary to get content property + ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); + + if (contentData != null) + { + long contentSize = contentData.getSize(); + + // Get owner/creator + String owner = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_OWNER); + if ((owner == null) || (owner.equals(OwnableService.NO_OWNER))) + { + owner = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_CREATOR); + } + + if (contentSize != 0 && owner != null) + { + // increment usage if node is being created + if (logger.isDebugEnabled()) logger.debug("onCreateNode: nodeRef="+nodeRef+", owner="+owner+", contentSize="+contentSize); + incrementUserUsage(owner, contentSize, nodeRef); + recordCreate(nodeRef); + } + } + } + } + + + @SuppressWarnings("unchecked") + private void recordCreate(NodeRef nodeRef) + { + Set createdNodes = (Set)AlfrescoTransactionSupport.getResource(KEY_CREATED_NODES); + if (createdNodes == null) + { + createdNodes = new HashSet(); + AlfrescoTransactionSupport.bindResource(KEY_CREATED_NODES, createdNodes); + } + createdNodes.add(tenantService.getName(nodeRef)); + } + + @SuppressWarnings("unchecked") + private boolean alreadyCreated(NodeRef nodeRef) + { + Set createdNodes = (Set)AlfrescoTransactionSupport.getResource(KEY_CREATED_NODES); + if (createdNodes != null) + { + for (NodeRef createdNodeRef : createdNodes) + { + if (createdNodeRef.equals(nodeRef)) + { + if (logger.isDebugEnabled()) logger.debug("alreadyCreated: nodeRef="+nodeRef); + return true; + } + } + } + return false; + } + + /** + * Called after a node's properties have been changed. + * + * @param nodeRef reference to the updated node + * @param before the node's properties before the change + * @param after the node's properties after the change + */ + public void onUpdateProperties( + NodeRef nodeRef, + Map before, + Map after) + { + if (stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString()) && (! alreadyCreated(nodeRef))) + { + // Check for change in content size + + // TODO use data dictionary to get content property + ContentData contentDataBefore = (ContentData)before.get(ContentModel.PROP_CONTENT); + Long contentSizeBefore = (contentDataBefore == null ? null : contentDataBefore.getSize()); + ContentData contentDataAfter = (ContentData)after.get(ContentModel.PROP_CONTENT); + Long contentSizeAfter = (contentDataAfter == null ? null : contentDataAfter.getSize()); + + // Check for change in owner/creator + String ownerBefore = (String)before.get(ContentModel.PROP_OWNER); + if ((ownerBefore == null) || (ownerBefore.equals(OwnableService.NO_OWNER))) + { + ownerBefore = (String)before.get(ContentModel.PROP_CREATOR); + } + String ownerAfter = (String)after.get(ContentModel.PROP_OWNER); + if ((ownerAfter == null) || (ownerAfter.equals(OwnableService.NO_OWNER))) + { + ownerAfter = (String)after.get(ContentModel.PROP_CREATOR); + } + + // check change in size (and possibly owner) + if (contentSizeBefore == null && contentSizeAfter != null && contentSizeAfter != 0 && ownerAfter != null) + { + // new size has been added - note: ownerBefore does not matter since the contentSizeBefore is null + if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateSize (null -> "+contentSizeAfter+"): nodeRef="+nodeRef+", ownerAfter="+ownerAfter); + incrementUserUsage(ownerAfter, contentSizeAfter, nodeRef); + } + else if (contentSizeAfter == null && contentSizeBefore != null && contentSizeBefore != 0 && ownerBefore != null) + { + // old size has been removed - note: ownerAfter does not matter since contentSizeAfter is null + if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateSize ("+contentSizeBefore+" -> null): nodeRef="+nodeRef+", ownerBefore="+ownerBefore); + decrementUserUsage(ownerBefore, contentSizeBefore, nodeRef); + } + else if (contentSizeBefore != null && contentSizeAfter != null) + { + if (contentSizeBefore.equals(contentSizeAfter) == false) + { + // size has changed (and possibly owner) + if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateSize ("+contentSizeBefore+" -> "+contentSizeAfter+"): nodeRef="+nodeRef+", ownerBefore="+ownerBefore+", ownerAfter="+ownerAfter); + + if (contentSizeBefore != 0 && ownerBefore != null) + { + decrementUserUsage(ownerBefore, contentSizeBefore, nodeRef); + } + if (contentSizeAfter != 0 && ownerAfter != null) + { + incrementUserUsage(ownerAfter, contentSizeAfter, nodeRef); + } + } + else + { + // same size - check change in owner only + if (ownerBefore == null && ownerAfter != null && contentSizeAfter != 0 && ownerAfter != null) + { + // new owner has been added + if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateOwner (null -> "+ownerAfter+"): nodeRef="+nodeRef+", contentSize="+contentSizeAfter); + incrementUserUsage(ownerAfter, contentSizeAfter, nodeRef); + } + else if (ownerAfter == null && ownerBefore != null && contentSizeBefore != 0) + { + // old owner has been removed + if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateOwner ("+ownerBefore+" -> null): nodeRef="+nodeRef+", contentSize="+contentSizeBefore); + decrementUserUsage(ownerBefore, contentSizeBefore, nodeRef); + } + else if (ownerBefore != null && ownerAfter != null && ownerBefore.equals(ownerAfter) == false) + { + // owner has changed (size has not) + if (logger.isDebugEnabled()) logger.debug("onUpdateProperties: updateOwner ("+ownerBefore+" -> "+ownerAfter+"): nodeRef="+nodeRef+", contentSize="+contentSizeBefore); + + if (contentSizeBefore != 0) + { + decrementUserUsage(ownerBefore, contentSizeBefore, nodeRef); + } + if (contentSizeAfter != 0) + { + incrementUserUsage(ownerAfter, contentSizeAfter, nodeRef); + } + } + } + } + } + } + + /** + * Called before a node is deleted. + * + * @param nodeRef the node reference + */ + public void beforeDeleteNode(NodeRef nodeRef) + { + if (stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString()) && (! alreadyDeleted(nodeRef))) + { + // TODO use data dictionary to get content property + ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); + + if (contentData != null) + { + long contentSize = contentData.getSize(); + + // Get owner/creator + String owner = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_OWNER); + if ((owner == null) || (owner.equals(OwnableService.NO_OWNER))) + { + owner = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_CREATOR); + } + + if (contentSize != 0 && owner != null) + { + // decrement usage if node is being deleted + if (logger.isDebugEnabled()) logger.debug("beforeDeleteNode: nodeRef="+nodeRef+", owner="+owner+", contentSize="+contentSize); + decrementUserUsage(owner, contentSize, nodeRef); + recordDelete(nodeRef); + } + } + } + } + + /** + * Called after an cm:ownable aspect has been added to a node + * + * @param nodeRef the node to which the aspect was added + * @param aspectTypeQName the type of the aspect + */ + /* NOTE: now handled via onUpdateProperties as expected + public void onAddAspect(NodeRef nodeRef, QName aspectTypeQName) + { + if ((stores.contains(tenantService.getBaseName(nodeRef.getStoreRef()).toString())) && + (aspectTypeQName.equals(ContentModel.ASPECT_OWNABLE))) + { + String newOwner = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_OWNER); + String creator = (String)nodeService.getProperty(nodeRef, ContentModel.PROP_CREATOR); + + if ((newOwner != null) && (! newOwner.equals(creator))) + { + if (newOwner.equals(OwnableService.NO_OWNER)) + { + // usage has to be applied somewhere, default back to creator for now + newOwner = creator; + } + + ContentData content = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT); + + Map before = new HashMap(2); + Map after = new HashMap(2); + + after.put(ContentModel.PROP_OWNER, newOwner); + after.put(ContentModel.PROP_CONTENT, content); + + before.put(ContentModel.PROP_CREATOR, creator); + before.put(ContentModel.PROP_CONTENT, content); + + onUpdateProperties(nodeRef, before, after); + } + } + } + */ + + private void incrementUserUsage(String userName, long contentSize, NodeRef contentNodeRef) + { + if (! authenticationContext.isSystemUserName(userName)) + { + // increment usage - add positive delta + if (logger.isDebugEnabled()) logger.debug("incrementUserUsage: username="+userName+", contentSize="+contentSize+", contentNodeRef="+contentNodeRef); + + long currentSize = getUserUsage(userName); + long quotaSize = getUserQuota(userName); + + long newSize = currentSize + contentSize; + + // check whether user's quota exceeded + if ((quotaSize != -1) && (newSize > quotaSize)) + { + if (logger.isWarnEnabled()) + { + logger.warn("User (" + userName + ") quota exceeded: content=" + contentSize + + ", usage=" + currentSize + + ", quota=" + quotaSize); + } + throw new ContentQuotaException("User quota exceeded"); + } + + NodeRef personNodeRef = getPerson(userName); + if (personNodeRef != null) + { + usageService.insertDelta(personNodeRef, contentSize); + } + } + } + + private void decrementUserUsage(String userName, long contentSize, NodeRef contentNodeRef) + { + if (! authenticationContext.isSystemUserName(userName)) + { + // decrement usage - add negative delta + if (logger.isDebugEnabled()) logger.debug("decrementUserUsage: username="+userName+", contentSize="+contentSize+", contentNodeRef="+contentNodeRef); + + long currentSize = getUserUsage(userName); + + long newSize = currentSize + contentSize; + + if (newSize < 0) + { + if (logger.isDebugEnabled()) + { + logger.debug("User (" + userName + ") has negative usage (" + newSize + ") - reset to 0"); + } + } + + NodeRef personNodeRef = getPerson(userName); + if (personNodeRef != null) + { + usageService.insertDelta(personNodeRef, (-contentSize)); + } + } + } + + /** + * Set user's usage. Should only be called by background (collapse) job ! + * + * @param userName + * @param currentUsage + */ + public void setUserStoredUsage(NodeRef personNodeRef, long currentUsage) + { + if (personNodeRef != null) + { + nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, new Long(currentUsage)); + } + } + + private long getUserStoredUsage(NodeRef personNodeRef) + { + Long currentUsage = null; + if (personNodeRef != null) + { + currentUsage = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT); + } + + return (currentUsage == null ? -1 : currentUsage); + } + + public long getUserUsage(String userName) + { + ParameterCheck.mandatoryString("userName", userName); + return getUserUsage(getPerson(userName)); + } + + public long getUserUsage(NodeRef personNodeRef) + { + long currentUsage = -1; + + if (personNodeRef != null) + { + currentUsage = getUserStoredUsage(personNodeRef); + } + + if (currentUsage != -1) + { + // add any deltas + currentUsage = currentUsage + usageService.getTotalDeltaSize(personNodeRef); + + if (currentUsage < 0) + { + if (logger.isWarnEnabled()) + { + logger.warn("User usage ("+ personNodeRef+") is negative ("+currentUsage+") overriding to 0"); + } + currentUsage = 0; + } + } + + return currentUsage; + } + + /** + * Set user's current quota. + * Usually called by Web Client (Admin Console) if admin is changing/setting a user's quota. + * + * @param userName + * @param currentQuota + */ + public void setUserQuota(String userName, long currentQuota) + { + NodeRef personNodeRef = getPerson(userName); + if (personNodeRef != null) + { + nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_QUOTA, new Long(currentQuota)); + } + } + + public long getUserQuota(String userName) + { + Long currentQuota = null; + + NodeRef personNodeRef = getPerson(userName); + if (personNodeRef != null) + { + currentQuota = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_QUOTA); + } + + return (currentQuota == null ? -1 : currentQuota); + } + + public boolean getEnabled() + { + return enabled; + } + + private NodeRef getPerson(String userName) + { + NodeRef personNodeRef = null; + try + { + personNodeRef = personService.getPerson(userName); + } + catch (RuntimeException e) + { + // workaround for ETHREEOH-1457 where existing tenants (created using 3.0.1) may have been bootstrapped with creator set + // to super admin (eg. "admin") rather than "System@xxx". This workaround should remain until we patch any such existing tenants + if (tenantService.isEnabled()) + { + personNodeRef = null; + } + else + { + throw e; + } + } + return personNodeRef; + } +} diff --git a/source/java/org/alfresco/repo/usage/UsageServiceImpl.java b/source/java/org/alfresco/repo/usage/UsageServiceImpl.java index 7d0d1c47f5..17cd2ce141 100644 --- a/source/java/org/alfresco/repo/usage/UsageServiceImpl.java +++ b/source/java/org/alfresco/repo/usage/UsageServiceImpl.java @@ -1,66 +1,66 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.usage; - -import java.util.Set; - -import org.alfresco.repo.domain.UsageDeltaDAO; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.usage.UsageService; - -/** - * The implementation of the UsageService for tracking usages. - * - * @author Jan Vonka - * @since 2.9 - */ -public class UsageServiceImpl implements UsageService -{ - private UsageDeltaDAO usageDeltaDAO; - - public void setUsageDeltaDAO(UsageDeltaDAO usageDeltaDAO) - { - this.usageDeltaDAO = usageDeltaDAO; - } - - public void insertDelta(NodeRef usageNodeRef, long deltaSize) - { - usageDeltaDAO.insertDelta(usageNodeRef, deltaSize); - } - - public long getTotalDeltaSize(NodeRef usageNodeRef) - { - return usageDeltaDAO.getTotalDeltaSize(usageNodeRef); - } - - public long getAndRemoveTotalDeltaSize(NodeRef usageNodeRef) - { - return usageDeltaDAO.getAndRemoveTotalDeltaSize(usageNodeRef); - } - - public Set getUsageDeltaNodes() - { - return usageDeltaDAO.getUsageDeltaNodes(); - } - - public int deleteDeltas(NodeRef usageNodeRef) - { - return usageDeltaDAO.deleteDeltas(usageNodeRef); - } -} +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.usage; + +import java.util.Set; + +import org.alfresco.repo.domain.usage.UsageDAO; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.usage.UsageService; + +/** + * The implementation of the UsageService for tracking usages. + * + * @author janv + * @since 2.9, 3.0 + */ +public class UsageServiceImpl implements UsageService +{ + private UsageDAO usageDAO; + + public void setUsageDAO(UsageDAO usageDAO) + { + this.usageDAO = usageDAO; + } + + public void insertDelta(NodeRef usageNodeRef, long deltaSize) + { + usageDAO.insertDelta(usageNodeRef, deltaSize); + } + + public long getTotalDeltaSize(NodeRef usageNodeRef) + { + return usageDAO.getTotalDeltaSize(usageNodeRef, false); + } + + public long getAndRemoveTotalDeltaSize(NodeRef usageNodeRef) + { + return usageDAO.getTotalDeltaSize(usageNodeRef, true); + } + + public Set getUsageDeltaNodes() + { + return usageDAO.getUsageDeltaNodes(); + } + + public int deleteDeltas(NodeRef usageNodeRef) + { + return usageDAO.deleteDeltas(usageNodeRef); + } +} diff --git a/source/java/org/alfresco/repo/usage/UserUsageTrackingComponent.java b/source/java/org/alfresco/repo/usage/UserUsageTrackingComponent.java index e6115f580a..7a013387b0 100644 --- a/source/java/org/alfresco/repo/usage/UserUsageTrackingComponent.java +++ b/source/java/org/alfresco/repo/usage/UserUsageTrackingComponent.java @@ -1,594 +1,586 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.repo.usage; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.node.db.NodeDaoService; -import org.alfresco.repo.node.db.NodeDaoService.ObjectArrayQueryCallback; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; -import org.alfresco.repo.tenant.Tenant; -import org.alfresco.repo.tenant.TenantAdminService; -import org.alfresco.repo.tenant.TenantService; -import org.alfresco.repo.transaction.TransactionServiceImpl; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -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.repository.StoreRef; -import org.alfresco.service.cmr.usage.UsageService; -import org.alfresco.service.namespace.QName; -import org.springframework.extensions.surf.util.AbstractLifecycleBean; -import org.alfresco.util.Pair; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.context.ApplicationEvent; - -/** - * User Usage Tracking Component - to allow user usages to be collapsed or re-calculated - * - * - used by UserUsageCollapseJob to collapse usage deltas. - * - used on bootstrap to either clear all usages or (re-)calculate all missing usages. - */ -public class UserUsageTrackingComponent extends AbstractLifecycleBean -{ - private static Log logger = LogFactory.getLog(UserUsageTrackingComponent.class); - - private TransactionServiceImpl transactionService; - private ContentUsageImpl contentUsageImpl; - - private NodeService nodeService; - private NodeDaoService nodeDaoService; - private UsageService usageService; - private TenantAdminService tenantAdminService; - private TenantService tenantService; - - private StoreRef personStoreRef; - - private int clearBatchSize = 50; - private int updateBatchSize = 50; - - private boolean enabled = true; - private Lock writeLock = new ReentrantLock(); - - public void setTransactionService(TransactionServiceImpl transactionService) - { - this.transactionService = transactionService; - } - - public void setContentUsageImpl(ContentUsageImpl contentUsageImpl) - { - this.contentUsageImpl = contentUsageImpl; - } - - public void setPersonStoreUrl(String storeUrl) - { - this.personStoreRef = new StoreRef(storeUrl); - } - - public void setNodeService(NodeService nodeService) - { - this.nodeService = nodeService; - } - - public void setNodeDaoService(NodeDaoService nodeDaoService) - { - this.nodeDaoService = nodeDaoService; - } - - public void setUsageService(UsageService usageService) - { - this.usageService = usageService; - } - - public void setTenantAdminService(TenantAdminService tenantAdminService) - { - this.tenantAdminService = tenantAdminService; - } - - public void setTenantService(TenantService tenantService) - { - this.tenantService = tenantService; - } - - public void setClearBatchSize(int clearBatchSize) - { - this.clearBatchSize = clearBatchSize; - } - - public void setUpdateBatchSize(int updateBatchSize) - { - this.updateBatchSize = updateBatchSize; - } - - public void setEnabled(boolean enabled) - { - this.enabled = enabled; - } - - public void execute() - { - if (enabled == false || transactionService.isReadOnly()) - { - return; - } - - boolean locked = writeLock.tryLock(); - if (locked) - { - // collapse usages - note: for MT environment, will collapse for all tenants - try - { - collapseUsages(); - } - finally - { - writeLock.unlock(); - } - } - } - - - @Override - protected void onBootstrap(ApplicationEvent event) - { - // default domain - bootstrapInternal(); - - if (tenantAdminService.isEnabled()) - { - List tenants = tenantAdminService.getAllTenants(); - for (Tenant tenant : tenants) - { - AuthenticationUtil.runAs(new RunAsWork() - { - public Object doWork() throws Exception - { - bootstrapInternal(); - return null; - } - }, tenantAdminService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenant.getTenantDomain())); - } - } - } - - public void bootstrapInternal() - { - if (transactionService.isReadOnly()) - { - return; - } - - boolean locked = writeLock.tryLock(); - if (locked) - { - try - { - if (enabled) - { - // enabled - calculate missing usages - calculateMissingUsages(); - } - else - { - if (clearBatchSize != 0) - { - // disabled - remove all usages - clearAllUsages(); - } - } - } - finally - { - writeLock.unlock(); - } - } - } - - @Override - protected void onShutdown(ApplicationEvent event) - { - } - - - /** - * Clear content usage for all users that have a usage. - */ - private void clearAllUsages() - { - if (logger.isInfoEnabled()) - { - logger.info("Disabled - clear non-missing user usages ..."); - } - - final Map users = new HashMap(); - - RetryingTransactionCallback getUsersWithUsage = new RetryingTransactionCallback() - { - public Object execute() throws Throwable - { - // get people (users) with calculated usage - ObjectArrayQueryCallback userHandler = new ObjectArrayQueryCallback() - { - public boolean handle(Object[] arr) - { - String username = (String)arr[0]; - String uuid = (String)arr[1]; - - users.put(username, new NodeRef(personStoreRef, uuid)); - - return true; // continue to next node (more required) - } - }; - nodeDaoService.getUsersWithUsage(personStoreRef, userHandler); - - return null; - } - }; - - // execute in READ-ONLY txn - transactionService.getRetryingTransactionHelper().doInTransaction(getUsersWithUsage, true); - - if (logger.isInfoEnabled()) - { - logger.info("Found " + users.size() + " users to clear"); - } - - int clearCount = 0; - int batchCount = 0; - int totalCount = 0; - - List batchPersonRefs = new ArrayList(clearBatchSize); - for (NodeRef personNodeRef : users.values()) - { - batchPersonRefs.add(personNodeRef); - batchCount++; - totalCount++; - - if ((batchCount == clearBatchSize) || (totalCount == users.size())) - { - int cleared = clearUsages(batchPersonRefs); - clearCount = clearCount + cleared; - - batchPersonRefs.clear(); - batchCount = 0; - } - } - - if (logger.isInfoEnabled()) - { - logger.info("... cleared non-missing usages for " + clearCount + " users"); - } - } - - private int clearUsages(final List personNodeRefs) - { - RetryingTransactionCallback clearPersonUsage = new RetryingTransactionCallback() - { - public Integer execute() throws Throwable - { - int clearCount = 0; - for (NodeRef personNodeRef : personNodeRefs) - { - nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, null); - usageService.deleteDeltas(personNodeRef); - - if (logger.isTraceEnabled()) - { - logger.trace("Cleared usage for person ("+ personNodeRef+")"); - } - - clearCount++; - } - return clearCount; - } - }; - - // execute in READ-WRITE txn - return transactionService.getRetryingTransactionHelper().doInTransaction(clearPersonUsage, false); - } - - /** - * Recalculate content usage for all users that have no usage. - * Required if upgrading an existing Alfresco, for users that have not had their initial usage calculated. - */ - private void calculateMissingUsages() - { - if (logger.isInfoEnabled()) - { - logger.info("Enabled - calculate missing user usages ..."); - } - - final Map users = new HashMap(); - - RetryingTransactionCallback getUsersWithoutUsage = new RetryingTransactionCallback() - { - public Object execute() throws Throwable - { - // get people (users) without calculated usage - ObjectArrayQueryCallback userHandler = new ObjectArrayQueryCallback() - { - public boolean handle(Object[] arr) - { - String username = (String)arr[0]; - String uuid = (String)arr[1]; - - users.put(username, new NodeRef(personStoreRef, uuid)); - - return true; // continue to next node (more required) - } - }; - - nodeDaoService.getUsersWithoutUsage(tenantService.getName(personStoreRef), userHandler); - - return null; - } - }; - - // execute in READ-ONLY txn - transactionService.getRetryingTransactionHelper().doInTransaction(getUsersWithoutUsage, true); - - if (logger.isInfoEnabled()) - { - logger.info("Found " + users.size() + " users to recalculate"); - } - - int updateCount = 0; - if (users.size() > 0) - { - updateCount = recalculateUsages(users); - } - - if (logger.isInfoEnabled()) - { - logger.info("... calculated missing usages for " + updateCount + " users"); - } - } - - /* - * Recalculate content usage for given users. Required if upgrading an existing Alfresco, for users that - * have not had their initial usage calculated. In a future release, could also be called explicitly by - * a SysAdmin, eg. via a JMX operation. - */ - private int recalculateUsages(final Map users) - { - final Map currentUserUsages = new HashMap(users.size()); - - RetryingTransactionCallback calculateCurrentUsages = new RetryingTransactionCallback() - { - public Long execute() throws Throwable - { - List stores = contentUsageImpl.getStores(); - - for (String store : stores) - { - final StoreRef storeRef = tenantService.getName(new StoreRef(store)); - - if (logger.isTraceEnabled()) - { - logger.trace("Recalc usages for store=" + storeRef); - } - - // get content urls - ObjectArrayQueryCallback nodeContentUrlHandler = new ObjectArrayQueryCallback() - { - public boolean handle(Object[] arr) - { - String owner = (String)arr[0]; - String creator = (String)arr[1]; - String contentUrlStr = (String)arr[2]; - - if (owner == null) - { - owner = creator; - } - - ContentData contentData = ContentData.createContentProperty(contentUrlStr); - if (contentData != null) - { - Long currentUsage = currentUserUsages.get(owner); - - if (currentUsage == null) - { - currentUsage = 0L; - } - - currentUserUsages.put(owner, currentUsage + contentData.getSize()); - } - return true; // continue to next node (more required) - } - }; - nodeDaoService.getContentUrlsForStore(storeRef, nodeContentUrlHandler); - } - - return null; - } - }; - - // execute in READ-ONLY txn - transactionService.getRetryingTransactionHelper().doInTransaction(calculateCurrentUsages, true); - - if (logger.isDebugEnabled()) - { - logger.debug("Usages calculated - start update"); - } - - int updateCount = 0; - int batchCount = 0; - int totalCount = 0; - - List> batchUserUsages = new ArrayList>(updateBatchSize); - - for (Map.Entry user : users.entrySet()) - { - String userName = user.getKey(); - NodeRef personNodeRef = user.getValue(); - - Long currentUsage = currentUserUsages.get(userName); - if (currentUsage == null) - { - currentUsage = 0L; - } - - batchUserUsages.add(new Pair(personNodeRef, currentUsage)); - batchCount++; - totalCount++; - - if ((batchCount == updateBatchSize) || (totalCount == users.size())) - { - int updated = updateUsages(batchUserUsages); - updateCount = updateCount + updated; - - batchUserUsages.clear(); - batchCount = 0; - } - } - - return totalCount; - } - - private int updateUsages(final List> userUsages) - { - RetryingTransactionCallback updateCurrentUsages = new RetryingTransactionCallback() - { - public Integer execute() throws Throwable - { - int updateCount = 0; - - for (Pair userUsage : userUsages) - { - NodeRef personNodeRef = userUsage.getFirst(); - Long currentUsage = userUsage.getSecond(); - - contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage); - usageService.deleteDeltas(personNodeRef); - - updateCount++; - } - return updateCount; - } - }; - - // execute in READ-WRITE txn - return transactionService.getRetryingTransactionHelper().doInTransaction(updateCurrentUsages, false); - } - - /** - * Collapse usages - note: for MT environment, will collapse all tenants - */ - private void collapseUsages() - { - if (logger.isDebugEnabled()) - { - logger.debug("Collapse usages ..."); - } - - // Collapse usage deltas (if a person has initial usage set) - RetryingTransactionCallback> getUsageNodeRefs = new RetryingTransactionCallback>() - { - public Set execute() throws Throwable - { - // Get distinct candidates - return usageService.getUsageDeltaNodes(); - } - }; - - // execute in READ-ONLY txn - Set usageNodeRefs = transactionService.getRetryingTransactionHelper().doInTransaction(getUsageNodeRefs, true); - - int collapseCount = 0; - for (final NodeRef usageNodeRef : usageNodeRefs) - { - Boolean collapsed = AuthenticationUtil.runAs(new RunAsWork() - { - public Boolean doWork() throws Exception - { - return collapseUsage(usageNodeRef); - } - }, tenantAdminService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantAdminService.getDomain(usageNodeRef.getStoreRef().getIdentifier()))); - - if (collapsed) - { - collapseCount++; - } - } - - if (logger.isDebugEnabled()) - { - logger.debug("... collapsed usages for " + collapseCount + " users"); - } - } - - private boolean collapseUsage(final NodeRef usageNodeRef) - { - RetryingTransactionCallback collapseUsages = new RetryingTransactionCallback() - { - public Boolean execute() throws Throwable - { - if (!nodeService.exists(usageNodeRef)) - { - // Ignore - return false; - } - QName nodeType = nodeService.getType(usageNodeRef); - - if (nodeType.equals(ContentModel.TYPE_PERSON)) - { - NodeRef personNodeRef = usageNodeRef; - String userName = (String)nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME); - - long currentUsage = contentUsageImpl.getUserStoredUsage(personNodeRef); - if (currentUsage != -1) - { - // Collapse the usage deltas - // Calculate and remove deltas in one go to guard against deletion of - // deltas from another transaction that have not been included in the - // calculation - currentUsage = contentUsageImpl.getUserUsage(userName, true); - contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage); - - if (logger.isTraceEnabled()) - { - logger.trace("Collapsed usage: username=" + userName + ", usage=" + currentUsage); - } - } - else - { - if (logger.isWarnEnabled()) - { - logger.warn("Initial usage for user has not yet been calculated: " + userName); - } - } - } - return true; - } - }; - - // execute in READ-WRITE txn - return transactionService.getRetryingTransactionHelper().doInTransaction(collapseUsages, false); - } -} +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.usage; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.usage.UsageDAO; +import org.alfresco.repo.domain.usage.UsageDAO.MapHandler; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.tenant.Tenant; +import org.alfresco.repo.tenant.TenantAdminService; +import org.alfresco.repo.tenant.TenantService; +import org.alfresco.repo.transaction.TransactionServiceImpl; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +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.usage.UsageService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.ApplicationEvent; +import org.springframework.extensions.surf.util.AbstractLifecycleBean; + +/** + * User Usage Tracking Component - to allow user usages to be collapsed or re-calculated + * + * - used by UserUsageCollapseJob to collapse usage deltas. + * - used on bootstrap to either clear all usages or (re-)calculate all missing usages. + */ +public class UserUsageTrackingComponent extends AbstractLifecycleBean +{ + private static Log logger = LogFactory.getLog(UserUsageTrackingComponent.class); + + private TransactionServiceImpl transactionService; + private ContentUsageImpl contentUsageImpl; + + private NodeService nodeService; + private UsageDAO usageDAO; + private UsageService usageService; + private TenantAdminService tenantAdminService; + private TenantService tenantService; + + private StoreRef personStoreRef; + + private int clearBatchSize = 50; + private int updateBatchSize = 50; + + private boolean enabled = true; + private Lock writeLock = new ReentrantLock(); + + public void setTransactionService(TransactionServiceImpl transactionService) + { + this.transactionService = transactionService; + } + + public void setContentUsageImpl(ContentUsageImpl contentUsageImpl) + { + this.contentUsageImpl = contentUsageImpl; + } + + public void setPersonStoreUrl(String storeUrl) + { + this.personStoreRef = new StoreRef(storeUrl); + } + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + public void setUsageDAO(UsageDAO usageDAO) + { + this.usageDAO = usageDAO; + } + + public void setUsageService(UsageService usageService) + { + this.usageService = usageService; + } + + public void setTenantAdminService(TenantAdminService tenantAdminService) + { + this.tenantAdminService = tenantAdminService; + } + + public void setTenantService(TenantService tenantService) + { + this.tenantService = tenantService; + } + + public void setClearBatchSize(int clearBatchSize) + { + this.clearBatchSize = clearBatchSize; + } + + public void setUpdateBatchSize(int updateBatchSize) + { + this.updateBatchSize = updateBatchSize; + } + + public void setEnabled(boolean enabled) + { + this.enabled = enabled; + } + + public void execute() + { + if (enabled == false || transactionService.isReadOnly()) + { + return; + } + + boolean locked = writeLock.tryLock(); + if (locked) + { + // collapse usages - note: for MT environment, will collapse for all tenants + try + { + collapseUsages(); + } + finally + { + writeLock.unlock(); + } + } + } + + + @Override + protected void onBootstrap(ApplicationEvent event) + { + // default domain + bootstrapInternal(); + + if (tenantAdminService.isEnabled()) + { + List tenants = tenantAdminService.getAllTenants(); + for (Tenant tenant : tenants) + { + AuthenticationUtil.runAs(new RunAsWork() + { + public Object doWork() throws Exception + { + bootstrapInternal(); + return null; + } + }, tenantAdminService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenant.getTenantDomain())); + } + } + } + + public void bootstrapInternal() + { + if (transactionService.isReadOnly()) + { + return; + } + + boolean locked = writeLock.tryLock(); + if (locked) + { + try + { + if (enabled) + { + // enabled - calculate missing usages + calculateMissingUsages(); + } + else + { + if (clearBatchSize != 0) + { + // disabled - remove all usages + clearAllUsages(); + } + } + } + finally + { + writeLock.unlock(); + } + } + } + + @Override + protected void onShutdown(ApplicationEvent event) + { + } + + + /** + * Clear content usage for all users that have a usage. + */ + private void clearAllUsages() + { + if (logger.isInfoEnabled()) + { + logger.info("Disabled - clear non-missing user usages ..."); + } + + final Map users = new HashMap(); + + RetryingTransactionCallback getUsersWithUsage = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + // get people (users) with calculated usage + MapHandler userHandler = new MapHandler() + { + public void handle(Map result) + { + String username = (String)result.get("username"); + String uuid = (String)result.get("uuid"); + + users.put(username, new NodeRef(personStoreRef, uuid)); + } + }; + usageDAO.getUsersWithUsage(personStoreRef, userHandler); + + return null; + } + }; + + // execute in READ-ONLY txn + transactionService.getRetryingTransactionHelper().doInTransaction(getUsersWithUsage, true); + + if (logger.isInfoEnabled()) + { + logger.info("Found " + users.size() + " users to clear"); + } + + int clearCount = 0; + int batchCount = 0; + int totalCount = 0; + + List batchPersonRefs = new ArrayList(clearBatchSize); + for (NodeRef personNodeRef : users.values()) + { + batchPersonRefs.add(personNodeRef); + batchCount++; + totalCount++; + + if ((batchCount == clearBatchSize) || (totalCount == users.size())) + { + int cleared = clearUsages(batchPersonRefs); + clearCount = clearCount + cleared; + + batchPersonRefs.clear(); + batchCount = 0; + } + } + + if (logger.isInfoEnabled()) + { + logger.info("... cleared non-missing usages for " + clearCount + " users"); + } + } + + private int clearUsages(final List personNodeRefs) + { + RetryingTransactionCallback clearPersonUsage = new RetryingTransactionCallback() + { + public Integer execute() throws Throwable + { + int clearCount = 0; + for (NodeRef personNodeRef : personNodeRefs) + { + nodeService.setProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT, null); + usageService.deleteDeltas(personNodeRef); + + if (logger.isTraceEnabled()) + { + logger.trace("Cleared usage for person ("+ personNodeRef+")"); + } + + clearCount++; + } + return clearCount; + } + }; + + // execute in READ-WRITE txn + return transactionService.getRetryingTransactionHelper().doInTransaction(clearPersonUsage, false); + } + + /** + * Recalculate content usage for all users that have no usage. + * Required if upgrading an existing Alfresco, for users that have not had their initial usage calculated. + */ + private void calculateMissingUsages() + { + if (logger.isInfoEnabled()) + { + logger.info("Enabled - calculate missing user usages ..."); + } + + final Map users = new HashMap(); + + RetryingTransactionCallback getUsersWithoutUsage = new RetryingTransactionCallback() + { + public Object execute() throws Throwable + { + // get people (users) without calculated usage + MapHandler userHandler = new MapHandler() + { + public void handle(Map result) + { + String username = (String)result.get("username"); + String uuid = (String)result.get("uuid"); + + users.put(username, new NodeRef(personStoreRef, uuid)); + } + }; + + usageDAO.getUsersWithoutUsage(tenantService.getName(personStoreRef), userHandler); + + return null; + } + }; + + // execute in READ-ONLY txn + transactionService.getRetryingTransactionHelper().doInTransaction(getUsersWithoutUsage, true); + + if (logger.isInfoEnabled()) + { + logger.info("Found " + users.size() + " users to recalculate"); + } + + int updateCount = 0; + if (users.size() > 0) + { + updateCount = recalculateUsages(users); + } + + if (logger.isInfoEnabled()) + { + logger.info("... calculated missing usages for " + updateCount + " users"); + } + } + + /* + * Recalculate content usage for given users. Required if upgrading an existing Alfresco, for users that + * have not had their initial usage calculated. In a future release, could also be called explicitly by + * a SysAdmin, eg. via a JMX operation. + */ + private int recalculateUsages(final Map users) + { + final Map currentUserUsages = new HashMap(users.size()); + + RetryingTransactionCallback calculateCurrentUsages = new RetryingTransactionCallback() + { + public Long execute() throws Throwable + { + List stores = contentUsageImpl.getStores(); + + for (String store : stores) + { + final StoreRef storeRef = tenantService.getName(new StoreRef(store)); + + if (logger.isTraceEnabled()) + { + logger.trace("Recalc usages for store=" + storeRef); + } + + // get content urls + MapHandler userContentUrlHandler = new MapHandler() + { + public void handle(Map result) + { + String owner = (String)result.get("owner"); + String creator = (String)result.get("creator"); + Long contentSize = (Long)result.get("contentSize"); // sum of content size (via join of new style content id) + + if (contentSize == null) + { + contentSize = 0L; + } + + if (owner == null) + { + owner = creator; + } + + Long currentUsage = currentUserUsages.get(owner); + + if (currentUsage == null) + { + currentUsage = 0L; + } + + currentUserUsages.put(owner, currentUsage + contentSize); + } + }; + + // Query and sum the 'new' style content properties + usageDAO.getUserContentSizesForStore(storeRef, userContentUrlHandler); + } + + return null; + } + }; + + // execute in READ-ONLY txn + transactionService.getRetryingTransactionHelper().doInTransaction(calculateCurrentUsages, true); + + if (logger.isDebugEnabled()) + { + logger.debug("Usages calculated - start update"); + } + + int updateCount = 0; + int batchCount = 0; + int totalCount = 0; + + List> batchUserUsages = new ArrayList>(updateBatchSize); + + for (Map.Entry user : users.entrySet()) + { + String userName = user.getKey(); + NodeRef personNodeRef = user.getValue(); + + Long currentUsage = currentUserUsages.get(userName); + if (currentUsage == null) + { + currentUsage = 0L; + } + + batchUserUsages.add(new Pair(personNodeRef, currentUsage)); + batchCount++; + totalCount++; + + if ((batchCount == updateBatchSize) || (totalCount == users.size())) + { + int updated = updateUsages(batchUserUsages); + updateCount = updateCount + updated; + + batchUserUsages.clear(); + batchCount = 0; + } + } + + return totalCount; + } + + private int updateUsages(final List> userUsages) + { + RetryingTransactionCallback updateCurrentUsages = new RetryingTransactionCallback() + { + public Integer execute() throws Throwable + { + int updateCount = 0; + + for (Pair userUsage : userUsages) + { + NodeRef personNodeRef = userUsage.getFirst(); + Long currentUsage = userUsage.getSecond(); + + contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage); + usageService.deleteDeltas(personNodeRef); + + updateCount++; + } + return updateCount; + } + }; + + // execute in READ-WRITE txn + return transactionService.getRetryingTransactionHelper().doInTransaction(updateCurrentUsages, false); + } + + /** + * Collapse usages - note: for MT environment, will collapse all tenants + */ + private void collapseUsages() + { + if (logger.isDebugEnabled()) + { + logger.debug("Collapse usages ..."); + } + + // Collapse usage deltas (if a person has initial usage set) + RetryingTransactionCallback> getUsageNodeRefs = new RetryingTransactionCallback>() + { + public Set execute() throws Throwable + { + // Get distinct candidates + return usageService.getUsageDeltaNodes(); + } + }; + + // execute in READ-ONLY txn + Set usageNodeRefs = transactionService.getRetryingTransactionHelper().doInTransaction(getUsageNodeRefs, true); + + int collapseCount = 0; + for (final NodeRef usageNodeRef : usageNodeRefs) + { + Boolean collapsed = AuthenticationUtil.runAs(new RunAsWork() + { + public Boolean doWork() throws Exception + { + return collapseUsage(usageNodeRef); + } + }, tenantAdminService.getDomainUser(AuthenticationUtil.getSystemUserName(), tenantAdminService.getDomain(usageNodeRef.getStoreRef().getIdentifier()))); + + if (collapsed) + { + collapseCount++; + } + } + + if (logger.isDebugEnabled()) + { + logger.debug("... collapsed usages for " + collapseCount + " users"); + } + } + + private boolean collapseUsage(final NodeRef usageNodeRef) + { + RetryingTransactionCallback collapseUsages = new RetryingTransactionCallback() + { + public Boolean execute() throws Throwable + { + if (!nodeService.exists(usageNodeRef)) + { + // Ignore + return false; + } + QName nodeType = nodeService.getType(usageNodeRef); + + if (nodeType.equals(ContentModel.TYPE_PERSON)) + { + NodeRef personNodeRef = usageNodeRef; + // collapse the usage deltas + long currentUsage = contentUsageImpl.getUserUsage(personNodeRef); + if (currentUsage != -1) + { + usageService.deleteDeltas(personNodeRef); + contentUsageImpl.setUserStoredUsage(personNodeRef, currentUsage); + + if (logger.isTraceEnabled()) + { + logger.trace("Collapsed usage: personNodeRef=" + personNodeRef + ", usage=" + currentUsage); + } + } + else + { + if (logger.isWarnEnabled()) + { + logger.warn("Initial usage has not yet been calculated: personNodeRef=" + personNodeRef); + } + } + } + return true; + } + }; + + // execute in READ-WRITE txn + return transactionService.getRetryingTransactionHelper().doInTransaction(collapseUsages, false); + } +} diff --git a/source/java/org/alfresco/repo/usage/UserUsageTrackingComponentTest.java b/source/java/org/alfresco/repo/usage/UserUsageTrackingComponentTest.java index 73d83cf88c..25456c6ac3 100644 --- a/source/java/org/alfresco/repo/usage/UserUsageTrackingComponentTest.java +++ b/source/java/org/alfresco/repo/usage/UserUsageTrackingComponentTest.java @@ -1,387 +1,388 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.repo.usage; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; - -import javax.transaction.UserTransaction; - -import junit.framework.TestCase; - -import org.alfresco.model.ContentModel; -import org.alfresco.repo.content.MimetypeMap; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.service.cmr.repository.ChildAssociationRef; -import org.alfresco.service.cmr.repository.ContentService; -import org.alfresco.service.cmr.repository.ContentWriter; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.security.MutableAuthenticationService; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.cmr.usage.ContentUsageService; -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; - -/** - * Test enabling (recalculating) and disabling (clearing) and user usages, and also collapsing user usage deltas. - */ -public class UserUsageTrackingComponentTest extends TestCase -{ - private static ApplicationContext applicationContext = ApplicationContextHelper.getApplicationContext(); - - private boolean clean = true; - - private MutableAuthenticationService authenticationService; - private ContentService contentService; - private TransactionService transactionService; - private PersonService personService; - private NodeService nodeService; - private UserUsageTrackingComponent userUsageTrackingComponent; - private ContentUsageService contentUsageService; - - private UserTransaction testTX; - - public static StoreRef SPACES_STORE = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore"); - - private static final String TEST_USER_PREFIX = "user-"; - - private static final int MAX_USERS = 5; - private static final int BATCH_SIZE = 5; - private static final int PROGRESS_SIZE = 100; - - protected void setUp() throws Exception - { - nodeService = (NodeService)applicationContext.getBean("NodeService"); - authenticationService = (MutableAuthenticationService)applicationContext.getBean("authenticationService"); - transactionService = (TransactionService)applicationContext.getBean("transactionComponent"); - personService = (PersonService)applicationContext.getBean("PersonService"); - contentService = (ContentService)applicationContext.getBean("ContentService"); - contentUsageService = (ContentUsageService)applicationContext.getBean("ContentUsageService"); - - userUsageTrackingComponent = (UserUsageTrackingComponent)applicationContext.getBean("userUsageTrackingComponent"); - - AuthenticationUtil.setRunAsUserSystem(); - - createUsersAndContent(); - } - - protected void tearDown() throws Exception - { - if (clean) - { - deleteUsersAndContent(); - } - - super.tearDown(); - } - - private void createUsersAndContent() - { - long start = System.currentTimeMillis(); - long progressStart = System.currentTimeMillis(); - - try - { - int count = 0; - int batch = 0; - //long batchStart = 0; - - for (int i = 1; i <= MAX_USERS; i++) - { - if (count == 0) - { - batch++; - - testTX = transactionService.getUserTransaction(); - testTX.begin(); - - //batchStart = System.currentTimeMillis(); - } - - count++; - String userName = TEST_USER_PREFIX+i; - - if (! authenticationService.authenticationExists(userName)) - { - // Note: this will auto-create the user home - HashMap props = new HashMap(); - props.put(ContentModel.PROP_USERNAME, userName); - personService.createPerson(props); - - authenticationService.createAuthentication(userName, userName.toCharArray()); - - NodeRef homeFolder = getHomeSpaceFolderNode(userName); - - StringBuilder sb = new StringBuilder(); - for (int j = 1; j <= i; j++) - { - int k = j % 10; - sb.append(k); - } - - AuthenticationUtil.setFullyAuthenticatedUser(userName); - - addTextContent(homeFolder, "a-"+userName+".txt", sb.toString()); - addTextContent(homeFolder, "b-"+userName+".txt", sb.toString()); - } - - AuthenticationUtil.setRunAsUserSystem(); - - if ((count == BATCH_SIZE) || (i == MAX_USERS)) - { - testTX.commit(); - count = 0; - - //System.out.println("Batch "+batch+" took "+((System.currentTimeMillis()-batchStart)/1000)+" secs"); - } - - if (((i % PROGRESS_SIZE) == 0) && (i != MAX_USERS)) - { - System.out.println("Progress: "+PROGRESS_SIZE+" users created in "+((System.currentTimeMillis()-progressStart)/1000)+" secs"); - progressStart = System.currentTimeMillis(); - } - } - - System.out.println("Total: "+MAX_USERS+" users created in "+((System.currentTimeMillis()-start)/1000)+" secs"); - } - catch (Throwable t) - { - t.printStackTrace(); - - try { testTX.rollback(); } catch (Exception e) { e.printStackTrace(); } - } - } - - public void testEnableDisableCollapse() - { - userUsageTrackingComponent.setEnabled(false); - userUsageTrackingComponent.bootstrapInternal(); // false => clear - - System.out.println("Cleared usages"); - - checkCleared(); - - userUsageTrackingComponent.setEnabled(true); - userUsageTrackingComponent.bootstrapInternal(); // true => recalculate - - System.out.println("Recalculated usages"); - - checkCalculated(2L); - - checkUsage(2L); - - // add content - for (int i = 1; i <= MAX_USERS; i++) - { - String userName = TEST_USER_PREFIX+i; - - NodeRef homeFolder = getHomeSpaceFolderNode(userName); - - AuthenticationUtil.setFullyAuthenticatedUser(userName); - - StringBuilder sb = new StringBuilder(); - for (int j = 1; j <= i; j++) - { - int k = j % 10; - sb.append(k); - } - - addTextContent(homeFolder, "c-"+userName+".txt", sb.toString()); - addTextContent(homeFolder, "d-"+userName+".txt", sb.toString()); - - AuthenticationUtil.setRunAsUserSystem(); - } - - System.out.println("Added content"); - - checkUsage(4L); - - userUsageTrackingComponent.execute(); // collapse usages - - System.out.println("Collapsed usages"); - - checkUsage(4L); - - // delete content - for (int i = 1; i <= MAX_USERS; i++) - { - String userName = TEST_USER_PREFIX+i; - - NodeRef homeFolder = getHomeSpaceFolderNode(userName); - - AuthenticationUtil.setFullyAuthenticatedUser(userName); - - NodeRef childNodeRef = nodeService.getChildByName(homeFolder, ContentModel.ASSOC_CONTAINS, "a-"+userName+".txt"); - nodeService.deleteNode(childNodeRef); - - childNodeRef = nodeService.getChildByName(homeFolder, ContentModel.ASSOC_CONTAINS, "b-"+userName+".txt"); - nodeService.deleteNode(childNodeRef); - - AuthenticationUtil.setRunAsUserSystem(); - } - - System.out.println("Deleted content"); - - checkUsage(2L); - - userUsageTrackingComponent.execute(); // collapse usages - - System.out.println("Collapsed usages"); - - checkUsage(2L); - - userUsageTrackingComponent.setEnabled(false); - userUsageTrackingComponent.bootstrapInternal(); // false => clear - - System.out.println("Cleared usages"); - checkCleared(); - } - - private void checkCalculated(long factor) - { - for (int i = 1; i <= MAX_USERS; i++) - { - String userName = TEST_USER_PREFIX+i; - NodeRef personNodeRef = personService.getPerson(userName); - - // get user stored usage (not including deltas, if any) - Long sizeProp = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT); - assertNotNull("Property " + ContentModel.PROP_SIZE_CURRENT + "does not exist, yet", sizeProp); - assertEquals(userName, i*factor, sizeProp.longValue()); - } - } - - private void checkUsage(long factor) - { - for (int i = 1; i <= MAX_USERS; i++) - { - String userName = TEST_USER_PREFIX+i; - - // get user usage (including deltas, if any) - assertEquals(userName, i*factor, contentUsageService.getUserUsage(userName)); - } - } - - private void checkCleared() - { - for (int i = 1; i <= MAX_USERS; i++) - { - String userName = TEST_USER_PREFIX+i; - NodeRef personNodeRef = personService.getPerson(userName); - - assertNull(nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT)); - } - } - - private void deleteUsersAndContent() - { - long start = System.currentTimeMillis(); - - try - { - int count = 0; - int batch = 0; - //long batchStart = 0; - - int deleteCount = 0; - - for (int i = 1; i <= MAX_USERS; i++) - { - if (count == 0) - { - batch++; - - testTX = transactionService.getUserTransaction(); - testTX.begin(); - //batchStart = System.currentTimeMillis(); - } - - count++; - String userName = TEST_USER_PREFIX+i; - - - if (authenticationService.authenticationExists(userName)) - { - NodeRef homeFolder = getHomeSpaceFolderNode(userName); - nodeService.deleteNode(homeFolder); - - personService.deletePerson(userName); - deleteCount++; - } - - if ((count == BATCH_SIZE) || (i == MAX_USERS)) - { - testTX.commit(); - count = 0; - - //System.out.println("Batch "+batch+" took "+((System.currentTimeMillis()-batchStart)/1000)+" secs"); - } - } - - System.out.println("Total: "+deleteCount+" users deleted in "+((System.currentTimeMillis()-start)/1000)+" secs"); - } - catch (Throwable t) - { - t.printStackTrace(); - - try { testTX.rollback(); } catch (Exception e) { e.printStackTrace(); } - } - } - - private NodeRef getHomeSpaceFolderNode(String userName) - { - return (NodeRef)this.nodeService.getProperty(personService.getPerson(userName), ContentModel.PROP_HOMEFOLDER); - } - - private NodeRef addTextContent(NodeRef spaceRef, String fileName, String textData) - { - Map contentProps = new HashMap(); - contentProps.put(ContentModel.PROP_NAME, fileName); - - ChildAssociationRef association = nodeService.createNode(spaceRef, - ContentModel.ASSOC_CONTAINS, - QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, fileName), - ContentModel.TYPE_CONTENT, - contentProps); - - NodeRef content = association.getChildRef(); - - // add titled aspect (for Web Client display) - Map titledProps = new HashMap(); - titledProps.put(ContentModel.PROP_TITLE, fileName); - titledProps.put(ContentModel.PROP_DESCRIPTION, fileName); - this.nodeService.addAspect(content, ContentModel.ASPECT_TITLED, titledProps); - - ContentWriter writer = contentService.getWriter(content, ContentModel.PROP_CONTENT, true); - - writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); - writer.setEncoding("UTF-8"); - - writer.putContent(textData); - - return content; - } -} +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +package org.alfresco.repo.usage; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import javax.transaction.UserTransaction; + +import junit.framework.TestCase; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.security.MutableAuthenticationService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.cmr.usage.ContentUsageService; +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; + +/** + * Test enabling (recalculating) and disabling (clearing) and user usages, and also collapsing user usage deltas. + */ +public class UserUsageTrackingComponentTest extends TestCase +{ + private static ApplicationContext applicationContext = ApplicationContextHelper.getApplicationContext(); + + private boolean clean = true; + + private MutableAuthenticationService authenticationService; + private ContentService contentService; + private TransactionService transactionService; + private PersonService personService; + private NodeService nodeService; + private UserUsageTrackingComponent userUsageTrackingComponent; + private ContentUsageService contentUsageService; + + private UserTransaction testTX; + + public static StoreRef SPACES_STORE = new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore"); + + private static final String TEST_RUN = System.currentTimeMillis()+""; + private static final String TEST_USER_PREFIX = "user-"+TEST_RUN+"-"; + + private static final int MAX_USERS = 5; + private static final int BATCH_SIZE = 5; + private static final int PROGRESS_SIZE = 100; + + protected void setUp() throws Exception + { + nodeService = (NodeService)applicationContext.getBean("NodeService"); + authenticationService = (MutableAuthenticationService)applicationContext.getBean("authenticationService"); + transactionService = (TransactionService)applicationContext.getBean("transactionComponent"); + personService = (PersonService)applicationContext.getBean("PersonService"); + contentService = (ContentService)applicationContext.getBean("ContentService"); + contentUsageService = (ContentUsageService)applicationContext.getBean("ContentUsageService"); + + userUsageTrackingComponent = (UserUsageTrackingComponent)applicationContext.getBean("userUsageTrackingComponent"); + + AuthenticationUtil.setRunAsUserSystem(); + + createUsersAndContent(); + } + + protected void tearDown() throws Exception + { + if (clean) + { + deleteUsersAndContent(); + } + + super.tearDown(); + } + + private void createUsersAndContent() + { + long start = System.currentTimeMillis(); + long progressStart = System.currentTimeMillis(); + + try + { + int count = 0; + int batch = 0; + //long batchStart = 0; + + for (int i = 1; i <= MAX_USERS; i++) + { + if (count == 0) + { + batch++; + + testTX = transactionService.getUserTransaction(); + testTX.begin(); + + //batchStart = System.currentTimeMillis(); + } + + count++; + String userName = TEST_USER_PREFIX+i; + + if (! authenticationService.authenticationExists(userName)) + { + // Note: this will auto-create the user home + HashMap props = new HashMap(); + props.put(ContentModel.PROP_USERNAME, userName); + personService.createPerson(props); + + authenticationService.createAuthentication(userName, userName.toCharArray()); + + NodeRef homeFolder = getHomeSpaceFolderNode(userName); + + StringBuilder sb = new StringBuilder(); + for (int j = 1; j <= i; j++) + { + int k = j % 10; + sb.append(k); + } + + AuthenticationUtil.setFullyAuthenticatedUser(userName); + + addTextContent(homeFolder, "a-"+userName+".txt", sb.toString()); + addTextContent(homeFolder, "b-"+userName+".txt", sb.toString()); + } + + AuthenticationUtil.setRunAsUserSystem(); + + if ((count == BATCH_SIZE) || (i == MAX_USERS)) + { + testTX.commit(); + count = 0; + + //System.out.println("Batch "+batch+" took "+((System.currentTimeMillis()-batchStart)/1000)+" secs"); + } + + if (((i % PROGRESS_SIZE) == 0) && (i != MAX_USERS)) + { + System.out.println("Progress: "+PROGRESS_SIZE+" users created in "+((System.currentTimeMillis()-progressStart)/1000)+" secs"); + progressStart = System.currentTimeMillis(); + } + } + + System.out.println("Total: "+MAX_USERS+" users created in "+((System.currentTimeMillis()-start)/1000)+" secs"); + } + catch (Throwable t) + { + t.printStackTrace(); + + try { testTX.rollback(); } catch (Exception e) { e.printStackTrace(); } + } + } + + public void testEnableDisableCollapse() + { + userUsageTrackingComponent.setEnabled(false); + userUsageTrackingComponent.bootstrapInternal(); // false => clear + + System.out.println("Cleared usages"); + + checkCleared(); + + userUsageTrackingComponent.setEnabled(true); + userUsageTrackingComponent.bootstrapInternal(); // true => recalculate + + System.out.println("Recalculated usages"); + + checkCalculated(2L); + + checkUsage(2L); + + // add content + for (int i = 1; i <= MAX_USERS; i++) + { + String userName = TEST_USER_PREFIX+i; + + NodeRef homeFolder = getHomeSpaceFolderNode(userName); + + AuthenticationUtil.setFullyAuthenticatedUser(userName); + + StringBuilder sb = new StringBuilder(); + for (int j = 1; j <= i; j++) + { + int k = j % 10; + sb.append(k); + } + + addTextContent(homeFolder, "c-"+userName+".txt", sb.toString()); + addTextContent(homeFolder, "d-"+userName+".txt", sb.toString()); + + AuthenticationUtil.setRunAsUserSystem(); + } + + System.out.println("Added content"); + + checkUsage(4L); + + userUsageTrackingComponent.execute(); // collapse usages + + System.out.println("Collapsed usages"); + + checkUsage(4L); + + // delete content + for (int i = 1; i <= MAX_USERS; i++) + { + String userName = TEST_USER_PREFIX+i; + + NodeRef homeFolder = getHomeSpaceFolderNode(userName); + + AuthenticationUtil.setFullyAuthenticatedUser(userName); + + NodeRef childNodeRef = nodeService.getChildByName(homeFolder, ContentModel.ASSOC_CONTAINS, "a-"+userName+".txt"); + nodeService.deleteNode(childNodeRef); + + childNodeRef = nodeService.getChildByName(homeFolder, ContentModel.ASSOC_CONTAINS, "b-"+userName+".txt"); + nodeService.deleteNode(childNodeRef); + + AuthenticationUtil.setRunAsUserSystem(); + } + + System.out.println("Deleted content"); + + checkUsage(2L); + + userUsageTrackingComponent.execute(); // collapse usages + + System.out.println("Collapsed usages"); + + checkUsage(2L); + + userUsageTrackingComponent.setEnabled(false); + userUsageTrackingComponent.bootstrapInternal(); // false => clear + + System.out.println("Cleared usages"); + checkCleared(); + } + + private void checkCalculated(long factor) + { + for (int i = 1; i <= MAX_USERS; i++) + { + String userName = TEST_USER_PREFIX+i; + NodeRef personNodeRef = personService.getPerson(userName); + + // get user stored usage (not including deltas, if any) + Long sizeProp = (Long)nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT); + assertNotNull("Property " + ContentModel.PROP_SIZE_CURRENT + "does not exist, yet", sizeProp); + assertEquals(userName, i*factor, sizeProp.longValue()); + } + } + + private void checkUsage(long factor) + { + for (int i = 1; i <= MAX_USERS; i++) + { + String userName = TEST_USER_PREFIX+i; + + // get user usage (including deltas, if any) + assertEquals(userName, i*factor, contentUsageService.getUserUsage(userName)); + } + } + + private void checkCleared() + { + for (int i = 1; i <= MAX_USERS; i++) + { + String userName = TEST_USER_PREFIX+i; + NodeRef personNodeRef = personService.getPerson(userName); + + assertNull(nodeService.getProperty(personNodeRef, ContentModel.PROP_SIZE_CURRENT)); + } + } + + private void deleteUsersAndContent() + { + long start = System.currentTimeMillis(); + + try + { + int count = 0; + int batch = 0; + //long batchStart = 0; + + int deleteCount = 0; + + for (int i = 1; i <= MAX_USERS; i++) + { + if (count == 0) + { + batch++; + + testTX = transactionService.getUserTransaction(); + testTX.begin(); + //batchStart = System.currentTimeMillis(); + } + + count++; + String userName = TEST_USER_PREFIX+i; + + + if (authenticationService.authenticationExists(userName)) + { + NodeRef homeFolder = getHomeSpaceFolderNode(userName); + nodeService.deleteNode(homeFolder); + + personService.deletePerson(userName); + deleteCount++; + } + + if ((count == BATCH_SIZE) || (i == MAX_USERS)) + { + testTX.commit(); + count = 0; + + //System.out.println("Batch "+batch+" took "+((System.currentTimeMillis()-batchStart)/1000)+" secs"); + } + } + + System.out.println("Total: "+deleteCount+" users deleted in "+((System.currentTimeMillis()-start)/1000)+" secs"); + } + catch (Throwable t) + { + t.printStackTrace(); + + try { testTX.rollback(); } catch (Exception e) { e.printStackTrace(); } + } + } + + private NodeRef getHomeSpaceFolderNode(String userName) + { + return (NodeRef)this.nodeService.getProperty(personService.getPerson(userName), ContentModel.PROP_HOMEFOLDER); + } + + private NodeRef addTextContent(NodeRef spaceRef, String fileName, String textData) + { + Map contentProps = new HashMap(); + contentProps.put(ContentModel.PROP_NAME, fileName); + + ChildAssociationRef association = nodeService.createNode(spaceRef, + ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, fileName), + ContentModel.TYPE_CONTENT, + contentProps); + + NodeRef content = association.getChildRef(); + + // add titled aspect (for Web Client display) + Map titledProps = new HashMap(); + titledProps.put(ContentModel.PROP_TITLE, fileName); + titledProps.put(ContentModel.PROP_DESCRIPTION, fileName); + this.nodeService.addAspect(content, ContentModel.ASPECT_TITLED, titledProps); + + ContentWriter writer = contentService.getWriter(content, ContentModel.PROP_CONTENT, true); + + writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN); + writer.setEncoding("UTF-8"); + + writer.putContent(textData); + + return content; + } +} diff --git a/source/java/org/alfresco/repo/version/VersionMigrator.java b/source/java/org/alfresco/repo/version/VersionMigrator.java index 7043c0e71b..c2950d8f91 100644 --- a/source/java/org/alfresco/repo/version/VersionMigrator.java +++ b/source/java/org/alfresco/repo/version/VersionMigrator.java @@ -224,7 +224,7 @@ public class VersionMigrator implements ApplicationEventPublisherAware Date versionModified = (Date)dbNodeService.getProperty(versionNode, ContentModel.PROP_MODIFIED); String versionModifier = (String)dbNodeService.getProperty(versionNode, ContentModel.PROP_MODIFIER); Date versionAccessed = (Date)dbNodeService.getProperty(versionNode, ContentModel.PROP_ACCESSED); - + Map versionMetaDataProperties = version1Service.getVersionMetaData(versionNode); // Create the node details @@ -236,6 +236,13 @@ public class VersionMigrator implements ApplicationEventPublisherAware nodeDetails.addProperty(sourceType, entry.getKey(), entry.getValue()); } + // add newVersion auditable properties (of the version node itself, rather than the live versioned node) - will be set on create + nodeDetails.addProperty(sourceType, ContentModel.PROP_CREATED, versionCreated); + nodeDetails.addProperty(sourceType, ContentModel.PROP_CREATOR, versionCreator); + nodeDetails.addProperty(sourceType, ContentModel.PROP_MODIFIED, versionModified); + nodeDetails.addProperty(sourceType, ContentModel.PROP_MODIFIER, versionModifier); + nodeDetails.addProperty(sourceType, ContentModel.PROP_ACCESSED, versionAccessed); + // add aspects for (QName aspect : nodeAspects) { @@ -275,15 +282,6 @@ public class VersionMigrator implements ApplicationEventPublisherAware versionNumber, nodeDetails); - // set newVersion auditable properties (of the version node itself, rather than the live versioned node) - Map props = dbNodeService.getProperties(newVersionRef); - props.put(ContentModel.PROP_CREATED, versionCreated); - props.put(ContentModel.PROP_CREATOR, versionCreator); - props.put(ContentModel.PROP_MODIFIED, versionModified); - props.put(ContentModel.PROP_MODIFIER, versionModifier); - props.put(ContentModel.PROP_ACCESSED, versionAccessed); - dbNodeService.setProperties(newVersionRef, props); - return newVersionRef; } @@ -384,8 +382,8 @@ public class VersionMigrator implements ApplicationEventPublisherAware public Boolean migrateVersions(int batchSize, int threadCount, int limit, final boolean deleteImmediately, final String lockToken, boolean isRunningAsJob) { final NodeRef oldRootNodeRef = dbNodeService.getRootNode(VersionMigrator.VERSION_STORE_REF_OLD); - final NodeRef newRootNodeRef = dbNodeService.getRootNode(VersionMigrator.VERSION_STORE_REF_NEW); - + final NodeRef newRootNodeRef = dbNodeService.getRootNode(VersionMigrator.VERSION_STORE_REF_NEW); + refreshLock(lockToken); long startTime = System.currentTimeMillis(); @@ -406,7 +404,7 @@ public class VersionMigrator implements ApplicationEventPublisherAware migrationComplete = false; - if (logger.isInfoEnabled()) + if (logger.isInfoEnabled()) { logger.info("Found "+childAssocRefs.size()+" version histories in old version store (in "+((System.currentTimeMillis()-startTime)/1000)+" secs)"); } @@ -419,21 +417,21 @@ public class VersionMigrator implements ApplicationEventPublisherAware long splitTime = System.currentTimeMillis(); boolean firstMigration = false; - + if (! isRunningAsJob) - { + { List newChildAssocRefs = getVersionHistories(newRootNodeRef); firstMigration = (newChildAssocRefs.size() == 0); if (logger.isInfoEnabled()) - { + { if (! firstMigration) { logger.warn("This is not the first migration attempt. Found "+newChildAssocRefs.size()+" version histories in new version store (in "+((System.currentTimeMillis()-splitTime)/1000)+" secs)"); } - } - } - + } + } + // note: assumes patch runs before cleanup starts int alreadyMigratedCount = 0; @@ -472,20 +470,20 @@ public class VersionMigrator implements ApplicationEventPublisherAware for (final ChildAssociationRef childAssocRef : childAssocRefs) { - // short-cut if first migration - if (!firstMigration) + // short-cut if first migration + if (!firstMigration) { - if (isMigrated(childAssocRef)) - { - // skip - already migrated - alreadyMigratedCount++; - continue; - } + if (isMigrated(childAssocRef)) + { + // skip - already migrated + alreadyMigratedCount++; + continue; + } } toMigrateCount++; - if (tmpBatch.size() < batchSize) + if (tmpBatch.size() < batchSize) { tmpBatch.add(childAssocRef.getChildRef()); } @@ -627,7 +625,7 @@ public class VersionMigrator implements ApplicationEventPublisherAware MLPropertyInterceptor.setMLAware(wasMLAware); SessionSizeResourceManager.setEnableInTransaction(); } - + return migrationComplete; } @@ -674,7 +672,7 @@ public class VersionMigrator implements ApplicationEventPublisherAware int notMigratedCount = 0; int batchErrorCount = 0; int batchCount = 0; - + boolean wasMLAware = MLPropertyInterceptor.setMLAware(true); SessionSizeResourceManager.setDisableInTransaction(); @@ -696,7 +694,7 @@ public class VersionMigrator implements ApplicationEventPublisherAware totalCount++; if (! isMigrated(childAssocRef)) - { + { notMigratedCount++; } else @@ -800,8 +798,8 @@ public class VersionMigrator implements ApplicationEventPublisherAware } } - protected boolean isMigrated(ChildAssociationRef vhChildAssocRef) - { - return (((String)dbNodeService.getProperty(vhChildAssocRef.getChildRef(), ContentModel.PROP_NAME)).startsWith(VersionMigrator.PREFIX_MIGRATED)); - } + protected boolean isMigrated(ChildAssociationRef vhChildAssocRef) + { + return (((String)dbNodeService.getProperty(vhChildAssocRef.getChildRef(), ContentModel.PROP_NAME)).startsWith(VersionMigrator.PREFIX_MIGRATED)); + } } diff --git a/source/java/org/alfresco/repo/version/VersionMigratorTest.java b/source/java/org/alfresco/repo/version/VersionMigratorTest.java index 9cd332872b..45cae9d054 100644 --- a/source/java/org/alfresco/repo/version/VersionMigratorTest.java +++ b/source/java/org/alfresco/repo/version/VersionMigratorTest.java @@ -168,21 +168,21 @@ public class VersionMigratorTest extends BaseVersionStoreTest assertTrue(""+key, newVersionAspects.contains(key)); } - // TODO review against latest merges - /* - assertEquals(oldVersionProps.size(), newVersionProps.size()); - for (QName key : oldVersionProps.keySet()) + // note: since 3.4, "cm:accessed" is not returned/migrated if null + int expectedPropCount = oldVersionProps.size(); + + if (oldVersionProps.get(ContentModel.PROP_ACCESSED) == null) { - assertEquals(""+key, oldVersionProps.get(key), newVersionProps.get(key)); + expectedPropCount--; } - */ - assertEquals(oldVersionProps.size(), newVersionProps.size()+1); + + assertEquals(expectedPropCount, newVersionProps.size()); for (QName key : oldVersionProps.keySet()) { - if (! key.equals(ContentModel.PROP_ACCESSED)) - { - assertEquals(""+key, oldVersionProps.get(key), newVersionProps.get(key)); - } + if (! (key.equals(ContentModel.PROP_ACCESSED) && (oldVersionProps.get(key) == null))) + { + assertEquals(""+key, oldVersionProps.get(key), newVersionProps.get(key)); + } } // ALFCOM-2658 diff --git a/source/java/org/alfresco/repo/version/common/VersionHistoryImpl.java b/source/java/org/alfresco/repo/version/common/VersionHistoryImpl.java index b78e708c42..3270727d7a 100644 --- a/source/java/org/alfresco/repo/version/common/VersionHistoryImpl.java +++ b/source/java/org/alfresco/repo/version/common/VersionHistoryImpl.java @@ -18,14 +18,15 @@ */ package org.alfresco.repo.version.common; -import java.io.IOException; -import java.io.ObjectInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; import java.io.Serializable; -import java.io.ObjectInputStream.GetField; +import java.io.ObjectInputStream.GetField; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.Date; import java.util.HashMap; import java.util.List; @@ -33,7 +34,10 @@ import org.alfresco.service.cmr.version.Version; import org.alfresco.service.cmr.version.VersionDoesNotExistException; import org.alfresco.service.cmr.version.VersionHistory; import org.alfresco.service.cmr.version.VersionServiceException; +import org.alfresco.util.EqualsHelper; import org.alfresco.util.VersionNumber; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; /** * Version History implementation. @@ -42,18 +46,19 @@ import org.alfresco.util.VersionNumber; */ public class VersionHistoryImpl implements VersionHistory { + private static Log logger = LogFactory.getLog(VersionHistoryImpl.class); + private static final long serialVersionUID = 3257001051558326840L; - /* * Error message(s) */ private static final String ERR_MSG = "The root version must be specified when creating a version history object."; /* - * Field is left here to aid in detection of old serialized versions + * Field is left here to aid in detection of old serialized versions */ - @SuppressWarnings("unused") - private transient List versions; + @SuppressWarnings("unused") + private transient List versions; /* * Version history tree structure map @@ -131,10 +136,10 @@ public class VersionHistoryImpl implements VersionHistory */ public Collection getAllVersions() { - Collection versions = versionsByLabel.values(); - List sortedVersions = new ArrayList(versions); - Collections.sort(sortedVersions, versionComparatorDesc); - return sortedVersions; + Collection versions = versionsByLabel.values(); + List sortedVersions = new ArrayList(versions); + Collections.sort(sortedVersions, versionComparatorDesc); + return sortedVersions; } /** @@ -171,7 +176,7 @@ public class VersionHistoryImpl implements VersionHistory { for (String key : this.versionHistory.keySet()) { - if (this.versionHistory.get(key) == versionLabel) + if (EqualsHelper.nullSafeEquals(this.versionHistory.get(key), versionLabel)) { result.add(getVersion(key)); } @@ -229,7 +234,7 @@ public class VersionHistoryImpl implements VersionHistory /** * Version Comparator * - * Note: Descending (last modified) date order + * Note: Descending (last modified) date order */ public static class VersionComparatorDesc implements Comparator, Serializable { @@ -237,7 +242,18 @@ public class VersionHistoryImpl implements VersionHistory public int compare(Version v1, Version v2) { - int result = v2.getFrozenModifiedDate().compareTo(v1.getFrozenModifiedDate()); + Date v1Date = v1.getFrozenModifiedDate(); + Date v2Date = v2.getFrozenModifiedDate(); + int result = 0; + if ((v1Date != null) && (v2Date != null)) + { + result = v2.getFrozenModifiedDate().compareTo(v1.getFrozenModifiedDate()); + } + else + { + logger.warn("Missing frozen modified date"); + } + if (result == 0) { result = new VersionNumber(v2.getVersionLabel()).compareTo(new VersionNumber(v1.getVersionLabel())); @@ -249,7 +265,7 @@ public class VersionHistoryImpl implements VersionHistory /** * Version Comparator * - * Note: Ascending (last modified) date order + * Note: Ascending (last modified) date order */ public static class VersionComparatorAsc implements Comparator, Serializable { @@ -257,7 +273,18 @@ public class VersionHistoryImpl implements VersionHistory public int compare(Version v1, Version v2) { - int result = v1.getFrozenModifiedDate().compareTo(v2.getFrozenModifiedDate()); + Date v1Date = v1.getFrozenModifiedDate(); + Date v2Date = v2.getFrozenModifiedDate(); + int result = 0; + if ((v1Date != null) && (v2Date != null)) + { + result = v1.getFrozenModifiedDate().compareTo(v2.getFrozenModifiedDate()); + } + else + { + logger.warn("Missing frozen modified date"); + } + if (result == 0) { result = new VersionNumber(v1.getVersionLabel()).compareTo(new VersionNumber(v2.getVersionLabel())); @@ -266,29 +293,29 @@ public class VersionHistoryImpl implements VersionHistory } } - @SuppressWarnings("unchecked") - private void readObject(ObjectInputStream is) throws ClassNotFoundException, IOException - { - GetField fields = is.readFields(); - if (fields.defaulted("versionsByLabel")) - { - // This is a V2.2 class - // The old 'rootVersion' maps to the current 'rootVersion' - this.rootVersion = (Version) fields.get("rootVersion", null);; - // The old 'versions' maps to the current 'versionsByLabel' - this.versionsByLabel = (HashMap) fields.get("versions", new HashMap()); - // The old 'versionHistory' maps to the current 'versionHistory' - this.versionHistory = (HashMap) fields.get("versionHistory", new HashMap()); - } - else - { - // This is a V3.1.0 to ... class - // The old 'rootVersion' maps to the current 'rootVersion' - this.rootVersion = (Version) fields.get("rootVersion", null); - // The old 'versionsByLabel' maps to the current 'versionsByLabel' - this.versionsByLabel = (HashMap) fields.get("versionsByLabel", new HashMap()); - // The old 'versionHistory' maps to the current 'versionHistory' - this.versionHistory = (HashMap) fields.get("versionHistory", new HashMap()); - } - } + @SuppressWarnings("unchecked") + private void readObject(ObjectInputStream is) throws ClassNotFoundException, IOException + { + GetField fields = is.readFields(); + if (fields.defaulted("versionsByLabel")) + { + // This is a V2.2 class + // The old 'rootVersion' maps to the current 'rootVersion' + this.rootVersion = (Version) fields.get("rootVersion", null);; + // The old 'versions' maps to the current 'versionsByLabel' + this.versionsByLabel = (HashMap) fields.get("versions", new HashMap()); + // The old 'versionHistory' maps to the current 'versionHistory' + this.versionHistory = (HashMap) fields.get("versionHistory", new HashMap()); + } + else + { + // This is a V3.1.0 to ... class + // The old 'rootVersion' maps to the current 'rootVersion' + this.rootVersion = (Version) fields.get("rootVersion", null); + // The old 'versionsByLabel' maps to the current 'versionsByLabel' + this.versionsByLabel = (HashMap) fields.get("versionsByLabel", new HashMap()); + // The old 'versionHistory' maps to the current 'versionHistory' + this.versionHistory = (HashMap) fields.get("versionHistory", new HashMap()); + } + } } diff --git a/source/java/org/alfresco/service/cmr/attributes/AttrAndQuery.java b/source/java/org/alfresco/service/cmr/attributes/AttrAndQuery.java deleted file mode 100644 index 5581b207c2..0000000000 --- a/source/java/org/alfresco/service/cmr/attributes/AttrAndQuery.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.attributes; - -import java.util.ArrayList; -import java.util.List; - -/** - * And aggregate query. - * @author britt - */ -public class AttrAndQuery extends AttrQuery -{ - private static final long serialVersionUID = 5452165715643751502L; - - private List fSubQueries; - - public AttrAndQuery(List queries) - { - fSubQueries = queries; - } - - public AttrAndQuery(AttrQuery... queries) - { - fSubQueries = new ArrayList(); - for (AttrQuery query : queries) - { - fSubQueries.add(query); - } - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttrQuery#getPredicate(org.alfresco.service.cmr.attributes.AttrQueryHelper) - */ - @Override - public String getPredicate(AttrQueryHelper helper) - { - StringBuilder builder = new StringBuilder(); - builder.append('('); - for (int i = 0; i < fSubQueries.size() - 1; i++) - { - builder.append(fSubQueries.get(i).getPredicate(helper)); - builder.append(" and "); - } - builder.append(fSubQueries.get(fSubQueries.size() - 1).getPredicate(helper)); - builder.append(')'); - return builder.toString(); - } -} diff --git a/source/java/org/alfresco/service/cmr/attributes/AttrNotQuery.java b/source/java/org/alfresco/service/cmr/attributes/AttrNotQuery.java deleted file mode 100644 index e5f0222148..0000000000 --- a/source/java/org/alfresco/service/cmr/attributes/AttrNotQuery.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.attributes; - -/** - * The negation of a sub query. - * @author britt - */ -public class AttrNotQuery extends AttrQuery -{ - private static final long serialVersionUID = -7798693028454128695L; - - private AttrQuery fSubQuery; - - public AttrNotQuery(AttrQuery sub) - { - fSubQuery = sub; - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttrQuery#getPredicate(org.alfresco.service.cmr.attributes.AttrQueryHelper) - */ - @Override - public String getPredicate(AttrQueryHelper helper) - { - StringBuilder builder = new StringBuilder(); - builder.append("(not "); - builder.append(fSubQuery.getPredicate(helper)); - builder.append(')'); - return builder.toString(); - } -} diff --git a/source/java/org/alfresco/service/cmr/attributes/AttrOrQuery.java b/source/java/org/alfresco/service/cmr/attributes/AttrOrQuery.java deleted file mode 100644 index e47d723be9..0000000000 --- a/source/java/org/alfresco/service/cmr/attributes/AttrOrQuery.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.attributes; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author britt - * - */ -public class AttrOrQuery extends AttrQuery -{ - private static final long serialVersionUID = 2295618804175882547L; - - private List fSubQueries; - - public AttrOrQuery(List queries) - { - fSubQueries = queries; - } - - public AttrOrQuery(AttrQuery... queries) - { - fSubQueries = new ArrayList(); - for (AttrQuery query : queries) - { - fSubQueries.add(query); - } - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttrQuery#getPredicate(int) - */ - @Override - public String getPredicate(AttrQueryHelper helper) - { - StringBuilder builder = new StringBuilder(); - builder.append('('); - for (int i = 0; i < fSubQueries.size() - 1; i++) - { - builder.append(fSubQueries.get(i).getPredicate(helper)); - builder.append(" or "); - } - builder.append(fSubQueries.get(fSubQueries.size() - 1).getPredicate(helper)); - builder.append(')'); - return builder.toString(); - } -} diff --git a/source/java/org/alfresco/service/cmr/attributes/AttrQuery.java b/source/java/org/alfresco/service/cmr/attributes/AttrQuery.java deleted file mode 100644 index d97fe36a02..0000000000 --- a/source/java/org/alfresco/service/cmr/attributes/AttrQuery.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.attributes; - -import java.io.Serializable; - -/** - * Abstract base class for Attribute Query nodes. - * @author britt - */ -public abstract class AttrQuery implements Serializable -{ - protected String fValue; - - protected AttrQuery() - { - } - - protected AttrQuery(String value) - { - fValue = value; - } - - /** - * Get the predicate that goes into a Hibernate query. - * @return The predicate. - */ - public abstract String getPredicate(AttrQueryHelper helper); -} diff --git a/source/java/org/alfresco/service/cmr/attributes/AttrQueryEquals.java b/source/java/org/alfresco/service/cmr/attributes/AttrQueryEquals.java deleted file mode 100644 index 402c74124a..0000000000 --- a/source/java/org/alfresco/service/cmr/attributes/AttrQueryEquals.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.attributes; - -/** - * The equals predicate. - * @author britt - */ -public class AttrQueryEquals extends AttrQuery -{ - private static final long serialVersionUID = 2180915053803244460L; - - public AttrQueryEquals(String name) - { - super(name); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttrQuery#getPredicate() - */ - @Override - public String getPredicate(AttrQueryHelper helper) - { - String name = "name" + helper.getNextSuffix(); - helper.setParameter(name, fValue); - return "me.key.key = :" + name; - } -} diff --git a/source/java/org/alfresco/service/cmr/attributes/AttrQueryGT.java b/source/java/org/alfresco/service/cmr/attributes/AttrQueryGT.java deleted file mode 100644 index 34fa57e251..0000000000 --- a/source/java/org/alfresco/service/cmr/attributes/AttrQueryGT.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.attributes; - -/** - * Greater than query. - * @author britt - */ -public class AttrQueryGT extends AttrQuery -{ - private static final long serialVersionUID = 3171792743187950462L; - - /** - * @param name - */ - public AttrQueryGT(String name) - { - super(name); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttrQuery#getPredicate() - */ - @Override - public String getPredicate(AttrQueryHelper helper) - { - String name = "name" + helper.getNextSuffix(); - helper.setParameter(name, fValue); - return "me.key.key > :" + name; - } -} diff --git a/source/java/org/alfresco/service/cmr/attributes/AttrQueryGTE.java b/source/java/org/alfresco/service/cmr/attributes/AttrQueryGTE.java deleted file mode 100644 index 992a92a1eb..0000000000 --- a/source/java/org/alfresco/service/cmr/attributes/AttrQueryGTE.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.attributes; - - -/** - * Greater than or equals predicate. - * @author britt - */ -public class AttrQueryGTE extends AttrQuery -{ - private static final long serialVersionUID = -7957078449719425057L; - - /** - * @param name - */ - public AttrQueryGTE(String name) - { - super(name); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttrQuery#getPredicate() - */ - @Override - public String getPredicate(AttrQueryHelper helper) - { - String name = "name" + helper.getNextSuffix(); - helper.setParameter(name, fValue); - return "me.key.key >= :" + name; - } -} diff --git a/source/java/org/alfresco/service/cmr/attributes/AttrQueryHelper.java b/source/java/org/alfresco/service/cmr/attributes/AttrQueryHelper.java deleted file mode 100644 index bf01d84185..0000000000 --- a/source/java/org/alfresco/service/cmr/attributes/AttrQueryHelper.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.attributes; - -import java.util.Map; - -/** - * An implementation of this is passed into an AttrQuery to aid it - * in generating the actual predicate. - * @author britt - */ -public interface AttrQueryHelper -{ - /** - * Get the next integer suffix for named arguments. - * @return The next integer suffix. - */ - public int getNextSuffix(); - - /** - * As an AttrQuery is generating the predicate, it - * tells this helper about its parameter names and bindings. - * @param name The name of the parameter - * @param value The binding. - */ - public void setParameter(String name, String value); - - /** - * Get the parameter bindings for a generated predicate. - * @return The parameter bindings. - */ - public Map getParameters(); -} diff --git a/source/java/org/alfresco/service/cmr/attributes/AttrQueryLT.java b/source/java/org/alfresco/service/cmr/attributes/AttrQueryLT.java deleted file mode 100644 index 8f45dfd95a..0000000000 --- a/source/java/org/alfresco/service/cmr/attributes/AttrQueryLT.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.attributes; - -/** - * Query a less than condition. - * @author britt - */ -public class AttrQueryLT extends AttrQuery -{ - private static final long serialVersionUID = -2385160490778425115L; - - /** - * @param name - */ - public AttrQueryLT(String name) - { - super(name); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttrQuery#getPredicate() - */ - @Override - public String getPredicate(AttrQueryHelper helper) - { - String name = "name" + helper.getNextSuffix(); - helper.setParameter(name, fValue); - return "me.key.key < :" + name; - } -} diff --git a/source/java/org/alfresco/service/cmr/attributes/AttrQueryLTE.java b/source/java/org/alfresco/service/cmr/attributes/AttrQueryLTE.java deleted file mode 100644 index 39b164f7f3..0000000000 --- a/source/java/org/alfresco/service/cmr/attributes/AttrQueryLTE.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.attributes; - -/** - * Less than or equal query - * @author britt - */ -public class AttrQueryLTE extends AttrQuery -{ - private static final long serialVersionUID = -7735611069499505767L; - - /** - * @param value - */ - public AttrQueryLTE(String value) - { - super(value); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttrQuery#getPredicate() - */ - @Override - public String getPredicate(AttrQueryHelper helper) - { - String name = "name" + helper.getNextSuffix(); - helper.setParameter(name, fValue); - return "me.key.key <= :" + name; - } -} diff --git a/source/java/org/alfresco/service/cmr/attributes/AttrQueryLike.java b/source/java/org/alfresco/service/cmr/attributes/AttrQueryLike.java deleted file mode 100644 index 156629e9b0..0000000000 --- a/source/java/org/alfresco/service/cmr/attributes/AttrQueryLike.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.attributes; - - -/** - * A "like" query. - * @author britt - */ -public class AttrQueryLike extends AttrQuery -{ - private static final long serialVersionUID = -984397014171296687L; - - /** - * @param name - */ - public AttrQueryLike(String name) - { - super(name); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttrQuery#getPredicate() - */ - @Override - public String getPredicate(AttrQueryHelper helper) - { - String name = "name" + helper.getNextSuffix(); - helper.setParameter(name, fValue); - return "me.key.key like :" + name; - } -} diff --git a/source/java/org/alfresco/service/cmr/attributes/AttrQueryNE.java b/source/java/org/alfresco/service/cmr/attributes/AttrQueryNE.java deleted file mode 100644 index 5cb035d2f4..0000000000 --- a/source/java/org/alfresco/service/cmr/attributes/AttrQueryNE.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.attributes; - -/** - * Not equals query. - * @author britt - */ -public class AttrQueryNE extends AttrQuery -{ - private static final long serialVersionUID = 103038173214972590L; - - /** - * @param name - */ - public AttrQueryNE(String name) - { - super(name); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.attributes.AttrQuery#getPredicate() - */ - @Override - public String getPredicate(AttrQueryHelper helper) - { - String name = "name" + helper.getNextSuffix(); - helper.setParameter(name, fValue); - return "me.key.key <> :" + name; - } -} diff --git a/source/java/org/alfresco/service/cmr/attributes/AttributeService.java b/source/java/org/alfresco/service/cmr/attributes/AttributeService.java index 39a15fee00..325d251019 100644 --- a/source/java/org/alfresco/service/cmr/attributes/AttributeService.java +++ b/source/java/org/alfresco/service/cmr/attributes/AttributeService.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,321 +14,122 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.attributes; - -import java.util.List; -import java.util.Map; - -import org.alfresco.repo.attributes.Attribute; -import org.alfresco.service.PublicService; -import org.alfresco.util.Pair; -import org.alfresco.service.Auditable; -import org.alfresco.service.NotAuditable; - -/** - * This provides services for reading, writing, and querying global attributes. - *

- * Attributes are organized hierarchically. - * Each segment within the hierarchy is referred to as a "key". - * Keys are indexed so that they may be queried efficiently. - * Because databases may impose length restrictions - * on index of primary keys, you are strongly advised to keep - * "large" strings in values, not keys. - * For example, - * http://dev.mysql.com/tech-resources/crash-me.php reports - * that the index length limit of MySQL-4.1.1pre InnoDB is 1024, - * bytes. Assuming keys are stored in UTF8, this means keys - * should be no longer 170 chars (170*6 + 1 = 1020 < 1024). - *

- * - * When an attribute within the hierarchy is represented as a "path", - * the set of keys used to reach it is concatenated using the '/' character. - * Thus, "a/b/c" refers to attribute "c" within "b" within "a". - * This "path" notation is merely a convenience; if you prefer, - * lower-level functions can also be used that allow you to - * supply the list of keys directly. If you need to create a "path" - * that includes a key with an embedded '/' character, you must - * escape it with '\' (e.g.: "silly\/example"). No such restriction - * applies when you use an API that accepts a list of keys directly. - *

- * Lookups for attributes never attempt to search any other - * leaf key (final path segment) than the one specified - * function call. Thus, if you have an attribute named - * "egg", but no attribute named "hen/egg", a lookup for - * "egg" will suceed, but a lookup for "hen/egg" will fail - * (i.e.: it will return null). - * - * @author britt - */ -@PublicService -public interface AttributeService -{ - /** - * Get an Attribute using a path. - * - * @param path The path of the Attribute - * @return The value of the attribute or null. - */ - @NotAuditable - public Attribute getAttribute(String path); - - /** - * Get an attribute using a list of keys. - * - * @param keys List of attribute path keys (path components). - * @return The value of the attribute or null. - */ - @NotAuditable - public Attribute getAttribute(List keys); - - /** - * Set an attribute, overwriting its prior value if it already existed. - * - * @param name The name of the Attribute. - * @param value The value to set. - */ - @NotAuditable - public void setAttribute(String path, String name, Attribute value); - - /** - * Set an attribute, overwriting its prior value if it already existed. - * - * @param keys List of attribute path keys (path components). - * @param name The name of the attribute to set. - * @param value The Attribute to set. - */ - @NotAuditable - public void setAttribute(List keys, String name, Attribute value); - - /** - * Set a set of attributes on a map. - * @param path The path to the map. - * @param entries The entries to set. - */ - @NotAuditable - public void setAttributes(String path, Map entries); - - /** - * Set a set of attributes on a map. - * @param keys The List of path keys to the map. - * @param entries The entries to set. - */ - @NotAuditable - public void setAttributes(List keys, Map entries); - - /** - * Set an attribute in a list. - * - * @param path The path to the {@link org.alfresco.repo.attributes.ListAttribute ListAttribute}. - * @param index The list index. - * @param value The Attribute to set. - */ - @NotAuditable - public void setAttribute(String path, int index, Attribute value); - - /** - * Set an attribute in a list. - * @param keys List of attribute path keys (path components). - * @param index The list index. - * @param value The Attribute to set within the {@link org.alfresco.repo.attributes.ListAttribute ListAttribute} - */ - @NotAuditable - public void setAttribute(List keys, int index, Attribute value); - - /** - * Add an attribute to a list. - * - * @param path The path to the list. - * @param value The Attribute to add to the {@link org.alfresco.repo.attributes.ListAttribute ListAttribute} - */ - @NotAuditable - public void addAttribute(String path, Attribute value); - - /** - * Add an attribute to a list. - * - * @param keys List of attribute path keys (path components). - * @param value The Attribute to add to the {@link org.alfresco.repo.attributes.ListAttribute ListAttribute} - */ - @NotAuditable - public void addAttribute(List keys, Attribute value); - - /** - * Add a list of attributes to the end of a list. - * @param path The path to the list. - * @param values The values to add. - */ - @NotAuditable - public void addAttributes(String path, List values); - - /** - * Add a list of attributes to the end of a list. - * @param keys The List of path keys to the list. - * @param values The values to add. - */ - @NotAuditable - public void addAttributes(List keys, List values); - - /** - * Remove an Attribute. - * @param name The name of the Attribute. - */ - @NotAuditable - public void removeAttribute(String path, String name); - - /** - * Remove an Attribute. - * @param keys List of attribute path keys (path components). - * @param name The name of the attribute to remove. - */ - @NotAuditable - public void removeAttribute(List keys, String name); - - /** - * Remove an attribute from a list. - * @param path The path to the list. - * @param index The index to remove from the - * {@link org.alfresco.repo.attributes.ListAttribute ListAttribute} - */ - @NotAuditable - public void removeAttribute(String path, int index); - - /** - * Remove an attribute from a list. - * @param keys List of attribute path keys (path components). - * @param index The index to remove from the - * {@link org.alfresco.repo.attributes.ListAttribute ListAttribute} - */ - @NotAuditable - public void removeAttribute(List keys, int index); - - /** - * Remove entries from the designated map which match the given query. - * @param keys The list of attribute path entries. - * @param query The attribute query. - */ - @NotAuditable - public void removeEntries(List keys, AttrQuery query); - - /** - * Remove entries from the designated map which match the given query. - * @param path The path to the map. - * @param query The attribute query. - */ - @NotAuditable - public void removeEntries(String path, AttrQuery query); - - /** - * Query for the list of attributes that is contained in the map - * defined by the given path and meet the query criteria. - * - *

- * Example 1:
- * Find all attributes within the nested namespace "a/b" - * that are lexically greater than or equal to the string "v": - *

-     *          query("a/b", new AttrQueryGTE("v"))
-     * 
- *

- * Example 2:
- * Find all attributes within the namespace "xyz" that are - * either lexically less than the string "d" or greater than - * the string "w": - *

-     *           query("xyz", new AttrOrQuery(new AttrQueryLT("d"),
-     *                                        new AttrQueryGT("w")))
-     * 
- * - * @param path - * @param query - * @return A List of matching attributes. - */ - @NotAuditable - public List> query(String path, AttrQuery query); - - /** - * Query for a list of attributes which are contained in a map defined by the - * given path and meet the query criteria. - * @param keys List of attribute path keys (path components). - * @param query - * @return A list of matching attributes. - */ - @NotAuditable - public List> query(List keys, AttrQuery query); - - /** - * Get all the keys at a given attribute path. - * When prior call to - * {@link #setAttribute setAttribute} - * has associated a path with a - * {@link org.alfresco.repo.attributes.Attribute.Type#MAP MAP}, you can fetch the - * keys for that map via this function. - *

- * Example:
- * Suppose AttribSvc is an attribute service object:

-     *
-     *   MapAttribute x = new MapAttributeValue();
-     *   x.put("cow",  new StringAttributeValue("moo");
-     *   x.put("bird", new StringAttributeValue("tweet");
-     *  
-     *   MapAttribute y = new MapAttributeValue();
-     *   y.put("pekingese",    new StringAttributeValue("yip-yip-yip");
-     *   y.put("blood hound",  new StringAttributeValue("Aroooooooooooo");
-     *   y.put("labrador",     new StringAttributeValue("Hello, kind stranger!");
-     *
-     *   AttribSvc.setAttribute("",  "x", x);
-     *   AttribSvc.setAttribute("x", "y", y);
-     *
-     *   List<String> x_keys  = AttribSvc.getKeys("x");    // cow, bird
-     *   List<String> y_keys  = AttribSvc.getKeys("x/y");  // pekingese, blood hound, labrador
-     * 
- * - * @param path The attribute path. - * @return A list of all keys. - */ - @NotAuditable - public List getKeys(String path); - - /** - * Get all the keys at a given attribute path as specified by a list of path components. - * @param keys List of attribute path keys (path components). - * @return A list of all keys at the specified Attribute location - */ - @NotAuditable - public List getKeys(List keys); - - /** - * Get the size of a map or list. - * @param keys List of attribute path keys. - * @return The size of of the list or map. - */ - @NotAuditable - public int getCount(List keys); - - /** - * Get the size of a map or list. - * @param path The path to the map or list. - * @return The size of the list or map. - */ - @NotAuditable - public int getCount(String path); - - /** - * Does an attribute exist. - * @param keys List of attribute path keys. - * @return Whether the attribute exists. - */ - @NotAuditable - public boolean exists(List keys); - - /** - * Does an attribute exist. - * @param path The path to the attribute. - * @return Whether the attribute exists. - */ - @NotAuditable - public boolean exists(String path); -} + * along with Alfresco. If not, see . + */ +package org.alfresco.service.cmr.attributes; + +import java.io.Serializable; + +import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; + +/** + * This provides services for reading, writing, and querying global attributes. + *

+ * Attributes are uniquely identified by up to 3 keys; null keys are themselves treated uniquely i.e. + * ['a','b'] is equivalent to ['a','b',null] in all cases except where multiple search results + * are possible. Keys can be any simple Serializable type, typically being convertable using + * {@link DefaultTypeConverter}. The attribute values persisted can be any Serializable + * (including collections) but the raw values should be convertable by the {@link DefaultTypeConverter} for + * the most efficient persistence. + * + * @author Derek Hulley + * @since 3.4 + */ +public interface AttributeService +{ + /** + * Determine if a particular attribute exists. + * + * @param keys List of 1 to 3 keys to uniquely identify the attribute + * @return true if the attribute exists (regardless of its value) + * or false if it doesn't exist + */ + public boolean exists(Serializable ... keys); + + /** + * Get an attribute using a list of unique keys + * + * @param keys List of 1 to 3 keys to uniquely identify the attribute + * @return The attribute value or null + */ + public Serializable getAttribute(Serializable ... keys); + + /** + * Callback used for querying for lists of attributes. + * + * @author Derek Hulley + * @since 3.4 + */ + public interface AttributeQueryCallback + { + /** + * Handle an attribute value + * + * @param id the unique attribute ID + * @param value the value associated with the attribute + * @param keys the unique attribute keys + * @return true to continue sending results if any are available + */ + boolean handleAttribute(Long id, Serializable value, Serializable[] keys); + } + + /** + * Get all attributes that share the starter keys provided. If 3 key values are given, + * there can be, at most, one result. + * + * @param callback the callback that handles the results + * @param keys 0 to 3 key values to search against + */ + public void getAttributes(AttributeQueryCallback callback, Serializable ... keys); + + /** + * Set an attribute, overwriting its prior value if it already existed. null + * values are treated as unique i.e. if the value set is null then + * {@link #exists(String...)} will still return true. If the attribute doesn't + * exist, it will be created otherwise it will be modified. + * + * @param value The value to store (can be a collection or null) + * @param keys List of 1 to 3 keys to uniquely identify the attribute + */ + public void setAttribute(Serializable value, Serializable ... keys); + + /** + * Create an attribute with an optional value, assuming there is no existing attribute + * using the same keys. + * + * @param value The value to store (can be a collection or null) + * @param keys List of 1 to 3 keys to uniquely identify the attribute + * + * @throws DuplicateAttributeException if the attribute already exists + */ + public void createAttribute(Serializable value, Serializable ... keys); + + /** + * Update an attribute key whilst preserving the associated value (if any). If there is + * no existing key matching the original value, then nothing will happen. + * + * @param keyBefore1 the first part of the original unique key (never null) + * @param keyBefore2 the second part of the original unique key (null allowed) + * @param keyBefore3 the third part of the original unique key (null allowed) + * @param keyAfter1 the first part of the new unique key (never null) + * @param keyAfter2 the second part of the new unique key (null allowed) + * @param keyAfter3 the third part of the new unique key (null allowed) + */ + public void updateOrCreateAttribute( + Serializable keyBefore1, Serializable keyBefore2, Serializable keyBefore3, + Serializable keyAfter1, Serializable keyAfter2, Serializable keyAfter3); + + /** + * Remove a specific attribute. + * + * @param keys up to 3 keys to uniquely identify the attribute + */ + public void removeAttribute(Serializable ... keys); + + /** + * Remove all attributes that share a set of keys (in order) + * + * @param keys up to 3 keys to identify attributes to remove + */ + public void removeAttributes(Serializable ... keys); +} diff --git a/source/java/org/alfresco/service/cmr/attributes/DuplicateAttributeException.java b/source/java/org/alfresco/service/cmr/attributes/DuplicateAttributeException.java new file mode 100644 index 0000000000..b46130d36f --- /dev/null +++ b/source/java/org/alfresco/service/cmr/attributes/DuplicateAttributeException.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.service.cmr.attributes; + +import java.io.Serializable; + +import org.alfresco.error.AlfrescoRuntimeException; + +/** + * Exception generated by attempting to create a duplicate attribute + * + * @author Derek Hulley + * @since 3.4 + */ +public class DuplicateAttributeException extends AlfrescoRuntimeException +{ + private static final long serialVersionUID = -3524390846515987837L; + + private final Serializable value1; + private final Serializable value2; + private final Serializable value3; + + public DuplicateAttributeException(Serializable value1, Serializable value2, Serializable value3, Throwable cause) + { + super("Non-unique values for attribute: " + value1 + "-" + value2 + "-" + value3, cause); + this.value1 = value1; + this.value2 = value2; + this.value3 = value3; + } + + public Serializable getValue1() + { + return value1; + } + + public Serializable getValue2() + { + return value2; + } + + public Serializable getValue3() + { + return value3; + } +} diff --git a/source/java/org/alfresco/service/cmr/avm/locking/AVMLock.java b/source/java/org/alfresco/service/cmr/avm/locking/AVMLock.java deleted file mode 100644 index 688cfad67b..0000000000 --- a/source/java/org/alfresco/service/cmr/avm/locking/AVMLock.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.avm.locking; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.alfresco.repo.attributes.Attribute; -import org.alfresco.repo.attributes.ListAttribute; -import org.alfresco.repo.attributes.ListAttributeValue; -import org.alfresco.repo.attributes.MapAttribute; -import org.alfresco.repo.attributes.MapAttributeValue; -import org.alfresco.repo.attributes.StringAttributeValue; - -/** - * Struct representing an AVM lock. - * @author britt - */ -public class AVMLock implements Serializable -{ - public static final String PATH = "path"; - public static final String STORE = "store"; - public static final String OWNERS = "owners"; - public static final String WEBPROJECT = "webproject"; - public static final String TYPE = "type"; - - private static final long serialVersionUID = -8026344276097527239L; - - /** - * The store relative path of the lock. - */ - private String fPath; - - /** - * The store of the actual locked version. - */ - private String fStore; - - /** - * The list of users who can access the locked asset. - */ - private List fOwners; - - /** - * The web project for which this lock applies. - */ - private String fWebProject; - - /** - * The type of the lock. - */ - private AVMLockingService.Type fType; - - public AVMLock(String webProject, - String store, - String path, - AVMLockingService.Type type, - List owners) - { - fWebProject = webProject; - fStore = store; - fPath = normalizePath(path); - fType = type; - fOwners = owners; - } - - public AVMLock(Attribute lockData) - { - fPath = lockData.get(PATH).getStringValue(); - fStore = lockData.get(STORE).getStringValue(); - fOwners = new ArrayList(); - for (Attribute owner : lockData.get(OWNERS)) - { - fOwners.add(owner.getStringValue()); - } - fType = AVMLockingService.Type.valueOf(lockData.get(TYPE).getStringValue()); - fWebProject = lockData.get(WEBPROJECT).getStringValue(); - } - - public Attribute getAttribute() - { - MapAttribute lockData = new MapAttributeValue(); - lockData.put(PATH, new StringAttributeValue(fPath)); - lockData.put(STORE, new StringAttributeValue(fStore)); - lockData.put(TYPE, new StringAttributeValue(fType.name())); - lockData.put(WEBPROJECT, new StringAttributeValue(fWebProject)); - ListAttribute owners = new ListAttributeValue(); - for (String owner : fOwners) - { - owners.add(new StringAttributeValue(owner)); - } - lockData.put(OWNERS, owners); - return lockData; - } - - /** - * @return the owners - */ - public List getOwners() - { - return fOwners; - } - - /** - * @return the Path - */ - public String getPath() - { - return fPath; - } - - /** - * Set the path of this lock. - * @param path - */ - public void setPath(String path) - { - fPath = normalizePath(path); - } - - /** - * @return the Store - */ - public String getStore() - { - return fStore; - } - - /** - * Set the store of this lock. - * @param store - */ - public void setStore(String store) - { - fStore = store; - } - - /** - * @return the Type - */ - public AVMLockingService.Type getType() - { - return fType; - } - - /** - * @return the WebProject - */ - public String getWebProject() - { - return fWebProject; - } - - public String toString() - { - StringBuilder buffer = new StringBuilder(); - buffer.append(" (webproject=").append(this.fWebProject); - buffer.append(" store=").append(this.fStore); - buffer.append(" path=").append(this.fPath); - buffer.append(" type=").append(this.fType); - buffer.append(" owners=").append(this.fOwners).append(")"); - return buffer.toString(); - } - - /** - * Utility to get relative paths into canonical form. - * @param path The incoming path. - * @return The normalized path. - */ - private String normalizePath(String path) - { - while (path.startsWith("/")) - { - path = path.substring(1); - } - while (path.endsWith("/")) - { - path = path.substring(0, path.length() - 1); - } - return path.replaceAll("/+", "/"); - } -} diff --git a/source/java/org/alfresco/service/cmr/avm/locking/AVMLockingException.java b/source/java/org/alfresco/service/cmr/avm/locking/AVMLockingException.java index c58b79f262..60957876d4 100644 --- a/source/java/org/alfresco/service/cmr/avm/locking/AVMLockingException.java +++ b/source/java/org/alfresco/service/cmr/avm/locking/AVMLockingException.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,52 +14,28 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.avm.locking; - -import org.alfresco.service.cmr.avm.AVMException; - -/** - * Exception thrown when lock permission is denied. - * @author britt - */ -public class AVMLockingException extends AVMException -{ - /** - * @param msgId - */ - public AVMLockingException(String msgId) - { - super(msgId); - } - - /** - * @param msgId - * @param msgParams - */ - public AVMLockingException(String msgId, Object[] msgParams) - { - super(msgId, msgParams); - } - - /** - * @param msgId - * @param cause - */ - public AVMLockingException(String msgId, Throwable cause) - { - super(msgId, cause); - } - - /** - * @param msgId - * @param msgParams - * @param cause - */ - public AVMLockingException(String msgId, Object[] msgParams, Throwable cause) - { - super(msgId, msgParams, cause); - } -} + * along with Alfresco. If not, see . + */ +package org.alfresco.service.cmr.avm.locking; + +import org.alfresco.service.cmr.avm.AVMException; + +/** + * Exception thrown when a lock is denied. + * + * @author Derek Hulley + */ +public class AVMLockingException extends AVMException +{ + private static final long serialVersionUID = -8446855530834146895L; + + public AVMLockingException(String msgId, Object ... msgParams) + { + super(msgId, msgParams); + } + + public AVMLockingException(Throwable cause, String msgId, Object ... msgParams) + { + super(msgId, msgParams, cause); + } +} diff --git a/source/java/org/alfresco/service/cmr/avm/locking/AVMLockingService.java b/source/java/org/alfresco/service/cmr/avm/locking/AVMLockingService.java index 57e2739ab3..bd9d59aec2 100644 --- a/source/java/org/alfresco/service/cmr/avm/locking/AVMLockingService.java +++ b/source/java/org/alfresco/service/cmr/avm/locking/AVMLockingService.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,131 +14,155 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.avm.locking; - -import java.io.Serializable; -import java.util.List; - -import org.alfresco.service.cmr.repository.NodeRef; - -/** - * Service to handle AVM locking. - * @author britt - */ -public interface AVMLockingService -{ - public enum Type implements Serializable - { - DISCRETIONARY - }; - - /** - * Creates a lock of the given type on a path. - * The lock is used to control access to all the - * corresponding paths in the given path's web project. - * @param lock The lock structure to create. - */ - public void lockPath(AVMLock lock); - - /** - * Get a lock on a given path - * @param webProject The website for which to get the lock. - * @param path The path to check for a lock. - * @return The Lock structure or null if there is no lock. - */ - public AVMLock getLock(String webProject, String path); - - /** - * Modify a lock. Null change parameters are ignored. - * @param webProject The name of the web project. - * @param path The path of the lock. - * @param newPath The path that the lock should be given. (may be null) - * @param newStore The store that the lock should be given. (may be null) - * @param usersToRemove List of users to remove from the lock. (may be null) - * @param usersToAdd List of users to add to the lock. (may be null) - */ - public void modifyLock(String webProject, String path, String newPath, - String newStore, List usersToRemove, - List usersToAdd); - - /** - * Remove a lock. - * @param webProject The web project the lock lives in. - * @param path The store relative path of the lock. - */ - public void removeLock(String webProject, String path); - - /** - * Remove all locks on files contained within a directory. - * @param webProject - * @param store - * @param path - */ - public void removeLocksInDirectory(String webProject, String store, String path); - - /** - * Removes all locks residing in a store. - * @param store The store name. - */ - public void removeStoreLocks(String store); - - /** - * Get all the locks that a user owns. - * @param user The name of the user. - * @return The (possibly empty list) of the user's locks. - */ - public List getUsersLocks(String user); - - /** - * Add a web project to the locking tables if it doesn't already exist. - * @param webProject The web project name. - */ - public void addWebProject(String webProject); - - /** - * Remove a web project and all associated data from the locking tables. - * @param webProject The web project name. - */ - public void removeWebProject(String webProject); - - /** - * Get all locks in a give web project. - * @param webProject The web project name. - * @return All the locks found. - */ - public List getWebProjectLocks(String webProject); - - /** - * Get all locks that reside in a given store. - * @param store The store name. - * @return All the locks found. - */ - public List getStoreLocks(String store); - - /** - * Is the user allowed to do anything to the given asset, other than read? - * @param webProject The name of the web project that this path is being checked in. - * @param avmPath A full avmPath - * @param user The name of the user, group, role to check on. - * @return Whether the user has access. - */ - public boolean hasAccess(String webProject, String avmPath, String user); - - /** - * Is the user allowed to do anything to the given asset, other than read? - * @param webProjectRef The NodeRef to the web project that this path is being checked in. - * @param avmPath A full avmPath - * @param user The name of the user, group, role to check on. - * @return Whether the user has access. - */ - public boolean hasAccess(NodeRef webProjectRef, String avmPath, String user); - - /** - * Get the names of all the web projects the service knows about. - * @return The list of web project names. - */ - public List getWebProjects(); -} + * along with Alfresco. If not, see . + */ +package org.alfresco.service.cmr.avm.locking; + +import java.util.Map; + +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Service to handle AVM locking. + * + * @author Derek Hulley, janv + */ +public interface AVMLockingService +{ + /** + * Creates a lock of the given type on a path within an AVM store. + * + * @param avmStore the name of the AVM store + * @param path the relative path of the lock + * @param lockOwner the user taking the lock + * @param lockData additional data to append to the lock + */ + public void lock(String avmStore, String path, String lockOwner, Map lockData); + + /** + * Modify a lock if it exists or do nothing if it doesn't. The user supplied must + * already hold the lock if it exists. + * + * @param avmStore the name of the AVM store + * @param path the relative path of the lock + * @param lockOwner the user taking the lock and who must also own the existing lock + * @param newAvmStore the name of the new AVM store + * @param newPath the new relative path of the lock + * @param lockData the new additional data to append to the lock + * @return true if the lock was modified or false if no lock existed + */ + public boolean modifyLock( + String avmStore, String path, String lockOwner, + String newAvmStore, String newPath, + Map lockData); + + /** + * Get the current holder of a lock on AVM store path + * + * @param avmStore the name of the AVM store + * @param path the relative path of the lock + * @return Returns the user holding the lock or null + */ + public String getLockOwner(String avmStore, String path); + + /** + * Enumeration of the state of a lock's with respect to a specific user. + * + * @author Derek Hulley + * @since 3.4 + */ + public static enum LockState + { + /** + * The user holds the lock + */ + LOCK_OWNER, + /** + * Another user holds the lock + */ + LOCK_NOT_OWNER, + /** + * There is currently no lock + */ + NO_LOCK; + } + + /** + * Get the state of a lock with respect to a given AVM store, path and user + * + * @param avmStore the name of the AVM store + * @param path the relative path of the lock + * @param lockOwner the user who might own the lock + * @return the state of the lock with respect to the given user + */ + public LockState getLockState(String avmStore, String path, String lockOwner); + + /** + * Get the data associated with a lock + * + * @param avmStore the name of the AVM store + * @param path the relative path of the lock + * @return the state of the lock with respect to the given user + */ + public Map getLockData(String avmStore, String path); + + /** + * Remove a lock. + * + * @param webProject the name of the web project + * @param path the relative path of the lock + */ + public void removeLock(String avmStore, String path); + + /** + * Remove all locks for a specific AVM store + * + * @param avmStore the name of the AVM store + */ + public void removeLocks(String avmStore); + + /** + * Remove all locks for a specific AVM store that start with a given directory path + * that also optionally match a map of lock data entries. + * + * @param avmStore the name of the AVM store + * @param dirPath optional - start with given directory path or null to match all + * @param lockDataToMatch optional - lock data to match (note: all entries must match) or null/empty to match all + */ + public void removeLocks(String avmStore, String dirPath, final Map lockDataToMatch); + + /** + * Remove all locks for a specific AVM store + * that also optionally match a map of lock data entries. + * + * @param avmStore the name of the AVM store + * @param lockDataToMatch optional - lock data to match (note: all entries must match) or null/empty to match all + */ + public void removeLocks(String avmStore, final Map lockDataToMatch); + + /** + * Is the user allowed to do anything to the given asset, other than read? + * + * @param webProject the name of the WCM project + * @param path the relative path of the lock + * @param lockOwner the user to check + * @return true if the user has access + * (either holds the lock or there is no lock, etc) + * + * @deprecated This will move into a WCMLockingService + */ + public boolean hasAccess(String webProject, String avmPath, String lockOwner); + + /** + * Is the user allowed to do anything to the given asset, other than read? + * + * @param webProject the name of the WCM project + * @param path the relative path of the lock + * @param lockOwner the user to check + * @return true if the user has access + * (either holds the lock or there is no lock, etc) + * + * @deprecated This will move into a WCMLockingService + */ + public boolean hasAccess(NodeRef webProject, String avmPath, String lockOwner); +} diff --git a/source/java/org/alfresco/service/cmr/remote/AttributeServiceTransport.java b/source/java/org/alfresco/service/cmr/remote/AttributeServiceTransport.java deleted file mode 100644 index e105e9c024..0000000000 --- a/source/java/org/alfresco/service/cmr/remote/AttributeServiceTransport.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ - -package org.alfresco.service.cmr.remote; - -import java.util.List; -import java.util.Map; - -import org.alfresco.repo.attributes.Attribute; -import org.alfresco.service.cmr.attributes.AttrQuery; -import org.alfresco.util.Pair; - -/** - * The transport wrapper for remoted AttributeService. - * @author britt - */ -public interface AttributeServiceTransport -{ - /** - * Get an Attribute. - * @param ticket The authentication ticket. - * @param path The path of the Attribute. - * @return The value of the attribute or null. - */ - public Attribute getAttribute(String ticket, String path); - - /** - * Get an attribute. - * @param ticket The authentication ticket. - * @param keys The keys in the attribute path. - * @return The value of the attribute or null. - */ - public Attribute getAttribute(String ticket, List keys); - - /** - * Set an attribute. Overwrites if it exists. - * @param ticket The authentication ticket. - * @param name The name of the Attribute. - * @param value The value to set. - */ - public void setAttribute(String ticket, String path, String name, Attribute value); - - /** - * Set an attribute - * @param ticket The authentication ticket. - * @param keys List of attribute path keys. - * @param name The name of the attribute to set. - * @param value The Attribute to set. - */ - public void setAttribute(String ticket, List keys, String name, Attribute value); - - /** - * Set an attribute in a list. - * @param ticket The authentication ticket. - * @param path The path to the list. - * @param index The list index. - * @param value The Attribute to set. - */ - public void setAttribute(String ticket, String path, int index, Attribute value); - - /** - * Set an attribute in a list. - * @param ticket The authentication ticket. - * @param keys The path components to the list. - * @param index The list index. - * @param value The Attribute to set. - */ - public void setAttribute(String ticket, List keys, int index, Attribute value); - - /** - * Add an attribute to a List Attribute - * @param ticket The authentication ticket. - * @param path The path to the list. - * @param value The Attribute to add. - */ - public void addAttribute(String ticket, String path, Attribute value); - - /** - * Add an attribute to a List Attribute. - * @param ticket The authentication ticket. - * @param keys The path components to the list. - * @param value The Attribute to add. - */ - public void addAttribute(String ticket, List keys, Attribute value); - - /** - * Remove an Attribute. - * @param ticket The authentication ticket. - * @param name The name of the Attribute. - */ - public void removeAttribute(String ticket, String path, String name); - - /** - * Remove an Attribute. - * @param ticket The authentication ticket. - * @param keys List of attribute path keys. - * @param name The name of the attribute to remove. - */ - public void removeAttribute(String ticket, List keys, String name); - - /** - * Remove an attribute from a list. - * @param ticket The authentication ticket. - * @param path The path to the list. - * @param index The index to remove. - */ - public void removeAttribute(String ticket, String path, int index); - - /** - * Remove an attribute from a list. - * @param ticket The authentication ticket. - * @param keys The components of the path to the list. - * @param index The index to remove. - */ - public void removeAttribute(String ticket, List keys, int index); - - /** - * Query for a list of attributes which are contained in the map - * defined by the given path and meet the query criteria. - * @param ticket The authentication ticket. - * @param path - * @param query - * @return A List of matching attributes. - */ - public List> query(String ticket, String path, AttrQuery query); - - /** - * Query for a list of attributes which are contained in a map defined by the - * given path and meet the query criteria. - * @param ticket The authentication ticket. - * @param keys The list of attribute path keys. - * @param query - * @return A list of matching attributes. - */ - public List> query(String ticket, List keys, AttrQuery query); - - /** - * Get all the keys for a given attribute path. - * @param ticket The authentication ticket. - * @param path The attribute path. - * @return A list of all keys. - */ - public List getKeys(String ticket, String path); - - /** - * Get all the keys for a give attribute path. - * @param ticket The authentication ticket. - * @param keys The keys of the attribute path. - * @return A list of all keys. - */ - public List getKeys(String ticket, List keys); - - /** - * Get the size of a map or list. - * @param keys List of attribute path keys. - * @return The size of of the list or map. - */ - public int getCount(String ticket, List keys); - - /** - * Get the size of a map or list. - * @param path The path to the map or list. - * @return The size of the list or map. - */ - public int getCount(String ticket, String path); - - /** - * Does an attribute exist. - * @param keys List of attribute path keys. - * @return Whether the attribute exists. - */ - public boolean exists(String ticket, List keys); - - /** - * Does an attribute exist. - * @param path The path to the attribute. - * @return Whether the attribute exists. - */ - public boolean exists(String ticket, String path); - - /** - * Add a list of attributes. - * @param ticket - * @param keys - * @param values - */ - public void addAttributes(String ticket, List keys, List values); - - /** - * Add a list of attributes. - * @param ticket - * @param path - * @param values - */ - public void addAttributes(String ticket, String path, List values); - - /** - * Add a set of attributes. - * @param ticket - * @param keys - * @param entries - */ - public void setAttributes(String ticket, List keys, Map entries); - - /** - * Add a set of attributes. - * @param ticket - * @param path - * @param entries - */ - public void setAttributes(String ticket, String path, Map entries); - - /** - * Remove entries from a map that match a query. - * @param ticket - * @param keys - * @param query - */ - public void removeEntries(String ticket, List keys, AttrQuery query); - - /** - * Remove entries from a map that match a query. - * @param ticket - * @param path - * @param query - */ - public void removeEntries(String ticket, String path, AttrQuery query); -} diff --git a/source/java/org/alfresco/service/cmr/repository/AbstractStoreException.java b/source/java/org/alfresco/service/cmr/repository/AbstractStoreException.java index 5ec7edb6ec..bdd2bc6c04 100644 --- a/source/java/org/alfresco/service/cmr/repository/AbstractStoreException.java +++ b/source/java/org/alfresco/service/cmr/repository/AbstractStoreException.java @@ -26,16 +26,28 @@ package org.alfresco.service.cmr.repository; */ public abstract class AbstractStoreException extends RuntimeException { + private static final long serialVersionUID = 1315634811903555316L; + private StoreRef storeRef; public AbstractStoreException(StoreRef storeRef) { - this(null, storeRef); + this(null, storeRef, null); } public AbstractStoreException(String msg, StoreRef storeRef) { - super(msg); + this(msg, storeRef, null); + } + + public AbstractStoreException(StoreRef storeRef, Throwable e) + { + this(null, storeRef, e); + } + + public AbstractStoreException(String msg, StoreRef storeRef, Throwable e) + { + super(msg, e); this.storeRef = storeRef; } diff --git a/source/java/org/alfresco/service/cmr/repository/AssociationExistsException.java b/source/java/org/alfresco/service/cmr/repository/AssociationExistsException.java index 68cc471e4d..65acca6844 100644 --- a/source/java/org/alfresco/service/cmr/repository/AssociationExistsException.java +++ b/source/java/org/alfresco/service/cmr/repository/AssociationExistsException.java @@ -30,43 +30,43 @@ public class AssociationExistsException extends RuntimeException { private static final long serialVersionUID = 3256440317824874800L; - private NodeRef sourceRef; - private NodeRef targetRef; + private Long sourceNodeId; + private Long targetNodeId; private QName qname; /** * @see #AssociationExistsException(NodeRef, NodeRef, QName, Throwable) */ - public AssociationExistsException(NodeRef sourceRef, NodeRef targetRef, QName qname) + public AssociationExistsException(Long sourceNodeId, Long targetNodeId, QName qname) { super(); - this.sourceRef = sourceRef; - this.targetRef = targetRef; + this.sourceNodeId = sourceNodeId; + this.targetNodeId = targetNodeId; this.qname = qname; } /** - * @param sourceRef the source of the association - * @param targetRef the target of the association - * @param qname the qualified name of the association + * @param sourceNodeId the source of the association + * @param targetNodeId the target of the association + * @param qname the qualified name of the association * @param cause a causal exception */ - public AssociationExistsException(NodeRef sourceRef, NodeRef targetRef, QName qname, Throwable cause) + public AssociationExistsException(Long sourceNodeId, Long targetNodeId, QName qname, Throwable cause) { super(cause); - this.sourceRef = sourceRef; - this.targetRef = targetRef; + this.sourceNodeId = sourceNodeId; + this.targetNodeId = targetNodeId; this.qname = qname; } - public NodeRef getSourceRef() + public Long getSourceNodeId() { - return sourceRef; + return sourceNodeId; } - public NodeRef getTargetRef() + public Long getTargetNodeId() { - return targetRef; + return targetNodeId; } public QName getQName() diff --git a/source/java/org/alfresco/service/cmr/repository/AssociationRef.java b/source/java/org/alfresco/service/cmr/repository/AssociationRef.java index 3ff852857e..0b39cfd2d0 100644 --- a/source/java/org/alfresco/service/cmr/repository/AssociationRef.java +++ b/source/java/org/alfresco/service/cmr/repository/AssociationRef.java @@ -27,6 +27,8 @@ import org.alfresco.util.EqualsHelper; /** * This class represents a regular, named node relationship between two nodes. + *

+ * Note that the ID of the association might not be populated. * * @author Derek Hulley */ @@ -42,11 +44,25 @@ public class AssociationRef implements EntityRef, Serializable private NodeRef targetRef; /** - * Construct a representation of a source --- name ----> target - * relationship. + * Construct a representation of a source --- name ----> target relationship. + * + * @param sourceRef + * the source reference - never null + * @param assocTypeQName + * the qualified name of the association type - never null + * @param targetRef + * the target node reference - never null. + */ + public AssociationRef(NodeRef sourceRef, QName assocTypeQName, NodeRef targetRef) + { + this(null, sourceRef, assocTypeQName, targetRef); + } + + /** + * Construct a representation of a source --- name ----> target relationship. * * @param id - * unique identifier + * unique identifier - may be null * @param sourceRef * the source reference - never null * @param assocTypeQName @@ -118,7 +134,6 @@ public class AssociationRef implements EntityRef, Serializable /** * Compares: *

    - *
  • {@link #id}
  • *
  • {@link #sourceRef}
  • *
  • {@link #targetRef}
  • *
  • {@link #assocTypeQName}
  • @@ -136,16 +151,14 @@ public class AssociationRef implements EntityRef, Serializable } AssociationRef other = (AssociationRef) o; - return (EqualsHelper.nullSafeEquals(this.id, other.id) - && EqualsHelper.nullSafeEquals(this.sourceRef, other.sourceRef) + return (EqualsHelper.nullSafeEquals(this.sourceRef, other.sourceRef) && EqualsHelper.nullSafeEquals(this.assocTypeQName, other.assocTypeQName) && EqualsHelper.nullSafeEquals(this.targetRef, other.targetRef)); } public int hashCode() { - int hashCode = (getId() == null) ? 0 : getId().hashCode(); - hashCode = 37 * hashCode + ((getSourceRef() == null) ? 0 : getSourceRef().hashCode()); + int hashCode = ((getSourceRef() == null) ? 0 : getSourceRef().hashCode()); hashCode = 37 * hashCode + ((getTypeQName() == null) ? 0 : getTypeQName().hashCode()); hashCode = 37 * hashCode + getTargetRef().hashCode(); return hashCode; @@ -154,7 +167,8 @@ public class AssociationRef implements EntityRef, Serializable /** * Gets the unique identifier for this association. * - * @return the unique identifier for this association + * @return the unique identifier for this association, or null if the ID was not + * given at the time of construction */ public Long getId() { diff --git a/source/java/org/alfresco/service/cmr/repository/InvalidStoreRefException.java b/source/java/org/alfresco/service/cmr/repository/InvalidStoreRefException.java index 2ee0b8bb36..dfe547e14a 100644 --- a/source/java/org/alfresco/service/cmr/repository/InvalidStoreRefException.java +++ b/source/java/org/alfresco/service/cmr/repository/InvalidStoreRefException.java @@ -31,7 +31,7 @@ public class InvalidStoreRefException extends AbstractStoreException public InvalidStoreRefException(StoreRef storeRef) { - super(storeRef); + this("Invalid store: " + storeRef, storeRef); } public InvalidStoreRefException(String msg, StoreRef storeRef) diff --git a/source/java/org/alfresco/service/cmr/repository/NodeService.java b/source/java/org/alfresco/service/cmr/repository/NodeService.java index 9ced377c49..9130d76d1e 100644 --- a/source/java/org/alfresco/service/cmr/repository/NodeService.java +++ b/source/java/org/alfresco/service/cmr/repository/NodeService.java @@ -300,14 +300,12 @@ public interface NodeService /** * Makes a parent-child association between the given nodes. Both nodes must belong to the same store. - *

    * - * - * @param parentRef - * @param childRef - * @param assocTypeQName the qualified name of the association type as defined in the datadictionary - * @param qname the qualified name of the association - * @return Returns a reference to the newly created child association + * @param parentRef the parent node + * @param childRef the child node + * @param assocTypeQName the qualified name of the association type as defined in the datadictionary + * @param qname the qualified name of the association + * @return Returns a reference to the newly created child association * @throws InvalidNodeRefException if the parent or child nodes could not be found * @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add */ @@ -320,14 +318,12 @@ public interface NodeService /** * Associates a given child node with a given collection of parents. All nodes must belong to the same store. - *

    * - * - * @param parentRefs - * @param childRef - * @param assocTypeQName the qualified name of the association type as defined in the datadictionary - * @param qname the qualified name of the association - * @return Returns a reference to the newly created child association + * @param parentRefs the parent nodes (there will be this many associations created). + * @param childRef the child node + * @param assocTypeQName the qualified name of the association type as defined in the datadictionary + * @param qname the qualified name of the association + * @return Returns a reference to the newly created child association * @throws InvalidNodeRefException if the parent or child nodes could not be found * @throws CyclicChildRelationshipException if the child partakes in a cyclic relationship after the add */ @@ -456,11 +452,11 @@ public interface NodeService *

    * The resultant list is ordered by (a) explicit index and (b) association creation time. * - * @param nodeRef the child node - * @param typeQNamePattern the pattern that the type qualified name of the association must match - * @param qnamePattern the pattern that the qnames of the assocs must match - * @return Returns a list of all parent-child associations that exist where the given - * node is the child + * @param nodeRef the child node + * @param typeQNamePattern the pattern that the type qualified name of the association must match + * @param qnamePattern the pattern that the qnames of the assocs must match + * @return Returns a list of all parent-child associations that exist where the given + * node is the child * @throws InvalidNodeRefException if the node could not be found * * @see ChildAssociationRef#getNthSibling() diff --git a/source/java/org/alfresco/service/cmr/repository/StoreExistsException.java b/source/java/org/alfresco/service/cmr/repository/StoreExistsException.java index 002e8151bc..df6b47779d 100644 --- a/source/java/org/alfresco/service/cmr/repository/StoreExistsException.java +++ b/source/java/org/alfresco/service/cmr/repository/StoreExistsException.java @@ -29,13 +29,8 @@ public class StoreExistsException extends AbstractStoreException { private static final long serialVersionUID = 3906369320370975030L; - public StoreExistsException(StoreRef storeRef) + public StoreExistsException(StoreRef storeRef, Throwable e) { - super(storeRef); - } - - public StoreExistsException(String msg, StoreRef storeRef) - { - super(msg, storeRef); + super(storeRef, e); } } diff --git a/source/java/org/alfresco/service/cmr/repository/datatype/DefaultTypeConverter.java b/source/java/org/alfresco/service/cmr/repository/datatype/DefaultTypeConverter.java index c472b0e6e7..856b5e4979 100644 --- a/source/java/org/alfresco/service/cmr/repository/datatype/DefaultTypeConverter.java +++ b/source/java/org/alfresco/service/cmr/repository/datatype/DefaultTypeConverter.java @@ -31,12 +31,7 @@ import java.text.ParseException; import java.util.Calendar; import java.util.Date; import java.util.Locale; -import java.util.Map; -import org.alfresco.repo.attributes.Attribute; -import org.alfresco.repo.attributes.MapAttribute; -import org.alfresco.repo.attributes.MapAttributeValue; -import org.alfresco.repo.attributes.StringAttributeValue; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.ContentData; @@ -329,36 +324,6 @@ public class DefaultTypeConverter } }); - // - // Attributes - // - INSTANCE.addConverter(MapAttribute.class, MLText.class, new TypeConverter.Converter() - { - public MLText convert(MapAttribute source) - { - MLText ret = new MLText(); - for (Map.Entry entry : source.entrySet()) - { - String localeStr = entry.getKey(); - Locale locale; - try - { - locale = INSTANCE.convert(Locale.class, localeStr); - } - catch (TypeConversionException e) - { - throw new TypeConversionException( - "MapAttribute string key cannot be converted to a locales:" + localeStr, e); - } - Attribute valueAttribute = entry.getValue(); - // Use the attribute's built-in conversion - String valueStr = valueAttribute == null ? null : valueAttribute.getStringValue(); - ret.put(locale, valueStr); - } - return ret; - } - }); - // // From Locale // @@ -402,21 +367,6 @@ public class DefaultTypeConverter } }); - INSTANCE.addConverter(MLText.class, Attribute.class, new TypeConverter.Converter() - { - public Attribute convert(MLText source) - { - Attribute attribute = new MapAttributeValue(); - for (Map.Entry entry : source.entrySet()) - { - String localeStr = INSTANCE.convert(String.class, entry.getKey()); - Attribute stringAttribute = new StringAttributeValue(entry.getValue()); - attribute.put(localeStr, stringAttribute); - } - return attribute; - } - }); - // // From enum // @@ -442,24 +392,24 @@ public class DefaultTypeConverter // From Class INSTANCE.addConverter(Class.class, String.class, new TypeConverter.Converter() - { - public String convert(Class source) - { - return source.getName(); - } - }); + { + public String convert(Class source) + { + return source.getName(); + } + }); // // Number to Subtypes and Date // INSTANCE.addConverter(Number.class, Boolean.class, new TypeConverter.Converter() - { - public Boolean convert(Number source) - { - return new Boolean(source.longValue() > 0); - } - }); + { + public Boolean convert(Number source) + { + return new Boolean(source.longValue() > 0); + } + }); INSTANCE.addConverter(Number.class, Byte.class, new TypeConverter.Converter() { diff --git a/source/java/org/alfresco/service/cmr/repository/datatype/DefaultTypeConverterTest.java b/source/java/org/alfresco/service/cmr/repository/datatype/DefaultTypeConverterTest.java index 5d37c35784..fa4bc496af 100644 --- a/source/java/org/alfresco/service/cmr/repository/datatype/DefaultTypeConverterTest.java +++ b/source/java/org/alfresco/service/cmr/repository/datatype/DefaultTypeConverterTest.java @@ -28,14 +28,10 @@ import java.util.Locale; import junit.framework.TestCase; -import org.alfresco.repo.attributes.Attribute; -import org.alfresco.repo.attributes.MapAttributeValue; -import org.alfresco.repo.attributes.StringAttribute; -import org.alfresco.repo.attributes.StringAttributeValue; import org.alfresco.service.cmr.repository.MLText; import org.alfresco.service.cmr.repository.Period; -import org.springframework.extensions.surf.util.ISO8601DateFormat; import org.alfresco.util.VersionNumber; +import org.springframework.extensions.surf.util.ISO8601DateFormat; public class DefaultTypeConverterTest extends TestCase { @@ -155,32 +151,6 @@ public class DefaultTypeConverterTest extends TestCase assertEquals(this.getClass().getName(), DefaultTypeConverter.INSTANCE.convert(String.class, this.getClass())); } - String localeStrEn = DefaultTypeConverter.INSTANCE.convert(String.class, Locale.ENGLISH); - String localeStrFr = DefaultTypeConverter.INSTANCE.convert(String.class, Locale.FRENCH); - public void testToMLText() - { - StringAttribute stringAttributeEn = new StringAttributeValue("English text"); - StringAttribute stringAttributeFr = new StringAttributeValue("French text"); - MapAttributeValue mapAttributeValue = new MapAttributeValue(); - mapAttributeValue.put(localeStrEn, stringAttributeEn); - mapAttributeValue.put(localeStrFr, stringAttributeFr); - - MLText mlText = DefaultTypeConverter.INSTANCE.convert(MLText.class, mapAttributeValue); - assertEquals("MapAttribute to MLText failed", "English text", mlText.getValue(Locale.ENGLISH)); - assertEquals("MapAttribute to MLText failed", "French text", mlText.getValue(Locale.FRENCH)); - } - - public void testFromMLText() - { - MLText mlText = new MLText(); - mlText.put(Locale.ENGLISH, "English"); - mlText.put(Locale.FRENCH, "French"); - Attribute attribute = DefaultTypeConverter.INSTANCE.convert(Attribute.class, mlText); - assertTrue("Attribute is of the wrong type", attribute instanceof MapAttributeValue); - assertNotNull("ML value not mapped", attribute.get(localeStrEn)); - assertNotNull("ML value not mapped", attribute.get(localeStrFr)); - } - public void testPrimativeAccessors() { assertEquals(false, DefaultTypeConverter.INSTANCE.convert(Boolean.class, false).booleanValue()); diff --git a/source/java/org/alfresco/service/cmr/usage/UsageService.java b/source/java/org/alfresco/service/cmr/usage/UsageService.java index bae60026d2..2e26e66933 100644 --- a/source/java/org/alfresco/service/cmr/usage/UsageService.java +++ b/source/java/org/alfresco/service/cmr/usage/UsageService.java @@ -1,65 +1,66 @@ -/* - * Copyright (C) 2005-2010 Alfresco Software Limited. - * - * This file is part of Alfresco - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.service.cmr.usage; - -import java.util.Set; - -import org.alfresco.service.NotAuditable; -import org.alfresco.service.PublicService; -import org.alfresco.service.cmr.repository.NodeRef; - -/** - * The public API by which applications can create usage delta entries. - * - * @author Jan Vonka - * @since 2.9 - */ -@PublicService -public interface UsageService -{ - /** - * Add a usage delta entry. - */ - @NotAuditable - public void insertDelta(NodeRef usageNodeRef, long deltaSize); - - /** - * Get sum of usage delta sizes. - */ - @NotAuditable - public long getTotalDeltaSize(NodeRef usageNodeRef); - - /** - * Get sum of usage delta sizes and remove affected deltas. - */ - @NotAuditable - public long getAndRemoveTotalDeltaSize(NodeRef usageNodeRef); - - /** - * Get distinct set of usage delta nodes - */ - @NotAuditable - public Set getUsageDeltaNodes(); - - /** - * Delete the usage delta nodes - */ - @NotAuditable - public int deleteDeltas(NodeRef usageNodeRef); -} +/* + * Copyright (C) 2005-2010 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.service.cmr.usage; + +import java.util.Set; + +import org.alfresco.service.NotAuditable; +import org.alfresco.service.PublicService; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * The public API by which applications can create usage delta entries. + * + * @author janv + * @since 2.9, 3.0 + */ +@PublicService +public interface UsageService +{ + /** + * Add a usage delta entry. + */ + @NotAuditable + public void insertDelta(NodeRef usageNodeRef, long deltaSize); + + /** + * Get sum of usage delta sizes. + */ + @NotAuditable + public long getTotalDeltaSize(NodeRef usageNodeRef); + + /** + * Get sum of usage delta sizes and remove affected deltas. + */ + @NotAuditable + public long getAndRemoveTotalDeltaSize(NodeRef usageNodeRef); + + /** + /** + * Get distinct set of usage delta nodes + */ + @NotAuditable + public Set getUsageDeltaNodes(); + + /** + * Delete the usage delta nodes + */ + @NotAuditable + public int deleteDeltas(NodeRef usageNodeRef); +} diff --git a/source/java/org/alfresco/wcm/AbstractWCMServiceImplTest.java b/source/java/org/alfresco/wcm/AbstractWCMServiceImplTest.java index 3254ffe10d..f51a16758b 100644 --- a/source/java/org/alfresco/wcm/AbstractWCMServiceImplTest.java +++ b/source/java/org/alfresco/wcm/AbstractWCMServiceImplTest.java @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2005-2010 Alfresco Software Limited. * * This file is part of Alfresco @@ -14,208 +14,211 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - */ -package org.alfresco.wcm; - -import java.util.List; - -import junit.framework.TestCase; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.model.ContentModel; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.cmr.security.MutableAuthenticationService; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.util.ApplicationContextHelper; -import org.alfresco.util.PropertyMap; -import org.alfresco.wcm.asset.AssetService; -import org.alfresco.wcm.sandbox.SandboxService; -import org.alfresco.wcm.util.WCMUtil; -import org.alfresco.wcm.webproject.WebProjectInfo; -import org.alfresco.wcm.webproject.WebProjectService; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -/** - * Abstract WCM Service implementation unit test - * - * @author janv - */ -public class AbstractWCMServiceImplTest extends TestCase -{ - private static Log logger = LogFactory.getLog(AbstractWCMServiceImplTest.class); - - private static final String PREVIEW_CONFIG_LOCATION = "classpath:wcm/wcm-test-preview-context.xml"; - - // override jbpm.job.executor idleInterval to 1s (was 1.5m) for WCM unit tests - private static final String SUBMIT_CONFIG_LOCATION = "classpath:wcm/wcm-jbpm-context.xml"; - - protected static final long POLL_DELAY = 1500L; // (in millis) 1.5s - protected static final int POLL_MAX_ATTEMPTS = 20; - - // note: all tests share same context (when run via WCMTestSuite) - protected static ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] {ApplicationContextHelper.CONFIG_LOCATIONS[0], SUBMIT_CONFIG_LOCATION, PREVIEW_CONFIG_LOCATION});; - - // - // test data - // - - protected static final String TEST_RUN = ""+System.currentTimeMillis(); - protected static final boolean CLEAN = true; // cleanup during teardown - - // base web project - protected static final String TEST_WEBPROJ_DNS = "testWebProj-"+TEST_RUN; - - protected static final String TEST_WEBPROJ_NAME = "testSandbox Web Project Display Name - "+TEST_RUN; - protected static final String TEST_WEBPROJ_TITLE = "This is my title"; - protected static final String TEST_WEBPROJ_DESCRIPTION = "This is my description"; - protected static final String TEST_WEBPROJ_DEFAULT_WEBAPP = WCMUtil.DIR_ROOT; - protected static final boolean TEST_WEBPROJ_USE_AS_TEMPLATE = true; - protected static final boolean TEST_WEBPROJ_DONT_USE_AS_TEMPLATE = false; - - // base web users - protected static String USER_ADMIN; - - protected static final String TEST_USER = "testWebUser-"+TEST_RUN; - - protected static final String USER_ONE = TEST_USER+"-One"; - protected static final String USER_TWO = TEST_USER+"-Two"; - protected static final String USER_THREE = TEST_USER+"-Three"; - protected static final String USER_FOUR = TEST_USER+"-Four"; - - // - // services - // - - protected WebProjectService wpService; - protected SandboxService sbService; - protected AssetService assetService; - - protected MutableAuthenticationService authenticationService; - protected PersonService personService; - - protected TransactionService transactionService; - - @Override - protected void setUp() throws Exception - { - // Get the required services - wpService = (WebProjectService)ctx.getBean("WebProjectService"); - sbService = (SandboxService)ctx.getBean("SandboxService"); - assetService = (AssetService)ctx.getBean("AssetService"); - - authenticationService = (MutableAuthenticationService)ctx.getBean("AuthenticationService"); - personService = (PersonService)ctx.getBean("PersonService"); - transactionService = (TransactionService)ctx.getBean("TransactionService"); - - // By default run as Admin - USER_ADMIN = AuthenticationUtil.getAdminUserName(); - AuthenticationUtil.setFullyAuthenticatedUser(USER_ADMIN); - - createUser(USER_ONE); - createUser(USER_TWO); - createUser(USER_THREE); - createUser(USER_FOUR); - } - - @Override - protected void tearDown() throws Exception - { - if (CLEAN) - { - // Switch back to Admin - AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); - - List webProjects = wpService.listWebProjects(); - for (final WebProjectInfo wpInfo : webProjects) - { - if (wpInfo.getStoreId().startsWith(TEST_WEBPROJ_DNS)) - { - // note: added retry for now, due to intermittent concurrent update (during tearDown) possibly due to OrphanReaper ? - // org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [org.alfresco.repo.avm.PlainFileNodeImpl#3752] - RetryingTransactionCallback deleteWebProjectWork = new RetryingTransactionCallback() - { - public Object execute() throws Exception - { - wpService.deleteWebProject(wpInfo.getNodeRef()); - return null; - } - }; - transactionService.getRetryingTransactionHelper().doInTransaction(deleteWebProjectWork); - } - } - - deleteUser(USER_ONE); - deleteUser(USER_TWO); - deleteUser(USER_THREE); - deleteUser(USER_FOUR); - } - - AuthenticationUtil.clearCurrentSecurityContext(); - } - - protected void createUser(String userName) - { - if (authenticationService.authenticationExists(userName) == false) - { - authenticationService.createAuthentication(userName, "PWD".toCharArray()); - - PropertyMap ppOne = new PropertyMap(4); - ppOne.put(ContentModel.PROP_USERNAME, userName); - ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName"); - ppOne.put(ContentModel.PROP_LASTNAME, "lastName"); - ppOne.put(ContentModel.PROP_EMAIL, "email@email.com"); - ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle"); - - personService.createPerson(ppOne); - } - } - - protected void deleteUser(String userName) - { - personService.deletePerson(userName); - } - - protected int pollForSnapshotCount(final String stagingStoreId, final int expectedCnt) throws InterruptedException - { - long start = System.currentTimeMillis(); - - String currentUser = AuthenticationUtil.getFullyAuthenticatedUser(); - - int attempts = 0; - - try - { - AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); - - int cnt = 0; - - while (cnt != expectedCnt) - { - Thread.sleep(POLL_DELAY); - - cnt = sbService.listSnapshots(stagingStoreId, false).size(); - - attempts++; - - if (attempts > POLL_MAX_ATTEMPTS) - { - throw new AlfrescoRuntimeException("Too many poll attempts: "+attempts); - } - } - } - finally - { - AuthenticationUtil.setFullyAuthenticatedUser(currentUser); - } - - logger.debug("pollForSnapshotCount: "+stagingStoreId+" in "+(System.currentTimeMillis()-start)+" msecs ("+attempts+" attempts)"); - - return attempts; - } -} + * along with Alfresco. If not, see . + */ +package org.alfresco.wcm; + +import java.util.List; + +import junit.framework.TestCase; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.cmr.avm.locking.AVMLockingService; +import org.alfresco.service.cmr.security.MutableAuthenticationService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.PropertyMap; +import org.alfresco.wcm.asset.AssetService; +import org.alfresco.wcm.sandbox.SandboxService; +import org.alfresco.wcm.util.WCMUtil; +import org.alfresco.wcm.webproject.WebProjectInfo; +import org.alfresco.wcm.webproject.WebProjectService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * Abstract WCM Service implementation unit test + * + * @author janv + */ +public class AbstractWCMServiceImplTest extends TestCase +{ + private static Log logger = LogFactory.getLog(AbstractWCMServiceImplTest.class); + + private static final String PREVIEW_CONFIG_LOCATION = "classpath:wcm/wcm-test-preview-context.xml"; + + // override jbpm.job.executor idleInterval to 1s (was 1.5m) for WCM unit tests + private static final String SUBMIT_CONFIG_LOCATION = "classpath:wcm/wcm-jbpm-context.xml"; + + protected static final long POLL_DELAY = 1500L; // (in millis) 1.5s + protected static final int POLL_MAX_ATTEMPTS = 20; + + // note: all tests share same context (when run via WCMTestSuite) + protected static ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] {ApplicationContextHelper.CONFIG_LOCATIONS[0], SUBMIT_CONFIG_LOCATION, PREVIEW_CONFIG_LOCATION});; + + // + // test data + // + + protected static final String TEST_RUN = ""+System.currentTimeMillis(); + protected static final boolean CLEAN = true; // cleanup during teardown + + // base web project + protected static final String TEST_WEBPROJ_DNS = "testWebProj-"+TEST_RUN; + + protected static final String TEST_WEBPROJ_NAME = "testSandbox Web Project Display Name - "+TEST_RUN; + protected static final String TEST_WEBPROJ_TITLE = "This is my title"; + protected static final String TEST_WEBPROJ_DESCRIPTION = "This is my description"; + protected static final String TEST_WEBPROJ_DEFAULT_WEBAPP = WCMUtil.DIR_ROOT; + protected static final boolean TEST_WEBPROJ_USE_AS_TEMPLATE = true; + protected static final boolean TEST_WEBPROJ_DONT_USE_AS_TEMPLATE = false; + + // base web users + protected static String USER_ADMIN; + + protected static final String TEST_USER = "testWebUser-"+TEST_RUN; + + protected static final String USER_ONE = TEST_USER+"-One"; + protected static final String USER_TWO = TEST_USER+"-Two"; + protected static final String USER_THREE = TEST_USER+"-Three"; + protected static final String USER_FOUR = TEST_USER+"-Four"; + + // + // services + // + + protected WebProjectService wpService; + protected SandboxService sbService; + protected AssetService assetService; + + protected MutableAuthenticationService authenticationService; + protected PersonService personService; + + protected TransactionService transactionService; + protected AVMLockingService avmLockingService; + + @Override + protected void setUp() throws Exception + { + // Get the required services + wpService = (WebProjectService)ctx.getBean("WebProjectService"); + sbService = (SandboxService)ctx.getBean("SandboxService"); + assetService = (AssetService)ctx.getBean("AssetService"); + + authenticationService = (MutableAuthenticationService)ctx.getBean("AuthenticationService"); + personService = (PersonService)ctx.getBean("PersonService"); + transactionService = (TransactionService)ctx.getBean("TransactionService"); + avmLockingService = (AVMLockingService)ctx.getBean("AVMLockingService"); + + // By default run as Admin + USER_ADMIN = AuthenticationUtil.getAdminUserName(); + AuthenticationUtil.setFullyAuthenticatedUser(USER_ADMIN); + + createUser(USER_ONE); + createUser(USER_TWO); + createUser(USER_THREE); + createUser(USER_FOUR); + } + + @Override + protected void tearDown() throws Exception + { + if (CLEAN) + { + // Switch back to Admin + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + + List webProjects = wpService.listWebProjects(); + for (final WebProjectInfo wpInfo : webProjects) + { + if (wpInfo.getStoreId().startsWith(TEST_WEBPROJ_DNS)) + { + // note: added retry for now, due to intermittent concurrent update (during tearDown) possibly due to OrphanReaper ? + // org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [org.alfresco.repo.avm.PlainFileNodeImpl#3752] + RetryingTransactionCallback deleteWebProjectWork = new RetryingTransactionCallback() + { + public Object execute() throws Exception + { + wpService.deleteWebProject(wpInfo.getNodeRef()); + return null; + } + }; + transactionService.getRetryingTransactionHelper().doInTransaction(deleteWebProjectWork); + } + } + + deleteUser(USER_ONE); + deleteUser(USER_TWO); + deleteUser(USER_THREE); + deleteUser(USER_FOUR); + } + + AuthenticationUtil.clearCurrentSecurityContext(); + } + + protected void createUser(String userName) + { + if (authenticationService.authenticationExists(userName) == false) + { + authenticationService.createAuthentication(userName, "PWD".toCharArray()); + + PropertyMap ppOne = new PropertyMap(4); + ppOne.put(ContentModel.PROP_USERNAME, userName); + ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName"); + ppOne.put(ContentModel.PROP_LASTNAME, "lastName"); + ppOne.put(ContentModel.PROP_EMAIL, "email@email.com"); + ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle"); + + personService.createPerson(ppOne); + } + } + + protected void deleteUser(String userName) + { + personService.deletePerson(userName); + } + + protected int pollForSnapshotCount(final String stagingStoreId, final int expectedCnt) throws InterruptedException + { + long start = System.currentTimeMillis(); + + String currentUser = AuthenticationUtil.getFullyAuthenticatedUser(); + + int attempts = 0; + + try + { + AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + + int cnt = 0; + + while (cnt != expectedCnt) + { + Thread.sleep(POLL_DELAY); + + cnt = sbService.listSnapshots(stagingStoreId, false).size(); + + attempts++; + + if (attempts > POLL_MAX_ATTEMPTS) + { + throw new AlfrescoRuntimeException("Too many poll attempts: "+attempts); + } + } + } + finally + { + AuthenticationUtil.setFullyAuthenticatedUser(currentUser); + } + + logger.debug("pollForSnapshotCount: "+stagingStoreId+" in "+(System.currentTimeMillis()-start)+" msecs ("+attempts+" attempts)"); + + return attempts; + } +} diff --git a/source/java/org/alfresco/wcm/asset/AssetService.java b/source/java/org/alfresco/wcm/asset/AssetService.java index 3ca40bd1ad..7e060cd52d 100644 --- a/source/java/org/alfresco/wcm/asset/AssetService.java +++ b/source/java/org/alfresco/wcm/asset/AssetService.java @@ -31,8 +31,6 @@ import org.alfresco.service.namespace.QName; import org.alfresco.service.Auditable; import org.alfresco.service.NotAuditable; - - /** * Asset Service fundamental API. *

    @@ -45,46 +43,24 @@ public interface AssetService { /** * Create folder within given sandbox and webApp - * - * @param sbStoreId - * @param webApp - * @param parentFolderPathRelativeToWebApp - * @param name */ @NotAuditable public void createFolderWebApp(String sbStoreId, String webApp, String parentFolderPathRelativeToWebApp, String name); /** * Create folder within given sandbox - * - * @param sbStoreId - * @param parentFolderPath - * @param name - * @param properties */ @NotAuditable public void createFolder(String sbStoreId, String parentFolderPath, String name, Map properties); /** * Create (empty) file within given sandbox and webApp, return content writer for file contents - * - * @param sbStoreId - * @param webApp - * @param parentFolderPath - * @param name - * @return */ @NotAuditable public ContentWriter createFileWebApp(String sbStoreId, String webApp, String parentFolderPath, String name); /** * Create (empty) file within given sandbox, return content writer for file contents - * - * @param sbStoreId - * @param parentFolderPath - * @param name - * @param properties - * @return */ @NotAuditable public ContentWriter createFile(String sbStoreId, String parentFolderPath, String name, Map properties); @@ -93,11 +69,6 @@ public interface AssetService * Get asset (file or folder) for given sandbox, webApp and path (within webApp) *

    * Returns null if the asset can not be found - * - * @param sbStoreId - * @param webApp - * @param pathRelativeToWebApp - * @return */ @NotAuditable public AssetInfo getAssetWebApp(String sbStoreId, String webApp, String pathRelativeToWebApp); @@ -106,12 +77,6 @@ public interface AssetService * Get asset (file or folder) for given sandbox, webApp and path (within webApp), optionally include deleted assets *

    * Returns null if the asset can not be found - * - * @param sbStoreId - * @param webApp - * @param pathRelativeToWebApp - * @param includeDeleted - * @return AssetInfo asset info */ @NotAuditable public AssetInfo getAssetWebApp(String sbStoreId, String webApp, String pathRelativeToWebApp, boolean includeDeleted); @@ -132,148 +97,90 @@ public interface AssetService * Get asset (file or folder) for given sandbox version and path, optionally include deleted assets *

    * Returns null if the asset can not be found - * - * @param sbStoreId - * @param version - * @param path - * @param includeDeleted - * @return AssetInfo asset info */ @NotAuditable public AssetInfo getAsset(String sbStoreId, int version, String path, boolean includeDeleted); /** * Get content writer for given file asset, to allow file contents to be written or updated - * - * @param asset - * @return */ @NotAuditable public ContentWriter getContentWriter(AssetInfo fileAsset); /** * Get content reader for given file asset, to allow file contents to be read - * - * @param asset - * @return */ @NotAuditable public ContentReader getContentReader(AssetInfo fileAsset); /** * Get asset properties - * - * @param asset - * @return */ @NotAuditable public Map getAssetProperties(AssetInfo asset); /** * Set asset properties (will replace all existing properties) - * - * @param asset - * @param properties */ @NotAuditable public void setAssetProperties(AssetInfo asset, Map properties); /** * Update asset properties (will replace given set of properties, if they already exist) - * - * @param asset - * @param properties */ @NotAuditable public void updateAssetProperties(AssetInfo asset, Map properties); /** * Apply aspect to asset, with given properties (can be null) - * - * @param asset - * @param aspectName - * @param properties */ @NotAuditable public void addAspect(AssetInfo asset, QName aspectName, Map properties); /** * Remove aspect from asset, and any related properties - * - * @param asset - * @param aspectName */ @NotAuditable public void removeAspect(AssetInfo asset, QName aspectName); /** * Get set of aspects applied to asset - * - * @param asset - * @return list of aspects */ @NotAuditable public Set getAspects(AssetInfo asset); /** * True, if asset has given aspect applied - * - * @param asset - * @param aspectName - * @return */ @NotAuditable public boolean hasAspect(AssetInfo asset, QName aspectName); /** * List assets within given sandbox and webApp and path (within webApp), optionally include deleted - * - * @param sbStoreId - * @param webApp - * @param parentFolderPathRelativeToWebApp - * @param includeDeleted - * @return list of assets */ @NotAuditable public List listAssetsWebApp(String sbStoreId, String webApp, String parentFolderPathRelativeToWebApp, boolean includeDeleted); /** * List assets within given sandbox and path, optionally include deleted - * - * @param sbStoreId - * @param parentFolderPath - * @param includeDeleted - * @return list of assets */ @NotAuditable public List listAssets(String sbStoreId, String parentFolderPath, boolean includeDeleted); /** * List assets within given sandbox version and path, optionally include deleted - * - * @param sbStoreId - * @param version - * @param parentFolderPath - * @param includeDeleted - * @return list of assets */ @NotAuditable public List listAssets(String sbStoreId, int version, String parentFolderPath, boolean includeDeleted); /** * Delete asset - * - * @param asset */ @NotAuditable public void deleteAsset(AssetInfo asset); /** * Rename asset - * - * @param asset - * @param newName - * @return AssetInfo asset info */ @NotAuditable public AssetInfo renameAsset(AssetInfo asset, String newName); @@ -283,10 +190,6 @@ public interface AssetService *

    * Note: folder asset will be recursively copied * Note: file asset(s) must have content - * - * @param asset - * @param parentFolderPath - * @return AssetInfo asset info */ @NotAuditable public AssetInfo copyAsset(AssetInfo asset, String parentFolderPath); @@ -295,20 +198,12 @@ public interface AssetService /** * Move asset within sandbox - * - * @param asset - * @param parentFolderPath - * @return AssetInfo asset info */ @NotAuditable public AssetInfo moveAsset(AssetInfo asset, String parentFolderPath); /** * Bulk import assets into sandbox - * - * @param sbStoreId - * @param parentFolderPath - * @param zipFile */ @NotAuditable public void bulkImport(String sbStoreId, String parentFolderPath, File zipFile, boolean isHighByteZip); @@ -316,7 +211,6 @@ public interface AssetService /** * Runtime check to get lock (and owner) for asset - null if not locked * - * @param asset * @return String lock owner (null if path not locked) */ @NotAuditable @@ -325,7 +219,6 @@ public interface AssetService /** * Runtime check to check if the current user can perform (write) operations on the asset when locked * - * @param asset * @return boolean true if current user has write access */ @NotAuditable diff --git a/source/java/org/alfresco/wcm/asset/AssetServiceImpl.java b/source/java/org/alfresco/wcm/asset/AssetServiceImpl.java index 45c791e391..df1c248787 100644 --- a/source/java/org/alfresco/wcm/asset/AssetServiceImpl.java +++ b/source/java/org/alfresco/wcm/asset/AssetServiceImpl.java @@ -45,7 +45,6 @@ import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.TransactionListenerAdapter; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; import org.alfresco.service.cmr.avm.AVMService; -import org.alfresco.service.cmr.avm.locking.AVMLock; import org.alfresco.service.cmr.avm.locking.AVMLockingService; import org.alfresco.service.cmr.model.FileExistsException; import org.alfresco.service.cmr.repository.ContentReader; @@ -53,11 +52,11 @@ import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.namespace.QName; -import org.springframework.extensions.surf.util.ParameterCheck; import org.alfresco.util.TempFileProvider; import org.alfresco.wcm.sandbox.SandboxConstants; import org.alfresco.wcm.util.WCMUtil; import org.apache.tools.zip.ZipFile; +import org.springframework.extensions.surf.util.ParameterCheck; /** * Asset Service fundamental API. @@ -68,9 +67,6 @@ import org.apache.tools.zip.ZipFile; */ public class AssetServiceImpl implements AssetService { - /** Logger */ - //private static Log logger = LogFactory.getLog(AssetServiceImpl.class); - private static char PATH_SEPARATOR = '/'; private static final int BUFFER_SIZE = 16384; @@ -116,9 +112,6 @@ public class AssetServiceImpl implements AssetService return ((propVal != null) && (WCMUtil.isStagingStore(sbStoreId))); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#createFolderWebApp(java.lang.String, java.lang.String, java.lang.String, java.lang.String) - */ public void createFolderWebApp(String sbStoreId, String webApp, String parentFolderPathRelativeToWebApp, String name) { ParameterCheck.mandatoryString("sbStoreId", sbStoreId); @@ -140,9 +133,6 @@ public class AssetServiceImpl implements AssetService } } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#createFolder(java.lang.String, java.lang.String, java.lang.String, java.util.Map) - */ public void createFolder(String sbStoreId, String parentFolderPath, String name, Map properties) { ParameterCheck.mandatoryString("sbStoreId", sbStoreId); @@ -180,9 +170,6 @@ public class AssetServiceImpl implements AssetService } } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#createFileWebApp(java.lang.String, java.lang.String, java.lang.String, java.lang.String) - */ public ContentWriter createFileWebApp(String sbStoreId, String webApp, String parentFolderPathRelativeToWebApp, String name) { ParameterCheck.mandatoryString("sbStoreId", sbStoreId); @@ -201,9 +188,6 @@ public class AssetServiceImpl implements AssetService return avmService.getContentWriter(avmPath, true); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#createFile(java.lang.String, java.lang.String, java.lang.String, java.util.Map) - */ public ContentWriter createFile(String sbStoreId, String parentFolderPath, String name, Map properties) { ParameterCheck.mandatoryString("sbStoreId", sbStoreId); @@ -255,9 +239,6 @@ public class AssetServiceImpl implements AssetService } } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#getContentWriter(org.alfresco.wcm.asset.AssetInfo) - */ public ContentWriter getContentWriter(AssetInfo asset) { ParameterCheck.mandatory("asset", asset); @@ -272,9 +253,6 @@ public class AssetServiceImpl implements AssetService } } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#getContentReader(org.alfresco.wcm.asset.AssetInfo) - */ public ContentReader getContentReader(AssetInfo asset) { ParameterCheck.mandatory("asset", asset); @@ -282,17 +260,11 @@ public class AssetServiceImpl implements AssetService return avmService.getContentReader(asset.getSandboxVersion(), asset.getAvmPath()); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#getAssetWebApp(java.lang.String, java.lang.String, java.lang.String) - */ public AssetInfo getAssetWebApp(String sbStoreId, String webApp, String pathRelativeToWebApp) { return getAssetWebApp(sbStoreId, webApp, pathRelativeToWebApp, false); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#getAssetWebApp(java.lang.String, java.lang.String, java.lang.String, boolean) - */ public AssetInfo getAssetWebApp(String sbStoreId, String webApp, String pathRelativeToWebApp, boolean includeDeleted) { ParameterCheck.mandatoryString("sbStoreId", sbStoreId); @@ -306,17 +278,11 @@ public class AssetServiceImpl implements AssetService return getAssetAVM(-1, avmPath, includeDeleted); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#getAsset(java.lang.String, java.lang.String) - */ public AssetInfo getAsset(String sbStoreId, String path) { return getAsset(sbStoreId, -1, path, false); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#getAsset(java.lang.String, int, java.lang.String, boolean) - */ public AssetInfo getAsset(String sbStoreId, int version, String path, boolean includeDeleted) { ParameterCheck.mandatoryString("sbStoreId", sbStoreId); @@ -351,9 +317,6 @@ public class AssetServiceImpl implements AssetService return asset; } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#getLockOwner(org.alfresco.wcm.asset.AssetInfo) - */ public String getLockOwner(AssetInfo asset) { ParameterCheck.mandatory("asset", asset); @@ -363,39 +326,19 @@ public class AssetServiceImpl implements AssetService private String getLockOwner(String wpStoreId, String filePath) { - String lockOwner = null; - - if (avmLockingService != null) - { - AVMLock lock = avmLockingService.getLock(wpStoreId, filePath); - - if (lock != null) - { - // for now assume single lock owner (if more than one, then return first in list) - List lockUsers = lock.getOwners(); - if (lockUsers.size() > 0) - { - lockOwner = lockUsers.get(0); - } - } - } - - return lockOwner; + return avmLockingService.getLockOwner(wpStoreId, filePath); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#hasLockAccess(org.alfresco.wcm.asset.AssetInfo) - */ public boolean hasLockAccess(AssetInfo asset) { ParameterCheck.mandatory("asset", asset); - return avmLockingService.hasAccess(WCMUtil.getWebProjectStoreId(asset.getSandboxId()), asset.getAvmPath(), AuthenticationUtil.getFullyAuthenticatedUser()); + return avmLockingService.hasAccess( + WCMUtil.getWebProjectStoreId(asset.getSandboxId()), + asset.getAvmPath(), + AuthenticationUtil.getFullyAuthenticatedUser()); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#updateAssetProperties(org.alfresco.wcm.asset.AssetInfo, java.util.Map) - */ public void updateAssetProperties(AssetInfo asset, Map properties) { ParameterCheck.mandatory("asset", asset); @@ -408,9 +351,6 @@ public class AssetServiceImpl implements AssetService } } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#setAssetProperties(org.alfresco.wcm.asset.AssetInfo, java.util.Map) - */ public void setAssetProperties(AssetInfo asset, Map properties) { ParameterCheck.mandatory("asset", asset); @@ -425,9 +365,6 @@ public class AssetServiceImpl implements AssetService avmNodeService.setProperties(avmNodeRef, properties); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#addAspect(org.alfresco.wcm.asset.AssetInfo, org.alfresco.service.namespace.QName, java.util.Map) - */ public void addAspect(AssetInfo asset, QName aspectName, Map properties) { addAspect(asset.getAvmPath(), aspectName, properties); @@ -439,9 +376,6 @@ public class AssetServiceImpl implements AssetService avmNodeService.addAspect(avmNodeRef, aspect, properties); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#removeAspect(org.alfresco.wcm.asset.AssetInfo, org.alfresco.service.namespace.QName) - */ public void removeAspect(AssetInfo asset, QName aspectName) { ParameterCheck.mandatory("asset", asset); @@ -450,9 +384,6 @@ public class AssetServiceImpl implements AssetService avmNodeService.removeAspect(avmNodeRef, aspectName); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#getAspects(org.alfresco.wcm.asset.AssetInfo) - */ public Set getAspects(AssetInfo asset) { ParameterCheck.mandatory("asset", asset); @@ -461,9 +392,6 @@ public class AssetServiceImpl implements AssetService return avmNodeService.getAspects(avmNodeRef); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#hasAspect(org.alfresco.wcm.asset.AssetInfo, org.alfresco.service.namespace.QName) - */ public boolean hasAspect(AssetInfo asset, QName aspectName) { ParameterCheck.mandatory("asset", asset); @@ -472,9 +400,6 @@ public class AssetServiceImpl implements AssetService return avmNodeService.hasAspect(avmNodeRef, aspectName); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#getAssetProperties(org.alfresco.wcm.asset.AssetInfo) - */ public Map getAssetProperties(AssetInfo asset) { ParameterCheck.mandatory("asset", asset); @@ -488,9 +413,6 @@ public class AssetServiceImpl implements AssetService return avmNodeService.getProperties(avmNodeRef); // note: includes built-in properties } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#listAssetsWebApp(java.lang.String, java.lang.String, java.lang.String, boolean) - */ public List listAssetsWebApp(String sbStoreId, String webApp, String parentFolderPathRelativeToWebApp, boolean includeDeleted) { ParameterCheck.mandatoryString("sbStoreId", sbStoreId); @@ -504,9 +426,6 @@ public class AssetServiceImpl implements AssetService return listAssetsAVM(-1, avmPath, includeDeleted); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#listAssets(java.lang.String, java.lang.String, boolean) - */ public List listAssets(String sbStoreId, String parentFolderPath, boolean includeDeleted) { ParameterCheck.mandatoryString("sbStoreId", sbStoreId); @@ -517,9 +436,6 @@ public class AssetServiceImpl implements AssetService return listAssetsAVM(-1, avmPath, includeDeleted); } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#listAssets(java.lang.String, int, java.lang.String, boolean) - */ public List listAssets(String sbStoreId, int version, String parentFolderPath, boolean includeDeleted) { ParameterCheck.mandatoryString("sbStoreId", sbStoreId); @@ -554,9 +470,6 @@ public class AssetServiceImpl implements AssetService return assets; } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#deleteAsset(org.alfresco.wcm.asset.AssetInfo) - */ public void deleteAsset(AssetInfo asset) { ParameterCheck.mandatory("asset", asset); @@ -571,9 +484,6 @@ public class AssetServiceImpl implements AssetService } } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#renameAsset(org.alfresco.wcm.asset.AssetInfo, java.lang.String) - */ public AssetInfo renameAsset(AssetInfo asset, String newName) { ParameterCheck.mandatory("asset", asset); @@ -593,9 +503,6 @@ public class AssetServiceImpl implements AssetService } } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#moveAsset(org.alfresco.wcm.asset.AssetInfo, java.lang.String) - */ public AssetInfo moveAsset(AssetInfo asset, String parentFolderPath) { ParameterCheck.mandatory("asset", asset); @@ -617,9 +524,6 @@ public class AssetServiceImpl implements AssetService } } - /* (non-Javadoc) - * @see org.alfresco.wcm.asset.AssetService#copyAsset(org.alfresco.wcm.asset.AssetInfo, java.lang.String) - */ public AssetInfo copyAsset(AssetInfo asset, String parentFolderPath) { ParameterCheck.mandatory("asset", asset); diff --git a/source/java/org/alfresco/wcm/sandbox/SandboxConstants.java b/source/java/org/alfresco/wcm/sandbox/SandboxConstants.java index 5fcd31e64a..21e17b9883 100644 --- a/source/java/org/alfresco/wcm/sandbox/SandboxConstants.java +++ b/source/java/org/alfresco/wcm/sandbox/SandboxConstants.java @@ -52,6 +52,5 @@ public class SandboxConstants public final static QName PROP_WEB_PROJECT_NODE_REF = QName.createQName(null, ".web_project.noderef"); public final static QName PROP_WEB_PROJECT_PREVIEW_PROVIDER = QName.createQName(null, ".web_project.previewprovider"); - public final static QName PROP_LINK_VALIDATION_REPORT = QName.createQName(null, ".link.validation.report"); public final static QName PROP_LAST_DEPLOYMENT_ID = QName.createQName(null, ".deployment.id"); } diff --git a/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java b/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java index 9d15a04907..5549a42786 100644 --- a/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java +++ b/source/java/org/alfresco/wcm/sandbox/SandboxFactory.java @@ -75,9 +75,9 @@ public final class SandboxFactory extends WCMUtil private NodeService nodeService; private PermissionService permissionService; private AVMService avmService; - private AVMLockingService avmLockingService; private VirtServerRegistry virtServerRegistry; private AuthorityService authorityService; + private AVMLockingService avmLockingService; static { @@ -104,11 +104,6 @@ public final class SandboxFactory extends WCMUtil this.avmService = avmService; } - public void setAvmLockingService(AVMLockingService avmLockingService) - { - this.avmLockingService = avmLockingService; - } - public void setVirtServerRegistry(VirtServerRegistry virtServerRegistry) { this.virtServerRegistry = virtServerRegistry; @@ -119,6 +114,11 @@ public final class SandboxFactory extends WCMUtil this.authorityService = authorityService; } + public void setAvmLockingService(AVMLockingService avmLockingService) + { + this.avmLockingService = avmLockingService; + } + /** * Private constructor */ @@ -978,14 +978,15 @@ public final class SandboxFactory extends WCMUtil public void deleteSandbox(String wpStoreId, String sbStoreId) { - deleteSandbox(getSandbox(wpStoreId, sbStoreId, true)); + deleteSandbox(getSandbox(wpStoreId, sbStoreId, true), true); } - public void deleteSandbox(SandboxInfo sbInfo) + public void deleteSandbox(SandboxInfo sbInfo, boolean removeLocks) { if (sbInfo != null) { String mainSandboxStore = sbInfo.getMainStoreName(); + String wpStoreId = WCMUtil.getWebProjectStoreId(mainSandboxStore); // found the sandbox to remove - remove the main store (eg. user main store, staging main store, workflow main store) String path = WCMUtil.buildSandboxRootPath(mainSandboxStore); @@ -1025,8 +1026,11 @@ public final class SandboxFactory extends WCMUtil avmService.purgeStore(avmStoreName); } - // remove any locks this user may have - avmLockingService.removeStoreLocks(avmStoreName); + if (removeLocks) + { + Map lockDataToMatch = Collections.singletonMap(WCMUtil.LOCK_KEY_STORE_NAME, avmStoreName); + avmLockingService.removeLocks(wpStoreId, lockDataToMatch); + } } if (logger.isDebugEnabled()) diff --git a/source/java/org/alfresco/wcm/sandbox/SandboxService.java b/source/java/org/alfresco/wcm/sandbox/SandboxService.java index f373f904d1..6c1067d892 100644 --- a/source/java/org/alfresco/wcm/sandbox/SandboxService.java +++ b/source/java/org/alfresco/wcm/sandbox/SandboxService.java @@ -279,7 +279,6 @@ public interface SandboxService * @param submitDescription description for submitted snapshot * @param expirationDates optional map of for those assets set with an expiration date, or can be null (if no expiration dates) * @param launchDate optional launch date - * @param validateLinks if true then will validate links (if link validation is enabled) * @param autoDeploy if true then will auto-deploy on workflow approval * * @deprecated subject to change @@ -288,7 +287,7 @@ public interface SandboxService public void submitListAssets(String sbStoreId, List relativePaths, String workflowName, Map workflowParams, String submitLabel, String submitDescription, - Map expirationDates, Date launchDate, boolean validateLinks, boolean autoDeploy); + Map expirationDates, Date launchDate, boolean autoDeploy); /** * Revert all changed assets for given sandbox (eg. in user sandbox) diff --git a/source/java/org/alfresco/wcm/sandbox/SandboxServiceImpl.java b/source/java/org/alfresco/wcm/sandbox/SandboxServiceImpl.java index ea3f927fba..b5743f5b16 100644 --- a/source/java/org/alfresco/wcm/sandbox/SandboxServiceImpl.java +++ b/source/java/org/alfresco/wcm/sandbox/SandboxServiceImpl.java @@ -593,7 +593,7 @@ public class SandboxServiceImpl implements SandboxService } // via submit direct workflow - submitViaWorkflow(sbStoreId, relativePaths, null, null, submitLabel, submitComment, null, null, false, false); + submitViaWorkflow(sbStoreId, relativePaths, null, null, submitLabel, submitComment, null, null, false); } /* (non-Javadoc) @@ -602,11 +602,11 @@ public class SandboxServiceImpl implements SandboxService public void submitListAssets(String sbStoreId, List relativePaths, String workflowName, Map workflowParams, String submitLabel, String submitComment, - Map expirationDates, Date launchDate, boolean validateLinks, boolean autoDeploy) + Map expirationDates, Date launchDate, boolean autoDeploy) { // via selected workflow submitViaWorkflow(sbStoreId, relativePaths, workflowName, workflowParams, submitLabel, submitComment, - expirationDates, launchDate, validateLinks, autoDeploy); + expirationDates, launchDate, autoDeploy); } /** @@ -621,7 +621,7 @@ public class SandboxServiceImpl implements SandboxService */ private void submitViaWorkflow(final String sbStoreId, final List relativePaths, String workflowName, Map workflowParams, final String submitLabel, final String submitComment, - final Map expirationDates, final Date launchDate, final boolean validateLinks, final boolean autoDeploy) + final Map expirationDates, final Date launchDate, final boolean autoDeploy) { // checks sandbox access (TODO review) getSandbox(sbStoreId); // ignore result @@ -683,7 +683,7 @@ public class SandboxServiceImpl implements SandboxService public String execute() throws Throwable { // call the actual implementation - startWorkflow(wpStoreId, sbStoreId, wfSandboxInfo, webApp, finalWorkflowName, finalWorkflowParams, submitLabel, submitComment, launchDate, validateLinks, autoDeploy); + startWorkflow(wpStoreId, sbStoreId, wfSandboxInfo, webApp, finalWorkflowName, finalWorkflowParams, submitLabel, submitComment, launchDate, autoDeploy); return null; } }; @@ -795,7 +795,7 @@ public class SandboxServiceImpl implements SandboxService * checked and reviewed. */ protected void startWorkflow(String wpStoreId, String sbStoreId, SandboxInfo wfSandboxInfo, String webApp, String workflowName, Map workflowParams, - String submitLabel, String submitComment, Date launchDate, boolean validateLinks, boolean autoDeploy) + String submitLabel, String submitComment, Date launchDate, boolean autoDeploy) { ParameterCheck.mandatoryString("workflowName", workflowName); ParameterCheck.mandatory("workflowParams", workflowParams); @@ -824,8 +824,6 @@ public class SandboxServiceImpl implements SandboxService workflowParams.put(WCMWorkflowModel.PROP_FROM_PATH, WCMUtil.buildStoreRootPath(sbStoreId)); workflowParams.put(WCMWorkflowModel.PROP_LAUNCH_DATE, launchDate); - workflowParams.put(WCMWorkflowModel.PROP_VALIDATE_LINKS, - new Boolean(validateLinks)); workflowParams.put(WCMWorkflowModel.PROP_AUTO_DEPLOY, new Boolean(autoDeploy)); workflowParams.put(WCMWorkflowModel.PROP_WEBAPP, @@ -856,7 +854,7 @@ public class SandboxServiceImpl implements SandboxService public String execute() throws Throwable { // delete AVM stores in the workflow sandbox - sandboxFactory.deleteSandbox(sandboxInfo); + sandboxFactory.deleteSandbox(sandboxInfo, true); return null; } }; @@ -1000,7 +998,7 @@ public class SandboxServiceImpl implements SandboxService logger.debug("unlocking file " + relativePath + " in web project " + wpStoreId); } - if (avmLockingService.getLock(wpStoreId, relativePath) != null) + if (avmLockingService.getLockOwner(wpStoreId, relativePath) != null) { avmLockingService.removeLock(wpStoreId, relativePath); } diff --git a/source/java/org/alfresco/wcm/sandbox/SandboxServiceImplTest.java b/source/java/org/alfresco/wcm/sandbox/SandboxServiceImplTest.java index 40682cb64d..e1923ddd05 100644 --- a/source/java/org/alfresco/wcm/sandbox/SandboxServiceImplTest.java +++ b/source/java/org/alfresco/wcm/sandbox/SandboxServiceImplTest.java @@ -497,8 +497,28 @@ public class SandboxServiceImplTest extends AbstractWCMServiceImplTest sbInfo = sbService.getAuthorSandbox(wpStoreId); assertNotNull(sbInfo); + String defaultWebApp = wpInfo.getDefaultWebApp(); + String authorSandboxId = sbInfo.getSandboxId(); + String authorSandboxPath = sbInfo.getSandboxRootPath() + "/" + defaultWebApp; + + for (int i = 1; i <= 10; i++) + { + assetService.createFile(authorSandboxId, authorSandboxPath, "myFile-"+i, null); + + String relPath = authorSandboxPath + "/" + "myFile-"+i; + assertEquals(USER_TWO, avmLockingService.getLockOwner(wpStoreId, relPath)); + } + // can delete own sandbox sbService.deleteSandbox(sbInfo.getSandboxId()); + assertNull(sbService.getSandbox(sbInfo.getSandboxId())); + + // Check locks have been removed + for (int i = 1; i <= 10; i++) + { + String relPath = authorSandboxPath + "/" + "myFile-"+i; + assertNull("Lock still exists: "+relPath, avmLockingService.getLockOwner(wpStoreId, relPath)); + } assertEquals(3, sbService.listSandboxes(wpStoreId).size()); diff --git a/source/java/org/alfresco/wcm/util/WCMUtil.java b/source/java/org/alfresco/wcm/util/WCMUtil.java index b0a252d876..84e54591ab 100644 --- a/source/java/org/alfresco/wcm/util/WCMUtil.java +++ b/source/java/org/alfresco/wcm/util/WCMUtil.java @@ -765,6 +765,9 @@ public class WCMUtil extends AVMUtil protected final static String SPACE_ICON_WEBSITE = "space-icon-website"; + // Locking constants + public static final String LOCK_KEY_STORE_NAME = "avm-store-name"; + // web user role permissions public static final String ROLE_CONTENT_MANAGER = PermissionService.WCM_CONTENT_MANAGER; public static final String ROLE_CONTENT_PUBLISHER = PermissionService.WCM_CONTENT_PUBLISHER; diff --git a/source/java/org/alfresco/wcm/webproject/WebProjectServiceImpl.java b/source/java/org/alfresco/wcm/webproject/WebProjectServiceImpl.java index 2798aa953e..48eb84b49b 100644 --- a/source/java/org/alfresco/wcm/webproject/WebProjectServiceImpl.java +++ b/source/java/org/alfresco/wcm/webproject/WebProjectServiceImpl.java @@ -64,7 +64,6 @@ import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.DNSNameMangler; -import org.springframework.extensions.surf.util.ParameterCheck; import org.alfresco.wcm.preview.PreviewURIServiceRegistry; import org.alfresco.wcm.sandbox.SandboxConstants; import org.alfresco.wcm.sandbox.SandboxFactory; @@ -73,6 +72,7 @@ import org.alfresco.wcm.sandbox.SandboxFactory.UserRoleWrapper; import org.alfresco.wcm.util.WCMUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.extensions.surf.util.ParameterCheck; /** * Web Project Service Implementation @@ -94,7 +94,6 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService private NodeService nodeService; private SearchService searchService; private AVMService avmService; - private AVMLockingService avmLockingService; private AuthorityService authorityService; private PermissionService permissionService; private PersonService personService; @@ -102,6 +101,7 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService private VirtServerRegistry virtServerRegistry; private PreviewURIServiceRegistry previewURIProviderRegistry; private TransactionService transactionService; + private AVMLockingService avmLockingService; public void setNodeService(NodeService nodeService) { @@ -118,11 +118,6 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService this.avmService = avmService; } - public void setAvmLockingService(AVMLockingService avmLockingService) - { - this.avmLockingService = avmLockingService; - } - public void setAuthorityService(AuthorityService authorityService) { this.authorityService = authorityService; @@ -158,6 +153,11 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService this.transactionService = transactionService; } + public void setAvmLockingService(AVMLockingService avmLockingService) + { + this.avmLockingService = avmLockingService; + } + /* (non-Javadoc) * @see org.alfresco.wcm.WebProjectService#createWebProject(java.lang.String, java.lang.String, java.lang.String, java.lang.String) */ @@ -275,9 +275,6 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService SandboxConstants.PROP_WEB_PROJECT_PREVIEW_PROVIDER, new PropertyValue(DataTypeDefinition.TEXT, previewProviderName)); - // inform the locking service about this new instance - avmLockingService.addWebProject(wpStoreId); - // Snapshot the store with the empty webapp avmService.createSnapshot(wpStoreId, null, null); @@ -756,9 +753,12 @@ public class WebProjectServiceImpl extends WCMUtil implements WebProjectService } // delete sandbox (and associated preview sandbox, if it exists) - sandboxFactory.deleteSandbox(wpStoreId, sbInfo.getSandboxId()); + sandboxFactory.deleteSandbox(sbInfo, false); } + // delete all web project locks in one go (ie. all those currently held against staging store) + avmLockingService.removeLocks(wpStoreId); + StoreRef archiveStoreRef = nodeService.getStoreArchiveNode(wpNodeRef.getStoreRef()).getStoreRef(); // delete the web project node itself diff --git a/source/java/org/alfresco/wcm/webproject/WebProjectServiceImplTest.java b/source/java/org/alfresco/wcm/webproject/WebProjectServiceImplTest.java index 8c30d271c6..32589da601 100644 --- a/source/java/org/alfresco/wcm/webproject/WebProjectServiceImplTest.java +++ b/source/java/org/alfresco/wcm/webproject/WebProjectServiceImplTest.java @@ -38,9 +38,7 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.AuthorityService; import org.alfresco.service.cmr.security.AuthorityType; -import org.alfresco.service.cmr.security.MutableAuthenticationService; import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.cmr.security.PersonService; import org.alfresco.wcm.AbstractWCMServiceImplTest; import org.alfresco.wcm.asset.AssetInfo; import org.alfresco.wcm.sandbox.SandboxInfo; @@ -81,7 +79,6 @@ public class WebProjectServiceImplTest extends AbstractWCMServiceImplTest private PermissionService permissionService; private AVMService avmService; private NodeService nodeService; - @Override protected void setUp() throws Exception @@ -89,8 +86,6 @@ public class WebProjectServiceImplTest extends AbstractWCMServiceImplTest super.setUp(); // Get the required services - authenticationService = (MutableAuthenticationService)ctx.getBean("AuthenticationService"); - personService = (PersonService)ctx.getBean("PersonService"); fileFolderService = (FileFolderService)ctx.getBean("FileFolderService"); authorityService = (AuthorityService)ctx.getBean("AuthorityService"); permissionService = (PermissionService)ctx.getBean("PermissionService"); @@ -518,12 +513,33 @@ public class WebProjectServiceImplTest extends AbstractWCMServiceImplTest } // Switch back to admin - AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName()); + String adminUser = AuthenticationUtil.getAdminUserName(); + AuthenticationUtil.setFullyAuthenticatedUser(adminUser); + + String defaultWebApp = wpInfo.getDefaultWebApp(); + SandboxInfo sbInfo = sbService.getAuthorSandbox(wpStoreId); + String authorSandboxId = sbInfo.getSandboxId(); + String authorSandboxPath = sbInfo.getSandboxRootPath() + "/" + defaultWebApp; + + for (int i = 1; i <= 10; i++) + { + assetService.createFile(authorSandboxId, authorSandboxPath, "myFile-"+i, null); + + String relPath = authorSandboxPath + "/" + "myFile-"+i; + assertEquals(adminUser, avmLockingService.getLockOwner(wpStoreId, relPath)); + } // Delete the web project wpService.deleteWebProject(wpStoreId); assertNull(wpService.getWebProject(wpStoreId)); + // Check locks have been removed + for (int i = 1; i <= 10; i++) + { + String relPath = authorSandboxPath + "/" + "myFile-"+i; + assertNull("Lock still exists: "+relPath, avmLockingService.getLockOwner(wpStoreId, relPath)); + } + assertEquals(0, sbService.listSandboxes(wpStoreId).size()); assertEquals(2, sbService.listSandboxes(wpStoreAnoId).size()); @@ -572,16 +588,16 @@ public class WebProjectServiceImplTest extends AbstractWCMServiceImplTest wpStoreId = wpInfo.getStoreId(); NodeRef wpNodeRef = wpInfo.getNodeRef(); - String defaultWebApp = wpInfo.getDefaultWebApp(); + defaultWebApp = wpInfo.getDefaultWebApp(); - SandboxInfo sbInfo = sbService.getAuthorSandbox(wpStoreId); - final String authorSandboxId = sbInfo.getSandboxId(); + sbInfo = sbService.getAuthorSandbox(wpStoreId); + authorSandboxId = sbInfo.getSandboxId(); // no changes yet List assets = sbService.listChangedAll(authorSandboxId, true); assertEquals(0, assets.size()); - String authorSandboxPath = sbInfo.getSandboxRootPath() + "/" + defaultWebApp; + authorSandboxPath = sbInfo.getSandboxRootPath() + "/" + defaultWebApp; for (int i = 1; i <= 100; i++) { diff --git a/source/test-resources/tenant/mt-context.xml b/source/test-resources/tenant/mt-context.xml index d2a1d3f43a..90645167f8 100644 --- a/source/test-resources/tenant/mt-context.xml +++ b/source/test-resources/tenant/mt-context.xml @@ -28,9 +28,6 @@ - - - org.alfresco.tenantsTransactionalCache