diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml index b5017e9377..b3efd3f861 100644 --- a/config/alfresco/bootstrap-context.xml +++ b/config/alfresco/bootstrap-context.xml @@ -48,6 +48,7 @@ + @@ -73,7 +74,7 @@ - + @@ -266,27 +267,27 @@ - - - - jbpm - alfresco/workflow/review_processdefinition.xml - text/xml - false - - - jbpm - alfresco/workflow/adhoc_processdefinition.xml - text/xml - false - - + + + + jbpm + alfresco/workflow/review_processdefinition.xml + text/xml + false + + + jbpm + alfresco/workflow/adhoc_processdefinition.xml + text/xml + false + + - jbpm - alfresco/workflow/submit_processdefinition.xml - text/xml - false - + jbpm + alfresco/workflow/submit_processdefinition.xml + text/xml + false + jbpm @@ -294,22 +295,22 @@ text/xml false - - - - + + + + alfresco/workflow/workflowModel.xml alfresco/workflow/wcmWorkflowModel.xml - - - - - alfresco/workflow/workflow-messages + + + + + alfresco/workflow/workflow-messages alfresco/workflow/wcm-workflow-messages - - - - + + + + @@ -319,7 +320,7 @@ - classpath:alfresco/version.properties + classpath:alfresco/version.properties @@ -446,7 +447,7 @@ - + @@ -459,12 +460,12 @@ - + - + - + diff --git a/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-2.2-ACL.sql b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-2.2-ACL.sql new file mode 100644 index 0000000000..591eaa0875 --- /dev/null +++ b/config/alfresco/dbscripts/upgrade/2.2/org.hibernate.dialect.MySQLInnoDBDialect/AlfrescoSchemaUpdate-2.2-ACL.sql @@ -0,0 +1,154 @@ +-- +-- Title: Update for permissions schema changes +-- Database: MySQL InnoDB +-- Since: V2.2 Schema 85 +-- Author: Andy Hind +-- +-- Please contact support@alfresco.com if you need assistance with the upgrade. +-- + +CREATE TABLE alf_acl_change_set ( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + primary key (id) +) type=InnoDB; + + +-- Add to ACL +ALTER TABLE alf_access_control_list + ADD COLUMN type INT NOT NULL DEFAULT 0, + ADD COLUMN latest BOOLEAN NOT NULL DEFAULT TRUE, + ADD COLUMN acl_id VARCHAR(36) NOT NULL DEFAULT 'UNSET', + ADD COLUMN acl_version BIGINT NOT NULL DEFAULT 1, + ADD COLUMN inherited_acl BIGINT, + ADD COLUMN is_versioned BOOLEAN NOT NULL DEFAULT FALSE, + ADD COLUMN requires_version BOOLEAN NOT NULL DEFAULT FALSE, + ADD COLUMN acl_change_set BIGINT, + ADD COLUMN inherits_from BIGINT, + ADD INDEX FK_ACL_CH_SET (acl_change_set), + ADD CONSTRAINT FOREIGN KEY FK_ACL_CH_SET (acl_change_set) REFERENCES alf_acl_change_set (id); + +UPDATE alf_access_control_list acl + set acl_id = (acl.id); + +ALTER TABLE alf_access_control_list + ADD UNIQUE (acl_id, latest, acl_version); + +-- Create ACL member list +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 INT NOT NULL, + primary key (id), + unique(acl_id, ace_id, pos), + index FK_ACL_ID (acl_id), + CONSTRAINT FOREIGN KEY FK_ACL_ID (acl_id) REFERENCES alf_access_control_list (id), + index FK_ACE_ID (ace_id), + CONSTRAINT FOREIGN KEY FK_ACE_ID (ace_id) REFERENCES alf_access_control_entry (id) +) type=InnoDB; + + + +ALTER TABLE alf_access_control_entry DROP INDEX acl_id; + +-- Extend ACE +ALTER TABLE alf_access_control_entry + ADD COLUMN auth_id BIGINT NOT NULL DEFAULT -1, + ADD COLUMN applies INT NOT NULL DEFAULT 0, + ADD COLUMN context_id BIGINT; + +-- remove unused +DROP TABLE alf_auth_ext_keys; + +-- remove authority constraint +ALTER TABLE alf_access_control_entry + DROP FOREIGN KEY FKFFF41F99B25A50BF; + +-- restructure authority +ALTER TABLE alf_authority + DROP PRIMARY KEY, + ADD COLUMN id BIGINT NOT NULL AUTO_INCREMENT, + CHANGE recipient authority VARCHAR(100), + ADD primary key (id), + ADD CONSTRAINT UNIQUE INDEX U_AUTH (authority); + +-- migrate data - fix up FK refs to authority +UPDATE alf_access_control_entry ace + set auth_id = (select id from alf_authority a where a.authority = ace.authority_id); + + +-- migrate data - build equivalent ACL entries +INSERT INTO alf_acl_member (version, acl_id, ace_id, pos) + select 1, acl_id, id, 0 from alf_access_control_entry; + +-- Create ACE context +CREATE TABLE alf_ace_context ( + id BIGINT NOT NULL AUTO_INCREMENT, + version BIGINT NOT NULL, + class_context VARCHAR(1024), + property_context VARCHAR(1024), + kvp_context VARCHAR(1024), + primary key (id) + ) type=InnoDB; + + +-- Create auth aliases table +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), + INDEX FK_ALIAS_TO_AUTH (alias_id), + CONSTRAINT FOREIGN KEY FK_ALIAS_TO_AUTH (alias_id) REFERENCES alf_authority (id), + INDEX FK_AUTH_TO_AUTH (auth_id), + CONSTRAINT FOREIGN KEY FK_AUTH_TO_AUTH (auth_id) REFERENCES alf_authority (id), + CONSTRAINT UNIQUE INDEX U_AUTH_TO_ALIAS (auth_id, alias_id) +) type=InnoDB; + + +-- Tidy up unused cols on ace table and add the FK contstraint back +-- finish take out of ACL_ID +ALTER TABLE alf_access_control_entry + DROP FOREIGN KEY FKFFF41F99B9553F6C, + DROP COLUMN acl_id, + DROP COLUMN authority_id, + CHANGE auth_id authority_id BIGINT NOT NULL, + ADD INDEX FK_ACL_TO_AUTH (authority_id), + ADD CONSTRAINT FOREIGN KEY FK_ACL_TO_AUTH (authority_id) REFERENCES alf_authority (id); + + +-- Update members to point to the first use of an access control entry +UPDATE alf_acl_member mem + SET ace_id = (SELECT min(ace2.id) FROM alf_access_control_entry ace1 + JOIN alf_access_control_entry ace2 + ON ace1.permission_id = ace2.permission_id AND + ace1.authority_id = ace2.authority_id AND + ace1.allowed = ace2.allowed AND + ace1.applies = ace2.applies + WHERE ace1.id = mem.ace_id ); + +-- Remove duplicate aces the mysql way (as you can not use the deleted table in the where clause ...) + +CREATE TEMPORARY TABLE tmp_to_delete SELECT ace.id FROM alf_acl_member mem RIGHT OUTER JOIN alf_access_control_entry ace ON mem.ace_id = ace.id WHERE mem.ace_id IS NULL; +DELETE FROM alf_access_control_entry ace USING alf_access_control_entry ace JOIN tmp_to_delete t ON ace.id = t.id; +DROP TEMPORARY TABLE tmp_to_delete; + +-- Add constraint for duplicate acls + +ALTER TABLE alf_access_control_entry + ADD UNIQUE (permission_id, authority_id, allowed, applies, context_id); + +-- +-- Record script finish +-- +DELETE FROM alf_applied_patch WHERE id = 'patch.db-V2.2-ACL'; +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-V2.2-ACL', 'Manually executed script upgrade V2.2: Update acl schema', + 0, 76, -1, 77, null, 'UNKOWN', 1, 1, 'Script completed' + ); \ No newline at end of file diff --git a/config/alfresco/ehcache-default.xml b/config/alfresco/ehcache-default.xml index 6e734bb280..a0e99d16ba 100644 --- a/config/alfresco/ehcache-default.xml +++ b/config/alfresco/ehcache-default.xml @@ -112,16 +112,9 @@ overflowToDisk="false" /> - + - - - + + + + + + + @@ -147,10 +161,10 @@ eternal="true" overflowToDisk="false" /> - + @@ -173,31 +187,31 @@ eternal="true" overflowToDisk="false" /> - - - - - + + + + + - - + diff --git a/config/alfresco/hibernate-context.xml b/config/alfresco/hibernate-context.xml index 920ec7815d..6d16d55ba8 100644 --- a/config/alfresco/hibernate-context.xml +++ b/config/alfresco/hibernate-context.xml @@ -159,26 +159,24 @@ ${cache.strategy} ${cache.strategy} - ${cache.strategy} + ${cache.strategy} ${cache.strategy} - ${cache.strategy} + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} ${cache.strategy} - - ${cache.strategy} - ${cache.strategy} - ${cache.strategy} + ${cache.strategy} + + ${cache.strategy} + ${cache.strategy} + ${cache.strategy} ${cache.strategy} ${cache.strategy} - - - ${cache.strategy} - ${cache.strategy} @@ -200,9 +198,25 @@ - - - + + + org.alfresco.repo.security.permissions.impl.PermissionsDaoComponent + + + + + + + + + + + + + + + + @@ -211,24 +225,48 @@ - - + + - - - - + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -257,12 +295,6 @@ - - - - - - org.alfresco.repo.node.db.NodeDaoService @@ -285,7 +317,7 @@ - + diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties index 9e3e2935e1..22342af3b2 100644 --- a/config/alfresco/messages/patch-service.properties +++ b/config/alfresco/messages/patch-service.properties @@ -200,3 +200,9 @@ patch.deploymentMigration.webProjectName=Migrating deployment data for web proje patch.deploymentMigration.serverMigrated=Server ''{0}'' from web project ''{1}'' has been migrated patch.deploymentMigration.reportMigrated=Deployment report for ''{0}'' from web project ''{1}'' has been migrated patch.deploymentMigration.result=Deployment data has been migrated. + +patch.updateAvmPermissionData.description=Update avm permissions from 'webfolder' to 'cmobject'. +patch.updateAvmPermissionData.result=Changed {0} 'webfolder' access control entries to 'cmobject'. + +patch.updateAvmPermissions.description=Update ACLs on all avm objects to the new 2.2 permission model +patch.updateAvmPermissions.result=Updated ACLs. Created {0} defining and {1} layered ACLs. diff --git a/config/alfresco/model/permissionDefinitions.xml b/config/alfresco/model/permissionDefinitions.xml index af88e9bef0..7c72635b37 100644 --- a/config/alfresco/model/permissionDefinitions.xml +++ b/config/alfresco/model/permissionDefinitions.xml @@ -19,6 +19,7 @@ + @@ -286,8 +287,8 @@ - - + + @@ -341,6 +342,23 @@ + + + + + + + + + + + + + + + + + @@ -358,29 +376,73 @@ + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + --> + + + + + + + --> + + + + + + + --> + + + + + + + --> + + + + + + + --> + + + + + + + --> + + + + + + + --> + + + + diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index ed4743d86e..6ab42d25aa 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -4,15 +4,15 @@ - - org.alfresco.repo.admin.patch.PatchService - - - + + org.alfresco.repo.admin.patch.PatchService + + + - - + + @@ -572,7 +572,7 @@ - + patch.LinkNodeFileExtension patch.linkNodeExtension.description @@ -608,8 +608,8 @@ - - + + patch.userAndPersonUserNamesAsIdentifiers patch.userAndPersonUserNamesAsIdentifiers.description 0 @@ -619,10 +619,10 @@ - + - + @@ -660,7 +660,7 @@ classpath:alfresco/dbscripts/upgrade/2.1/${db.script.dialect}/AlfrescoSchemaUpdate-2.1-NotNullColumns.sql - + patch.groupNamesAsIdentifiers patch.groupNamesAsIdentifiers.description @@ -675,8 +675,8 @@ - - + + patch.invalidUserPersonAndGroup patch.invalidUserPersonAndGroup.description 0 @@ -686,10 +686,10 @@ - + - + @@ -752,7 +752,7 @@ - + patch.groupMembersAsIdentifiers patch.groupMembersAsIdentifiers.description 0 @@ -1247,4 +1247,54 @@ + + patch.db-V2.2-ACL + patch.schemaUpgradeScript.description + 0 + 119 + 120 + + classpath:alfresco/dbscripts/upgrade/2.2/${db.script.dialect}/AlfrescoSchemaUpdate-2.2-ACL.sql + + + + + + + + + + patch.updateAvmPermissionData + patch.updateAvmPermissionData.description + 0 + 119 + 120 + + + + + + + + + + + + + patch.updateAvmPermissions + patch.updateAvmPermissions.description + 0 + 119 + 120 + + + + + + + + + + + \ No newline at end of file diff --git a/config/alfresco/public-services-security-context.xml b/config/alfresco/public-services-security-context.xml index 6d019ee03d..e6d774e3c2 100644 --- a/config/alfresco/public-services-security-context.xml +++ b/config/alfresco/public-services-security-context.xml @@ -35,6 +35,10 @@ + + @@ -63,10 +67,9 @@ - - - - + + + @@ -74,6 +77,43 @@ + + + + diff --git a/config/alfresco/scheduled-jobs-context.xml b/config/alfresco/scheduled-jobs-context.xml index e87685609f..ba04fe140e 100644 --- a/config/alfresco/scheduled-jobs-context.xml +++ b/config/alfresco/scheduled-jobs-context.xml @@ -232,7 +232,6 @@ - @@ -326,4 +325,9 @@ + + + + + \ No newline at end of file diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties index f8d6270f48..affa26c5a7 100644 --- a/config/alfresco/version.properties +++ b/config/alfresco/version.properties @@ -19,4 +19,4 @@ version.build=@build-number@ # Schema number -version.schema=119 +version.schema=120 diff --git a/source/java/org/alfresco/email/server/handler/AbstractEmailMessageHandler.java b/source/java/org/alfresco/email/server/handler/AbstractEmailMessageHandler.java index 7cc36ab631..3aec457fb0 100644 --- a/source/java/org/alfresco/email/server/handler/AbstractEmailMessageHandler.java +++ b/source/java/org/alfresco/email/server/handler/AbstractEmailMessageHandler.java @@ -39,6 +39,8 @@ import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.encoding.ContentCharsetFinder; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.email.EmailMessage; +import org.alfresco.service.cmr.email.EmailMessagePart; +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.MimetypeService; @@ -47,6 +49,7 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.SearchService; +import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -255,4 +258,113 @@ public abstract class AbstractEmailMessageHandler implements EmailMessageHandler log.debug("Emailed aspect has been added."); } } + + /** + * Add new node into Alfresco repository with specified parameters. Node content isn't added. + * + * @param nodeService Alfresco Node Service + * @param parent Parent node + * @param name Name of the new node + * @param assocType Association type that should be set between parent node and the new one. + * @return Reference to created node + */ + protected NodeRef addContentNode(NodeService nodeService, NodeRef parent, String name, QName assocType) + { + NodeRef childNodeRef = nodeService.getChildByName(parent, assocType, name); + if (childNodeRef != null) + { + // The node is present already. Make sure the name csae is correct + nodeService.setProperty(childNodeRef, ContentModel.PROP_NAME, name); + } + else + { + Map contentProps = new HashMap(); + contentProps.put(ContentModel.PROP_NAME, name); + ChildAssociationRef associationRef = nodeService.createNode( + parent, + assocType, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name), + ContentModel.TYPE_CONTENT, + contentProps); + childNodeRef = associationRef.getChildRef(); + } + return childNodeRef; + } + + /** + * Add new node into Alfresco repository with specified parameters. + * Node content isn't added. New node will be created with ContentModel.ASSOC_CONTAINS association with parent. + * + * @param nodeService Alfresco Node Service + * @param parent Parent node + * @param name Name of the new node + * @return Reference to created node + */ + protected NodeRef addContentNode(NodeService nodeService, NodeRef parent, String name) + { + return addContentNode(nodeService, parent, name, ContentModel.ASSOC_CONTAINS); + } + + /** + * Adds new node into Alfresco repository and mark its as an attachment. + * + * @param nodeService Alfresco Node Service. + * @param folder Space/Folder to add. + * @param mainContentNode Main content node. Any mail is added into Alfresco as one main content node and several its attachments. Each attachment related with its main node. + * @param fileName File name for the attachment. + * @return Reference to created node. + */ + protected NodeRef addAttachment(NodeService nodeService, NodeRef folder, NodeRef mainContentNode, String fileName) + { + if (log.isDebugEnabled()) + { + log.debug("Adding attachment node (name=" + fileName + ")."); + } + + NodeRef attachmentNode = addContentNode(nodeService, folder, fileName); + + // Remove 'attached' aspect so that we work with the document in its clean form + if (nodeService.hasAspect(attachmentNode, EmailServerModel.ASPECT_ATTACHED)) + { + nodeService.removeAspect(attachmentNode, EmailServerModel.ASPECT_ATTACHED); + } + + // Add attached aspect + nodeService.addAspect(attachmentNode, EmailServerModel.ASPECT_ATTACHED, null); + // Recreate the association + nodeService.createAssociation(attachmentNode, mainContentNode, EmailServerModel.ASSOC_ATTACHMENT); + + if (log.isDebugEnabled()) + { + log.debug("Attachment has been added."); + } + return attachmentNode; + } + + /** + * Extracts the attachments from the given message and adds them to the space. All attachments + * are linked back to the original node that they are attached to. + * + * @param spaceNodeRef the space to add the documents into + * @param nodeRef the node to which the documents will be attached + * @param message the email message + */ + protected void addAttachments(NodeRef spaceNodeRef, NodeRef nodeRef, EmailMessage message) + { + // Add attachments + EmailMessagePart[] attachments = message.getAttachments(); + for (EmailMessagePart attachment : attachments) + { + String fileName = attachment.getFileName(); + + InputStream contentIs = attachment.getContent(); + + MimetypeService mimetypeService = getMimetypeService(); + String mimetype = mimetypeService.guessMimetype(fileName); + String encoding = attachment.getEncoding(); + + NodeRef attachmentNode = addAttachment(getNodeService(), spaceNodeRef, nodeRef, fileName); + writeContent(attachmentNode, contentIs, mimetype, encoding); + } + } } diff --git a/source/java/org/alfresco/email/server/handler/AbstractForumEmailMessageHandler.java b/source/java/org/alfresco/email/server/handler/AbstractForumEmailMessageHandler.java index 61dbc65dae..da98906522 100644 --- a/source/java/org/alfresco/email/server/handler/AbstractForumEmailMessageHandler.java +++ b/source/java/org/alfresco/email/server/handler/AbstractForumEmailMessageHandler.java @@ -54,10 +54,11 @@ public abstract class AbstractForumEmailMessageHandler extends AbstractEmailMess /** * Posts content * - * @param nodeRef Reference to node - * @param parser Mail parser + * @param nodeRef Reference to node + * @param parser Mail parser + * @return Returns the new post node */ - protected void addPostNode(NodeRef nodeRef, EmailMessage message) + protected NodeRef addPostNode(NodeRef nodeRef, EmailMessage message) { NodeService nodeService = getNodeService(); Date now = new Date(); @@ -66,8 +67,8 @@ public abstract class AbstractForumEmailMessageHandler extends AbstractEmailMess PropertyMap properties = new PropertyMap(3); properties.put(ContentModel.PROP_NAME, nodeName); - NodeRef postNode = nodeService.getChildByName(nodeRef, ContentModel.ASSOC_CONTAINS, nodeName); - if (postNode == null) + NodeRef postNodeRef = nodeService.getChildByName(nodeRef, ContentModel.ASSOC_CONTAINS, nodeName); + if (postNodeRef == null) { ChildAssociationRef childAssoc = nodeService.createNode( nodeRef, @@ -75,27 +76,34 @@ public abstract class AbstractForumEmailMessageHandler extends AbstractEmailMess QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, nodeName), ForumModel.TYPE_POST, properties); - postNode = childAssoc.getChildRef(); + postNodeRef = childAssoc.getChildRef(); } // Add necessary aspects properties.clear(); properties.put(ContentModel.PROP_TITLE, nodeName); - nodeService.addAspect(postNode, ContentModel.ASPECT_TITLED, properties); + nodeService.addAspect(postNodeRef, ContentModel.ASPECT_TITLED, properties); properties.clear(); properties.put(ApplicationModel.PROP_EDITINLINE, true); - nodeService.addAspect(postNode, ApplicationModel.ASPECT_INLINEEDITABLE, properties); + nodeService.addAspect(postNodeRef, ApplicationModel.ASPECT_INLINEEDITABLE, properties); // Write content if (message.getBody() != null) { - writeContent(postNode, message.getBody().getContent(), message.getBody().getContentType(), message.getBody().getEncoding()); + writeContent( + postNodeRef, + message.getBody().getContent(), + message.getBody().getContentType(), + message.getBody().getEncoding()); } else { - writeContent(postNode, ""); + writeContent(postNodeRef, ""); } - addEmailedAspect(postNode, message); + addEmailedAspect(postNodeRef, message); + + // Done + return postNodeRef; } /** diff --git a/source/java/org/alfresco/email/server/handler/DocumentEmailMessageHandler.java b/source/java/org/alfresco/email/server/handler/DocumentEmailMessageHandler.java index 1d6a6d4269..dca0eda528 100644 --- a/source/java/org/alfresco/email/server/handler/DocumentEmailMessageHandler.java +++ b/source/java/org/alfresco/email/server/handler/DocumentEmailMessageHandler.java @@ -51,7 +51,7 @@ public class DocumentEmailMessageHandler extends AbstractForumEmailMessageHandle { private static final String forumNodeName = "EmailForum"; - public void processMessage(NodeRef nodeRef, EmailMessage message) + public void processMessage(NodeRef contentNodeRef, EmailMessage message) { String messageSubject; @@ -64,27 +64,34 @@ public class DocumentEmailMessageHandler extends AbstractForumEmailMessageHandle messageSubject = "EMPTY_SUBJECT_" + System.currentTimeMillis(); } - QName nodeTypeQName = getNodeService().getType(nodeRef); + QName nodeTypeQName = getNodeService().getType(contentNodeRef); DictionaryService dictionaryService = getDictionaryService(); if (dictionaryService.isSubClass(nodeTypeQName, ContentModel.TYPE_CONTENT)) { - NodeRef forumNode = getForumNode(nodeRef); + // Find where the content resides + NodeRef spaceNodeRef = getNodeService().getPrimaryParent(contentNodeRef).getParentRef(); + + NodeRef forumNode = getForumNode(contentNodeRef); if (forumNode == null) { - forumNode = addForumNode(nodeRef); + forumNode = addForumNode(contentNodeRef); } // Try to find existed node - NodeRef topicNode = getTopicNode(forumNode, messageSubject); + NodeRef topicNodeRef = getTopicNode(forumNode, messageSubject); - if (topicNode == null) + if (topicNodeRef == null) { - topicNode = addTopicNode(forumNode, messageSubject); + topicNodeRef = addTopicNode(forumNode, messageSubject); } - addPostNode(topicNode, message); + // Create the post + NodeRef postNodeRef = addPostNode(topicNodeRef, message); + + // Add attachments + addAttachments(spaceNodeRef, postNodeRef, message); } else { diff --git a/source/java/org/alfresco/email/server/handler/FolderEmailMessageHandler.java b/source/java/org/alfresco/email/server/handler/FolderEmailMessageHandler.java index 0153d4dd94..af0b951ec8 100644 --- a/source/java/org/alfresco/email/server/handler/FolderEmailMessageHandler.java +++ b/source/java/org/alfresco/email/server/handler/FolderEmailMessageHandler.java @@ -34,19 +34,14 @@ import java.util.Map; import javax.mail.MessagingException; -import org.alfresco.email.server.EmailServerModel; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.i18n.I18NUtil; import org.alfresco.model.ContentModel; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.service.cmr.email.EmailMessage; import org.alfresco.service.cmr.email.EmailMessageException; -import org.alfresco.service.cmr.email.EmailMessagePart; -import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.MimetypeService; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -140,101 +135,7 @@ public class FolderEmailMessageHandler extends AbstractEmailMessageHandler } // Add attachments - EmailMessagePart[] attachments = message.getAttachments(); - for (EmailMessagePart attachment : attachments) - { - String fileName = attachment.getFileName(); - - InputStream contentIs = attachment.getContent(); - - MimetypeService mimetypeService = getMimetypeService(); - String mimetype = mimetypeService.guessMimetype(fileName); - String encoding = attachment.getEncoding(); - - NodeRef attachmentNode = addAttachment(getNodeService(), spaceNodeRef, contentNodeRef, fileName); - writeContent(attachmentNode, contentIs, mimetype, encoding); - } - } - - /** - * Add new node into Alfresco repository with specified parameters. Node content isn't added. New node will be created with ContentModel.ASSOC_CONTAINS association with parent. - * - * @param nodeService Alfresco Node Service - * @param parent Parent node - * @param name Name of the new node - * @return Reference to created node - */ - private NodeRef addContentNode(NodeService nodeService, NodeRef parent, String name) - { - return addContentNode(nodeService, parent, name, ContentModel.ASSOC_CONTAINS); - } - - /** - * Add new node into Alfresco repository with specified parameters. Node content isn't added. - * - * @param nodeService Alfresco Node Service - * @param parent Parent node - * @param name Name of the new node - * @param assocType Association type that should be set between parent node and the new one. - * @return Reference to created node - */ - private NodeRef addContentNode(NodeService nodeService, NodeRef parent, String name, QName assocType) - { - NodeRef childNodeRef = nodeService.getChildByName(parent, assocType, name); - if (childNodeRef != null) - { - // The node is present already. Make sure the name csae is correct - nodeService.setProperty(childNodeRef, ContentModel.PROP_NAME, name); - } - else - { - Map contentProps = new HashMap(); - contentProps.put(ContentModel.PROP_NAME, name); - ChildAssociationRef associationRef = nodeService.createNode( - parent, - assocType, - QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, name), - ContentModel.TYPE_CONTENT, - contentProps); - childNodeRef = associationRef.getChildRef(); - } - return childNodeRef; - } - - /** - * Adds new node into Alfresco repository and mark its as an attachment. - * - * @param nodeService Alfresco Node Service. - * @param folder Space/Folder to add. - * @param mainContentNode Main content node. Any mail is added into Alfresco as one main content node and several its attachments. Each attachment related with its main node. - * @param fileName File name for the attachment. - * @return Reference to created node. - */ - private NodeRef addAttachment(NodeService nodeService, NodeRef folder, NodeRef mainContentNode, String fileName) - { - if (log.isDebugEnabled()) - { - log.debug("Adding attachment node (name=" + fileName + ")."); - } - - NodeRef attachmentNode = addContentNode(nodeService, folder, fileName); - - // Remove 'attached' aspect so that we work with the document in its clean form - if (nodeService.hasAspect(attachmentNode, EmailServerModel.ASPECT_ATTACHED)) - { - nodeService.removeAspect(attachmentNode, EmailServerModel.ASPECT_ATTACHED); - } - - // Add attached aspect - nodeService.addAspect(attachmentNode, EmailServerModel.ASPECT_ATTACHED, null); - // Recreate the association - nodeService.createAssociation(attachmentNode, mainContentNode, EmailServerModel.ASSOC_ATTACHMENT); - - if (log.isDebugEnabled()) - { - log.debug("Attachment has been added."); - } - return attachmentNode; + addAttachments(spaceNodeRef, contentNodeRef, message); } /** diff --git a/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailMessage.java b/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailMessage.java index 3c1862441b..d60ae83f98 100644 --- a/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailMessage.java +++ b/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailMessage.java @@ -32,6 +32,7 @@ import java.util.LinkedList; import java.util.List; import javax.mail.Address; +import javax.mail.BodyPart; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Part; @@ -176,13 +177,13 @@ public class SubethaEmailMessage implements EmailMessage sentDate = new Date(); // Just anti-null stub :) } - parseMesagePart(mimeMessage); + parseMessagePart(mimeMessage); attachments = new EmailMessagePart[attachmentList.size()]; attachmentList.toArray(attachments); attachmentList = null; } - private void parseMesagePart(Part messagePart) + private void parseMessagePart(Part messagePart) { try { @@ -231,7 +232,18 @@ public class SubethaEmailMessage implements EmailMessage } for (int i = 0; i < count; i++) { - parseMesagePart(mp.getBodyPart(i)); + BodyPart bp = mp.getBodyPart(i); + String disposition = bp.getDisposition(); + if (i > 0) + { + // It's an attachment. Recurse. + parseMessagePart(bp); + } + else + { + // It's the body + addBody(messagePart); + } } if (log.isDebugEnabled()) @@ -248,7 +260,7 @@ public class SubethaEmailMessage implements EmailMessage log.debug("MIME_RFC822 part found. Processing inside part..."); } - parseMesagePart((Part) messagePart.getContent()); + parseMessagePart((Part) messagePart.getContent()); if (log.isDebugEnabled()) { @@ -281,27 +293,15 @@ public class SubethaEmailMessage implements EmailMessage { if (body != null) { - if (!MIME_PLAIN_TEXT.equals(body.getContentType()) && messagePart.isMimeType(MIME_PLAIN_TEXT)) + attachmentList.add(new SubethaEmailMessagePart(messagePart, getPartFileName(getSubject() + " (part " + ++bodyNumber + ")", messagePart))); + if (log.isInfoEnabled()) { - attachmentList.add(body); - body = new SubethaEmailMessagePart(messagePart); - if (log.isDebugEnabled()) - { - log.debug("Body has been changed to the new one."); - } - } - else - { - attachmentList.add(new SubethaEmailMessagePart(messagePart, getPartFileName(getSubject() + " (part " + ++bodyNumber + ")", messagePart))); - if (log.isInfoEnabled()) - { - log.info(String.format("Attachment \"%s\" has been added.", attachmentList.get(attachmentList.size() - 1).getFileName())); - } + log.info(String.format("Attachment \"%s\" has been added.", attachmentList.get(attachmentList.size() - 1).getFileName())); } } else { - body = new SubethaEmailMessagePart(messagePart, getPartFileName(getSubject() + " (part " + ++bodyNumber + ")", messagePart)); + body = new SubethaEmailMessagePart(messagePart, getPartFileName(getSubject(), messagePart)); if (log.isDebugEnabled()) { log.debug("Boby has been added."); @@ -319,7 +319,7 @@ public class SubethaEmailMessage implements EmailMessage */ private void addAttachment(Part messagePart) throws MessagingException { - String fileName = getPartFileName(FILENAME_ATTACHMENT_PREFIX + ++attachmentNumber, messagePart); + String fileName = getPartFileName(FILENAME_ATTACHMENT_PREFIX + attachmentNumber, messagePart); attachmentList.add(new SubethaEmailMessagePart(messagePart, fileName)); if (log.isDebugEnabled()) { diff --git a/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java b/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java index 0201a5f617..94d4d2f4e4 100644 --- a/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java +++ b/source/java/org/alfresco/email/server/impl/subetha/SubethaEmailServer.java @@ -126,39 +126,46 @@ public class SubethaEmailServer extends EmailServer public void data(InputStream data) throws TooMuchDataException, IOException, RejectException { - if (deliveries.size() == 1) + if (deliveries.size() > 0) { Delivery delivery = deliveries.get(0); processDelivery(delivery, data); } - else if (deliveries.size() > 1) - { - DeferredFileOutputStream dfos = null; - try - { - dfos = new DeferredFileOutputStream(DEFAULT_DATA_DEFERRED_SIZE); - - byte[] bytes = new byte[1024 * 8]; - for (int len = -1; (len = data.read(bytes)) != -1;) - { - dfos.write(bytes, 0, len); - } - for (Delivery delivery : deliveries) - { - processDelivery(delivery, dfos.getInputStream()); - } - } - finally - { - try - { - dfos.close(); - } - catch (Exception e) - { - } - } - } +// Duplicate messages coming in +// http://www.subethamail.org/se/archive_msg.jsp?msgId=20938 +// if (deliveries.size() == 1) +// { +// Delivery delivery = deliveries.get(0); +// processDelivery(delivery, data); +// } +// else if (deliveries.size() > 1) +// { +// DeferredFileOutputStream dfos = null; +// try +// { +// dfos = new DeferredFileOutputStream(DEFAULT_DATA_DEFERRED_SIZE); +// +// byte[] bytes = new byte[1024 * 8]; +// for (int len = -1; (len = data.read(bytes)) != -1;) +// { +// dfos.write(bytes, 0, len); +// } +// for (Delivery delivery : deliveries) +// { +// processDelivery(delivery, dfos.getInputStream()); +// } +// } +// finally +// { +// try +// { +// dfos.close(); +// } +// catch (Exception e) +// { +// } +// } +// } } private void processDelivery(Delivery delivery, InputStream data) throws RejectException diff --git a/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionDataPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionDataPatch.java new file mode 100644 index 0000000000..922970fe01 --- /dev/null +++ b/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionDataPatch.java @@ -0,0 +1,64 @@ +/* + * 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.admin.patch.impl; + +import org.alfresco.i18n.I18NUtil; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + + +/** + * The roles defined in permissionsDefinition.xml moved from wca:webfolder to cm:cmobject. + * This effects the data stored in the permission table. + *

+ * + */ +public class AVMPermissionDataPatch extends AbstractPermissionChangePatch +{ + private static final String MSG_SUCCESS = "patch.updateAvmPermissionData.result"; + + private static final QName TYPE_QNAME_OLD = QName.createQName(NamespaceService.WCMAPP_MODEL_1_0_URI, "webfolder"); + private static final QName TYPE_QNAME_NEW = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "cmobject"); + private static final String[] NAMES = new String[] {"ContentManager", "ContentPublisher", "ContentContributor", "ContentReviewer"}; + + @Override + protected String applyInternal() throws Exception + { + int updateCount = 0; + for (String permissionName : NAMES) + { + updateCount += super.renamePermission( + AVMPermissionDataPatch.TYPE_QNAME_OLD, + permissionName, + AVMPermissionDataPatch.TYPE_QNAME_NEW, + permissionName); + } + + // build the result message + String msg = I18NUtil.getMessage(MSG_SUCCESS, updateCount); + // done + return msg; + } +} diff --git a/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionsPatch.java b/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionsPatch.java new file mode 100644 index 0000000000..5356ba7ec3 --- /dev/null +++ b/source/java/org/alfresco/repo/admin/patch/impl/AVMPermissionsPatch.java @@ -0,0 +1,60 @@ +/* + * 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.admin.patch.impl; + +import java.util.Map; + +import org.alfresco.i18n.I18NUtil; +import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.domain.AccessControlListDAO; +import org.alfresco.repo.security.permissions.ACLType; + +/** + * Migrate permissions from the OLD format to defining, shared and layered + */ +public class AVMPermissionsPatch extends AbstractPatch +{ + + private static final String MSG_SUCCESS = "patch.updateAvmPermissions.result"; + + private AccessControlListDAO accessControlListDao; + + @Override + protected String applyInternal() throws Exception + { + Map summary = accessControlListDao.patchAcls(); + + // build the result message + String msg = I18NUtil.getMessage(MSG_SUCCESS, summary.get(ACLType.DEFINING), summary.get(ACLType.LAYERED)); + // done + return msg; + } + + public void setAccessControlListDao(AccessControlListDAO accessControlListDao) + { + this.accessControlListDao = accessControlListDao; + } + +} 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 91d536d15c..a946485cb5 100644 --- a/source/java/org/alfresco/repo/admin/patch/impl/AbstractPermissionChangePatch.java +++ b/source/java/org/alfresco/repo/admin/patch/impl/AbstractPermissionChangePatch.java @@ -96,7 +96,6 @@ public abstract class AbstractPermissionChangePatch extends AbstractPatch private static class HibernateHelper extends HibernateDaoSupport { private static final String QUERY_GET_PERMISSION = "permission.GetPermission"; - private static final String QUERY_GET_ENTRIES_TO_CHANGE = "permission.patch.GetAccessControlEntriesToChangePermissionOn"; public int createAndUpdatePermission( final QName oldTypeQName, @@ -109,7 +108,7 @@ public abstract class AbstractPermissionChangePatch extends AbstractPatch throw new IllegalArgumentException("Cannot move permission to itself: " + oldTypeQName + "-" + oldName); } - HibernateCallback getNewPermissionCallback = new GetPermissionCallback(newTypeQName, newName); + HibernateCallback getNewPermissionCallback = new GetPermissionCallback(oldTypeQName, oldName); DbPermission permission = (DbPermission) getHibernateTemplate().execute(getNewPermissionCallback); if (permission == null) { @@ -120,58 +119,13 @@ public abstract class AbstractPermissionChangePatch extends AbstractPatch // save getHibernateTemplate().save(permission); } - final DbPermission newPermission = permission; - // now update all entries that refer to the old permission - HibernateCallback updateEntriesCallback = new HibernateCallback() + else { - private static final int MAX_RESULTS = 1000; - @SuppressWarnings("unchecked") - public Object doInHibernate(Session session) - { - int count = 0; - while (true) - { - // flush any outstanding entities - session.flush(); - - Query query = session.getNamedQuery(HibernateHelper.QUERY_GET_ENTRIES_TO_CHANGE); - query.setParameter("oldTypeQName", oldTypeQName) - .setParameter("oldName", oldName) - .setMaxResults(MAX_RESULTS); - List entries = (List) query.list(); - // if there are no results, then we're done - if (entries.size() == 0) - { - break; - } - for (DbAccessControlEntry entry : entries) - { - entry.setPermission(newPermission); - count++; - session.evict(entry); - } - // flush and evict all the entries - session.flush(); - for (DbAccessControlEntry entry : entries) - { - session.evict(entry); - } - // next set of results - } - // done - return count; - } - }; - int updateCount = (Integer) getHibernateTemplate().execute(updateEntriesCallback); - // now delete the old permission - HibernateCallback getOldPermissionCallback = new GetPermissionCallback(oldTypeQName, oldName); - DbPermission oldPermission = (DbPermission) getHibernateTemplate().execute(getOldPermissionCallback); - if (oldPermission != null) - { - getHibernateTemplate().delete(oldPermission); + permission.setTypeQname(newTypeQName); + permission.setName(newName); } // done - return updateCount; + return 1; } } } diff --git a/source/java/org/alfresco/repo/avm/AVMNode.java b/source/java/org/alfresco/repo/avm/AVMNode.java index 4247664e2d..26f5bee91d 100644 --- a/source/java/org/alfresco/repo/avm/AVMNode.java +++ b/source/java/org/alfresco/repo/avm/AVMNode.java @@ -1,250 +1,250 @@ -/* - * 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.avm; - -import java.util.Map; -import java.util.Set; - -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.namespace.QName; - -/** - * The Interface for versionable objects. - * @author britt - */ -public interface AVMNode -{ - /** - * Set the ancestor of this node. - * @param ancestor The ancestor to set. - */ - public void setAncestor(AVMNode ancestor); - - /** - * Change the ancestor of a node. - * @param ancestor The ancestor node that should be set. - */ - public void changeAncestor(AVMNode ancestor); - - /** - * Get the ancestor of this node. - * @return The ancestor of this node. - */ - public AVMNode getAncestor(); - - /** - * Set the merged from node. - * @param mergedFrom The merged from node. - */ - public void setMergedFrom(AVMNode mergedFrom); - - /** - * Get the node this was merged from. - * @return The node this was merged from. - */ - public AVMNode getMergedFrom(); - - /** - * Get the version number. - * @return The version number. - */ - public int getVersionID(); - - /** - * Set the version number. - * @param version The version number to set. - */ - public void setVersionID(int version); - - /** - * Possibly copy ourselves. - * @param lPath The Lookup for this node. - * @return A copy of ourself or null if no copy was necessary. - */ - public AVMNode copy(Lookup lPath); - - /** - * Get the type of this node. - */ - public int getType(); - - /** - * Get the descriptor for this node. - * @param lPath The Lookup. - * @param name The name of this in the current context. - * @return The descriptor for this node. - */ - public AVMNodeDescriptor getDescriptor(Lookup lPath, String name); - - /** - * Get the descriptor for this node. - * @param lPath The Lookup. - * @return The descriptor for this node. - */ - public AVMNodeDescriptor getDescriptor(Lookup lPath); - - /** - * Get a node descriptor for this node. - * @param parentPath The parent path. - * @param name The name looked up as. - * @param parentIndirection The indirection of the parent. - * @param parentIndirectionVersion The indirection version of the parent. - * @return The descriptor for this node. - */ - public AVMNodeDescriptor getDescriptor(String parentPath, String name, String parentIndirection, int parentIndirectionVersion); - - /** - * Get the object id. - * @return The object id. - */ - public long getId(); - - /** - * Get the newnews. - * @return Whether the node is new. - */ - public boolean getIsNew(); - - /** - * Get a string representation for debugging. - * @param lPath The Lookup. - * @return A String representation. - */ - public String toString(Lookup lPath); - - /** - * Set whether this node to be a root of a AVMStore - * @param isRoot - */ - public void setIsRoot(boolean isRoot); - - /** - * Get whether this node is a root of a AVMStore. - * @return Whether this node is a root. - */ - public boolean getIsRoot(); - - /** - * Update the modification time of this node. - */ - public void updateModTime(); - - /** - * Set a property. - * @param name The name of the property. - * @param value The value to set. - */ - public void setProperty(QName name, PropertyValue value); - - /** - * Set a collection of properties on this node. - * @param properties The Map of QNames to PropertyValues. - */ - public void setProperties(Map properties); - - /** - * Get a property by name. - * @param name The name of the property to get. - * @return A PropertyValue - */ - public PropertyValue getProperty(QName name); - - /** - * Get all the properties associated with this node. - * @return A Map of QNames to PropertyValues. - */ - public Map getProperties(); - - /** - * Delete a property from this node. - * @param name The name of the property. - */ - public void deleteProperty(QName name); - - /** - * Delete all properties from this node. - */ - public void deleteProperties(); - - /** - * Set an ACL on this node. - * @param acl The ACL to set. - */ - public void setAcl(DbAccessControlList acl); - - /** - * Get the ACL on this node. - * @return The ACL on this node. - */ - public DbAccessControlList getAcl(); - - /** - * Set the store that we are new in. - * @param store The store we are new in. - */ - public void setStoreNew(AVMStore store); - - /** - * Get the possibly null store that we're new in. - * @return The store that we're new in. - */ - public AVMStore getStoreNew(); - - /** - * Copy metadata from another node. - * @param other The other node. - */ - public void copyMetaDataFrom(AVMNode other); - - /** - * Get the GUID associated with this version. - * @return The GUID. - */ - public String getGuid(); - - /** - * Set the GUID associated with this version. - * @param guid - */ - public void setGuid(String guid); - - /** - * Get the Aspects that this node has. - * @return A Set of Aspects names. - */ - public Set getAspects(); - - /** - * Add properties to those that already exist. - * @param properties The properties to add. - */ - public void addProperties(Map properties); - - /** - * Get the Basic Attributes on this node. - * @return - */ - public BasicAttributes getBasicAttributes(); -} +/* + * 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.avm; + +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.namespace.QName; + +/** + * The Interface for versionable objects. + * @author britt + */ +public interface AVMNode +{ + /** + * Set the ancestor of this node. + * @param ancestor The ancestor to set. + */ + public void setAncestor(AVMNode ancestor); + + /** + * Change the ancestor of a node. + * @param ancestor The ancestor node that should be set. + */ + public void changeAncestor(AVMNode ancestor); + + /** + * Get the ancestor of this node. + * @return The ancestor of this node. + */ + public AVMNode getAncestor(); + + /** + * Set the merged from node. + * @param mergedFrom The merged from node. + */ + public void setMergedFrom(AVMNode mergedFrom); + + /** + * Get the node this was merged from. + * @return The node this was merged from. + */ + public AVMNode getMergedFrom(); + + /** + * Get the version number. + * @return The version number. + */ + public int getVersionID(); + + /** + * Set the version number. + * @param version The version number to set. + */ + public void setVersionID(int version); + + /** + * Possibly copy ourselves. + * @param lPath The Lookup for this node. + * @return A copy of ourself or null if no copy was necessary. + */ + public AVMNode copy(Lookup lPath); + + /** + * Get the type of this node. + */ + public int getType(); + + /** + * Get the descriptor for this node. + * @param lPath The Lookup. + * @param name The name of this in the current context. + * @return The descriptor for this node. + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath, String name); + + /** + * Get the descriptor for this node. + * @param lPath The Lookup. + * @return The descriptor for this node. + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath); + + /** + * Get a node descriptor for this node. + * @param parentPath The parent path. + * @param name The name looked up as. + * @param parentIndirection The indirection of the parent. + * @param parentIndirectionVersion The indirection version of the parent. + * @return The descriptor for this node. + */ + public AVMNodeDescriptor getDescriptor(String parentPath, String name, String parentIndirection, int parentIndirectionVersion); + + /** + * Get the object id. + * @return The object id. + */ + public long getId(); + + /** + * Get the newnews. + * @return Whether the node is new. + */ + public boolean getIsNew(); + + /** + * Get a string representation for debugging. + * @param lPath The Lookup. + * @return A String representation. + */ + public String toString(Lookup lPath); + + /** + * Set whether this node to be a root of a AVMStore + * @param isRoot + */ + public void setIsRoot(boolean isRoot); + + /** + * Get whether this node is a root of a AVMStore. + * @return Whether this node is a root. + */ + public boolean getIsRoot(); + + /** + * Update the modification time of this node. + */ + public void updateModTime(); + + /** + * Set a property. + * @param name The name of the property. + * @param value The value to set. + */ + public void setProperty(QName name, PropertyValue value); + + /** + * Set a collection of properties on this node. + * @param properties The Map of QNames to PropertyValues. + */ + public void setProperties(Map properties); + + /** + * Get a property by name. + * @param name The name of the property to get. + * @return A PropertyValue + */ + public PropertyValue getProperty(QName name); + + /** + * Get all the properties associated with this node. + * @return A Map of QNames to PropertyValues. + */ + public Map getProperties(); + + /** + * Delete a property from this node. + * @param name The name of the property. + */ + public void deleteProperty(QName name); + + /** + * Delete all properties from this node. + */ + public void deleteProperties(); + + /** + * Set an ACL on this node. + * @param acl The ACL to set. + */ + public void setAcl(DbAccessControlList acl); + + /** + * Get the ACL on this node. + * @return The ACL on this node. + */ + public DbAccessControlList getAcl(); + + /** + * Set the store that we are new in. + * @param store The store we are new in. + */ + public void setStoreNew(AVMStore store); + + /** + * Get the possibly null store that we're new in. + * @return The store that we're new in. + */ + public AVMStore getStoreNew(); + + /** + * Copy metadata from another node. + * @param other The other node. + */ + public void copyMetaDataFrom(AVMNode other, Long parentAcl); + + /** + * Get the GUID associated with this version. + * @return The GUID. + */ + public String getGuid(); + + /** + * Set the GUID associated with this version. + * @param guid + */ + public void setGuid(String guid); + + /** + * Get the Aspects that this node has. + * @return A Set of Aspects names. + */ + public Set getAspects(); + + /** + * Add properties to those that already exist. + * @param properties The properties to add. + */ + public void addProperties(Map properties); + + /** + * Get the Basic Attributes on this node. + * @return + */ + public BasicAttributes getBasicAttributes(); +} diff --git a/source/java/org/alfresco/repo/avm/AVMNodeImpl.java b/source/java/org/alfresco/repo/avm/AVMNodeImpl.java index 39208c1d65..a7ee61b1bb 100644 --- a/source/java/org/alfresco/repo/avm/AVMNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMNodeImpl.java @@ -1,536 +1,537 @@ -/* - * 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.avm; - -import java.io.Serializable; -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.service.cmr.avm.AVMReadOnlyException; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.GUID; +/* + * 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.avm; + +import java.io.Serializable; +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, Serializable -{ - private static Log fgLogger = LogFactory.getLog(AVMNodeImpl.class); - - protected static final boolean DEBUG = true; - - /** - * 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() - { - fAspects = new HashSet(); - fProperties = new HashMap(); - } - - /** - * Constructor used when creating a new concrete subclass instance. - * @param id The object id. - * @param store The AVMStore that owns this. - */ - protected AVMNodeImpl(long id, - AVMStore store) - { - fAspects = new HashSet(); - fProperties = new HashMap(); - fID = id; - fVersionID = -1; - fIsRoot = false; - long time = System.currentTimeMillis(); - String user = - RawServices.Instance().getAuthenticationComponent().getCurrentUserName(); - if (user == null) - { - user = RawServices.Instance().getAuthenticationComponent().getSystemUserName(); - } - fBasicAttributes = new BasicAttributesImpl(user, - user, - user, - time, - time, - time); - fStoreNew = store; - fGUID = 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 fID == ((AVMNode)obj).getId(); - } - - /** - * Get a reasonable hash value. - * @return The hash code. - */ - @Override - public int hashCode() - { - return (int)fID; - } - - /** - * Set the object id. For Hibernate. - * @param id The id to set. - */ - protected 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. For Hibernate. - * @param attrs - */ - protected 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 fStoreNew != null; - } - - /** - * Set the version for concurrency control - * @param vers - */ - protected void setVers(long vers) - { - fVers = vers; - } - - /** - * Get the version for concurrency control. - * @return The version for optimistic locks. - */ - protected 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().getAuthenticationComponent().getCurrentUserName(); - if (user == null) - { - user = RawServices.Instance().getAuthenticationComponent().getSystemUserName(); - } - fBasicAttributes.setModDate(System.currentTimeMillis()); - fBasicAttributes.setLastModifier(user); - } - - /** - * Copy all properties from another node. - * @param other The other node. - */ - protected void copyProperties(AVMNode other) - { - fProperties = new HashMap(); - for (Map.Entry entry : other.getProperties().entrySet()) - { - fProperties.put(entry.getKey(), entry.getValue()); - } - } - - /** - * Copy all aspects from another node. - * @param other The other node. - */ - protected void copyAspects(AVMNode other) - { - fAspects = new HashSet(other.getAspects()); - } - - protected void copyACLs(AVMNode other) - { - DbAccessControlList acl = other.getAcl(); - if (acl != null) - { - setAcl(acl.getCopy()); - } - } - - /** - * Copy out metadata from another node. - * @param other The other node. - */ - public void copyMetaDataFrom(AVMNode other) - { - copyAspects(other); - copyACLs(other); - copyProperties(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 name, PropertyValue value) - { - if (DEBUG) - { - checkReadOnly(); - } - fProperties.put(name, value); - } - - public void addProperties(Map properties) - { - for (Map.Entry entry : properties.entrySet()) - { - fProperties.put(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; - } - - /** - * Get a property by name. - * @param name The name of the property. - * @return The PropertyValue or null if non-existent. - */ - public PropertyValue getProperty(QName name) - { - return fProperties.get(name); - } - - /** - * Get all the properties associated with this node. - * @return A Map of QNames to PropertyValues. - */ - public Map getProperties() - { - return fProperties; - } - - /** - * Delete a property from this node. - * @param name The name of the property. - */ - public void deleteProperty(QName name) - { - if (DEBUG) - { - checkReadOnly(); - } - fProperties.remove(name); - } - - /** - * Delete all properties from this node. - */ - public void deleteProperties() - { - fProperties.clear(); - } - - /** - * 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() - { - return fAspects; - } - - /** - * Set the aspects on this node. - * @param aspects - */ - public void setAspects(Set aspects) - { - fAspects = aspects; - } -} +import org.apache.commons.logging.LogFactory; + +/** + * Base class for all repository file system like objects. + * @author britt + */ +public abstract class AVMNodeImpl implements AVMNode, Serializable +{ + private static Log fgLogger = LogFactory.getLog(AVMNodeImpl.class); + + protected static final boolean DEBUG = true; + + /** + * 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() + { + fAspects = new HashSet(); + fProperties = new HashMap(); + } + + /** + * Constructor used when creating a new concrete subclass instance. + * @param id The object id. + * @param store The AVMStore that owns this. + */ + protected AVMNodeImpl(long id, + AVMStore store) + { + fAspects = new HashSet(); + fProperties = new HashMap(); + fID = id; + fVersionID = -1; + fIsRoot = false; + long time = System.currentTimeMillis(); + String user = + RawServices.Instance().getAuthenticationComponent().getCurrentUserName(); + if (user == null) + { + user = RawServices.Instance().getAuthenticationComponent().getSystemUserName(); + } + fBasicAttributes = new BasicAttributesImpl(user, + user, + user, + time, + time, + time); + fStoreNew = store; + fGUID = 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 fID == ((AVMNode)obj).getId(); + } + + /** + * Get a reasonable hash value. + * @return The hash code. + */ + @Override + public int hashCode() + { + return (int)fID; + } + + /** + * Set the object id. For Hibernate. + * @param id The id to set. + */ + protected 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. For Hibernate. + * @param attrs + */ + protected 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 fStoreNew != null; + } + + /** + * Set the version for concurrency control + * @param vers + */ + protected void setVers(long vers) + { + fVers = vers; + } + + /** + * Get the version for concurrency control. + * @return The version for optimistic locks. + */ + protected 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().getAuthenticationComponent().getCurrentUserName(); + if (user == null) + { + user = RawServices.Instance().getAuthenticationComponent().getSystemUserName(); + } + fBasicAttributes.setModDate(System.currentTimeMillis()); + fBasicAttributes.setLastModifier(user); + } + + /** + * Copy all properties from another node. + * @param other The other node. + */ + protected void copyProperties(AVMNode other) + { + fProperties = new HashMap(); + for (Map.Entry entry : other.getProperties().entrySet()) + { + fProperties.put(entry.getKey(), entry.getValue()); + } + } + + /** + * Copy all aspects from another node. + * @param other The other node. + */ + protected void copyAspects(AVMNode other) + { + fAspects = new HashSet(other.getAspects()); + } + + 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); + } + + /** + * 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 name, PropertyValue value) + { + if (DEBUG) + { + checkReadOnly(); + } + fProperties.put(name, value); + } + + public void addProperties(Map properties) + { + for (Map.Entry entry : properties.entrySet()) + { + fProperties.put(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; + } + + /** + * Get a property by name. + * @param name The name of the property. + * @return The PropertyValue or null if non-existent. + */ + public PropertyValue getProperty(QName name) + { + return fProperties.get(name); + } + + /** + * Get all the properties associated with this node. + * @return A Map of QNames to PropertyValues. + */ + public Map getProperties() + { + return fProperties; + } + + /** + * Delete a property from this node. + * @param name The name of the property. + */ + public void deleteProperty(QName name) + { + if (DEBUG) + { + checkReadOnly(); + } + fProperties.remove(name); + } + + /** + * Delete all properties from this node. + */ + public void deleteProperties() + { + fProperties.clear(); + } + + /** + * 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() + { + return fAspects; + } + + /** + * Set the aspects on this node. + * @param aspects + */ + public void setAspects(Set aspects) + { + fAspects = aspects; + } +} diff --git a/source/java/org/alfresco/repo/avm/AVMRepository.java b/source/java/org/alfresco/repo/avm/AVMRepository.java index f8b7ea4dc7..1caa4ad5f3 100644 --- a/source/java/org/alfresco/repo/avm/AVMRepository.java +++ b/source/java/org/alfresco/repo/avm/AVMRepository.java @@ -1,2900 +1,3190 @@ -/* - * 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.avm; - -import java.io.File; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Serializable; -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.repo.content.ContentStore; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.PropertyValue; -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.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.security.AccessStatus; -import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.Pair; +/* + * 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.avm; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +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.content.ContentStore; +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.domain.PropertyValue; +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.DataTypeDefinition; +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.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.Pair; import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * This or AVMStore are - * the implementors of the operations specified by AVMService. - * @author britt - */ -public class AVMRepository -{ - @SuppressWarnings("unused") - private static Log fgLogger = LogFactory.getLog(AVMRepository.class); - - /** - * The single instance of AVMRepository. - */ - private static AVMRepository fgInstance; - - /** - * The current lookup count. - */ - private ThreadLocal fLookupCount; - - /** - * The node id issuer. - */ - private Issuer fNodeIssuer; - - /** - * The layer id issuer. - */ - private Issuer fLayerIssuer; - - /** - * Reference to the ContentStoreImpl - */ - private ContentStore fContentStore; - - /** - * The Lookup Cache instance. - */ - private LookupCache fLookupCache; - - 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 node issuer. For Spring. - * @param nodeIssuer The issuer. - */ - public void setNodeIssuer(Issuer nodeIssuer) - { - fNodeIssuer = nodeIssuer; - } - - /** - * Set the layer issuer. For Spring. - * @param layerIssuer The issuer. - */ - public void setLayerIssuer(Issuer layerIssuer) - { - fLayerIssuer = layerIssuer; - } - - /** - * 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 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(node, PermissionService.CREATE_CHILDREN)) - { - 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; - if (dir instanceof LayeredDirectoryNode) - { - child = new LayeredDirectoryNodeImpl((String)null, store, null); - ((LayeredDirectoryNode)child).setPrimaryIndirection(false); - ((LayeredDirectoryNode)child).setLayerID(parent.getLayerID()); - } - else - { - child = new PlainDirectoryNodeImpl(store); - } - dir.putChild(name, child); - DbAccessControlList acl = dir.getAcl(); - child.setAcl(acl != null ? acl.getCopy() : null); - 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) - { - 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. - @SuppressWarnings("unused") - AVMStore rep = new AVMStoreImpl(this, name); - // Special handling for AVMStore creation. - rep.getRoot().setStoreNew(null); - 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(dirNode, PermissionService.ADD_CHILDREN)) - { - 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). - if (srcNode.getType() == AVMNodeType.PLAIN_DIRECTORY) - { - dstNode = new PlainDirectoryNodeImpl((PlainDirectoryNode)srcNode, dstRepo); - } - else if (srcNode.getType() == AVMNodeType.LAYERED_DIRECTORY) - { - dstNode = - new LayeredDirectoryNodeImpl((LayeredDirectoryNode)srcNode, dstRepo, sPath, false); - ((LayeredDirectoryNode)dstNode).setLayerID(issueLayerID()); - } - else if (srcNode.getType() == AVMNodeType.LAYERED_FILE) - { - dstNode = new LayeredFileNodeImpl((LayeredFileNode)srcNode, dstRepo); - } - else // This is a plain file. - { - dstNode = new PlainFileNodeImpl((PlainFileNode)srcNode, dstRepo); - } - // dstNode.setVersionID(dstRepo.getNextVersionID()); - dstNode.setAncestor(srcNode); - dirNode.putChild(name, dstNode); - dirNode.updateModTime(); - DbAccessControlList acl = srcNode.getAcl(); - dstNode.setAcl(acl != null ? acl.getCopy() : null); - String beginingPath = AVMNodeConverter.NormalizePath(srcPath); - String finalPath = AVMNodeConverter.ExtendAVMPath(dstPath, name); - finalPath = AVMNodeConverter.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. - * @return A ContentWriter. - */ - public ContentWriter createContentWriter(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]); - } - fLookupCache.onWrite(pathParts[0]); - ContentWriter writer = store.createContentWriter(pathParts[1]); - 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(); - if (!can(srcDir, PermissionService.DELETE_CHILDREN) || !can(srcDir, PermissionService.ADD_CHILDREN)) - { - throw new AccessDeniedException("Not allowed to read or write: " + srcPath); - } - Pair temp = srcDir.lookupChild(sPath, srcName, false); - srcNode = (temp == null) ? null : temp.getFirst(); - if (srcNode == null) - { - throw new AVMNotFoundException("Not found: " + srcName); - } - 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(dstDir, PermissionService.ADD_CHILDREN)) - { - throw new AccessDeniedException("Not allowed to write: " + dstPath); - } - Pair temp = dstDir.lookupChild(dPath, dstName, true); - AVMNode child = (temp == null) ? null : temp.getFirst(); - if (child != null && child.getType() != AVMNodeType.DELETED_NODE) - { - throw new AVMExistsException("Node exists: " + dstName); - } - 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); - ((LayeredDirectoryNode)dstNode).setLayerID(sPath.getTopLayer().getLayerID()); - } - else - { - dstNode = new LayeredDirectoryNodeImpl((DirectoryNode)srcNode, dstRepo, sPath, srcName); - ((LayeredDirectoryNode)dstNode).setLayerID(issueLayerID()); - } - } - else - { - dstNode = new PlainDirectoryNodeImpl((PlainDirectoryNode)srcNode, dstRepo); - } - } - 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); - ((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); - } - else - { - dstNode = - new LayeredDirectoryNodeImpl((DirectoryNode)srcNode, dstRepo, sPath, srcName); - } - // 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 - { - ((LayeredDirectoryNode)dstNode).setLayerID(issueLayerID()); - } - } - } - else if (srcNode.getType() == AVMNodeType.LAYERED_FILE) - { - dstNode = new LayeredFileNodeImpl((LayeredFileNode)srcNode, dstRepo); - } - else // This is a plain file node. - { - dstNode = new PlainFileNodeImpl((PlainFileNode)srcNode, dstRepo); - } - 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); - } - 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. - */ - @SuppressWarnings("unchecked") - 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(root, PermissionService.DELETE_CHILDREN)) - { - throw new AccessDeniedException("Not allowed to purge: " + name); - } - root.setIsRoot(false); - List vRoots = fVersionRootDAO.getAllInAVMStore(store); - for (VersionRoot vr : vRoots) - { - AVMNode node = vr.getRoot(); - node.setIsRoot(false); - fVersionLayeredNodeEntryDAO.delete(vr); - fVersionRootDAO.delete(vr); - } - List newGuys = fAVMNodeDAO.getNewInStore(store); - for (AVMNode newGuy : newGuys) - { - newGuy.setStoreNew(null); - } - 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(node, PermissionService.READ_CONTENT)) - { - 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(node, PermissionService.READ_CHILDREN)) - { - 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(node, PermissionService.READ_CHILDREN)) - { - 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 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. - */ - @SuppressWarnings("unchecked") - public List getAVMStores() - { - List l = fAVMStoreDAO.getAll(); - List result = new ArrayList(); - for (AVMStore store : l) - { - 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); - } - - /** - * Issue a node id. - * @return The new id. - */ - public long issueID() - { - return fNodeIssuer.issue(); - } - - /** - * Issue a new layer id. - * @return The new id. - */ - public long issueLayerID() - { - return fLayerIssuer.issue(); - } - - /** - * 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(dirNode, PermissionService.READ_CHILDREN)) - { - 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); - } - 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(node, PermissionService.READ_CHILDREN)) - { - 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(node, PermissionService.READ_CHILDREN)) - { - 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(node, PermissionService.READ_CHILDREN)) - { - return null; - } - if (node.getIsRoot()) - { - AVMStore store = fAVMStoreDAO.getByRoot(node); - if (store != null) - { - return new Pair(-1, makePath(components, store.getName())); - } - VersionRoot vr = fVersionRootDAO.getByRoot(node); - if (vr != null) - { - 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(); - 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(node, PermissionService.READ_CHILDREN)) - { - 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(node, PermissionService.READ_CHILDREN)) - { - 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(lookup.getCurrentNode(), PermissionService.READ_PROPERTIES)) - { - 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) - { - String [] pathParts = path.split(":"); - if (pathParts.length != 2) - { - throw new AVMException("Invalid path: " + path); - } - return pathParts; - } - - /** - * 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(node, PermissionService.READ_PROPERTIES)) - { - 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++) - { - node = node.getAncestor(); - if (node == null) - { - break; - } - if (!can(node, PermissionService.READ_PROPERTIES)) - { - break; - } - history.add(node.getDescriptor("UNKNOWN", "UNKNOWN", "UNKNOWN", -1)); - } - 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."); - } - List matches = - fAVMStorePropertyDAO.queryByKeyPattern(st, - keyPattern); - Map results = new HashMap(); - for (AVMStoreProperty prop : matches) - { - results.put(prop.getName(), prop.getValue()); - } - return results; - } - - /** - * 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) - { - List matches = - fAVMStorePropertyDAO.queryByKeyPattern(keyPattern); - Map> results = - new HashMap>(); - for (AVMStoreProperty prop : matches) - { - String storeName = prop.getStore().getName(); - Map pairs = null; - if ((pairs = results.get(storeName)) == null) - { - pairs = new HashMap(); - results.put(storeName, pairs); - } - pairs.put(prop.getName(), prop.getValue()); - } - return results; - } - - /** - * 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(lNode, PermissionService.READ_PROPERTIES)) - { - throw new AccessDeniedException("Not allowed to read properties: " + left); - } - if (!can(rNode, PermissionService.READ_PROPERTIES)) - { - 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); - } - } - - - /** - * 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(dir, PermissionService.ADD_CHILDREN)) - { - 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(node, PermissionService.DELETE_CHILDREN)) - { - 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); - 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(node, PermissionService.READ)) - { - 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(node, PermissionService.READ_PROPERTIES)) - { - 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(node, PermissionService.READ_CONTENT)) - { - throw new AccessDeniedException("Not allowed to read: " + desc); - } - if (node.getType() == AVMNodeType.PLAIN_FILE) - { - PlainFileNode file = (PlainFileNode)node; - return file.getContentData(); - } - throw new AVMWrongTypeException("Not a Plain 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(node, PermissionService.READ_PROPERTIES)) - { - throw new AccessDeniedException("Not allowed to read properties: " + desc); - } - Set aspects = node.getAspects(); - return aspects; - } - - /** - * Evaluate permission on a node. - * I've got a bad feeling about this... - * @param node - * @param permission - * @return - */ - public boolean can(AVMNode node, String permission) - { - DbAccessControlList acl = node.getAcl(); - if (acl == null) - { - return true; - } - Map context = new HashMap(4); - context.put(PermissionService.OWNER_AUTHORITY, node.getBasicAttributes().getOwner()); - context.put(PermissionService.ASPECTS, node.getAspects()); - Map props = node.getProperties(); - Map properties = new HashMap(5); - for (Map.Entry entry : props.entrySet()) - { - PropertyDefinition def = fDictionaryService.getProperty(entry.getKey()); - if (def == null) - { - continue; - } - properties.put(entry.getKey(), entry.getValue().getValue(def.getDataType().getName())); - } - context.put(PermissionService.PROPERTIES, properties); - // TODO put node type in there to. - return fPermissionService.hasPermission(acl.getId(), context, permission) - == AccessStatus.ALLOWED; - } -} +import org.apache.commons.logging.LogFactory; + +/** + * This or AVMStore are the implementors of the operations specified by AVMService. + * + * @author britt + */ +public class AVMRepository +{ + @SuppressWarnings("unused") + private static Log fgLogger = LogFactory.getLog(AVMRepository.class); + + /** + * The single instance of AVMRepository. + */ + private static AVMRepository fgInstance; + + /** + * The current lookup count. + */ + private ThreadLocal fLookupCount; + + /** + * The node id issuer. + */ + private Issuer fNodeIssuer; + + /** + * The layer id issuer. + */ + private Issuer fLayerIssuer; + + /** + * Reference to the ContentStoreImpl + */ + private ContentStore fContentStore; + + /** + * The Lookup Cache instance. + */ + private LookupCache fLookupCache; + + 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 node issuer. For Spring. + * + * @param nodeIssuer + * The issuer. + */ + public void setNodeIssuer(Issuer nodeIssuer) + { + fNodeIssuer = nodeIssuer; + } + + /** + * Set the layer issuer. For Spring. + * + * @param layerIssuer + * The issuer. + */ + public void setLayerIssuer(Issuer layerIssuer) + { + fLayerIssuer = layerIssuer; + } + + /** + * 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 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(node, PermissionService.CREATE_CHILDREN)) + { + 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) + { + child = new LayeredDirectoryNodeImpl((String)null, store, null, parentAcl, ACLCopyMode.INHERIT); + ((LayeredDirectoryNode)child).setPrimaryIndirection(false); + ((LayeredDirectoryNode)child).setLayerID(parent.getLayerID()); + } + else + { + child = new PlainDirectoryNodeImpl(store); + } + dir.putChild(name, child); + DbAccessControlList acl = dir.getAcl(); + child.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null); + 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) + { + 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. + @SuppressWarnings("unused") + AVMStore rep = new AVMStoreImpl(this, name); + // Special handling for AVMStore creation. + rep.getRoot().setStoreNew(null); + 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(dirNode, PermissionService.ADD_CHILDREN)) + { + 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 parentAcl = dirNode.getAcl() == null ? null : dirNode.getAcl().getId(); + + if (srcNode.getType() == AVMNodeType.PLAIN_DIRECTORY) + { + dstNode = new PlainDirectoryNodeImpl((PlainDirectoryNode)srcNode, dstRepo, parentAcl, ACLCopyMode.COPY); + } + else if (srcNode.getType() == AVMNodeType.LAYERED_DIRECTORY) + { + dstNode = + new LayeredDirectoryNodeImpl((LayeredDirectoryNode)srcNode, dstRepo, sPath, false, parentAcl, ACLCopyMode.COPY); + ((LayeredDirectoryNode)dstNode).setLayerID(issueLayerID()); + } + else if (srcNode.getType() == AVMNodeType.LAYERED_FILE) + { + dstNode = new LayeredFileNodeImpl((LayeredFileNode)srcNode, dstRepo, parentAcl, ACLCopyMode.COPY); + } + else // This is a plain file. + { + dstNode = new PlainFileNodeImpl((PlainFileNode)srcNode, dstRepo, parentAcl, ACLCopyMode.COPY); + } + // dstNode.setVersionID(dstRepo.getNextVersionID()); + dstNode.setAncestor(srcNode); + dirNode.putChild(name, dstNode); + dirNode.updateModTime(); + DbAccessControlList acl = srcNode.getAcl(); + dstNode.setAcl(acl != null ? acl.getCopy(parentAcl, ACLCopyMode.COPY) : null); + String beginingPath = AVMNodeConverter.NormalizePath(srcPath); + String finalPath = AVMNodeConverter.ExtendAVMPath(dstPath, name); + finalPath = AVMNodeConverter.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. + * @return A ContentWriter. + */ + public ContentWriter createContentWriter(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]); + } + fLookupCache.onWrite(pathParts[0]); + ContentWriter writer = store.createContentWriter(pathParts[1]); + 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(); + if (!can(srcDir, PermissionService.DELETE_CHILDREN) || !can(srcDir, PermissionService.ADD_CHILDREN)) + { + throw new AccessDeniedException("Not allowed to read or write: " + srcPath); + } + Pair temp = srcDir.lookupChild(sPath, srcName, false); + srcNode = (temp == null) ? null : temp.getFirst(); + if (srcNode == null) + { + throw new AVMNotFoundException("Not found: " + srcName); + } + 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(dstDir, PermissionService.ADD_CHILDREN)) + { + throw new AccessDeniedException("Not allowed to write: " + dstPath); + } + Pair temp = dstDir.lookupChild(dPath, dstName, true); + AVMNode child = (temp == null) ? null : temp.getFirst(); + if (child != null && child.getType() != AVMNodeType.DELETED_NODE) + { + throw new AVMExistsException("Node exists: " + dstName); + } + + 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); + ((LayeredDirectoryNode)dstNode).setLayerID(issueLayerID()); + } + } + 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 + { + ((LayeredDirectoryNode)dstNode).setLayerID(issueLayerID()); + } + } + } + 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); + } + 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. + */ + @SuppressWarnings("unchecked") + 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(root, PermissionService.DELETE_CHILDREN)) + { + throw new AccessDeniedException("Not allowed to purge: " + name); + } + root.setIsRoot(false); + List vRoots = fVersionRootDAO.getAllInAVMStore(store); + for (VersionRoot vr : vRoots) + { + AVMNode node = vr.getRoot(); + node.setIsRoot(false); + fVersionLayeredNodeEntryDAO.delete(vr); + fVersionRootDAO.delete(vr); + } + List newGuys = fAVMNodeDAO.getNewInStore(store); + for (AVMNode newGuy : newGuys) + { + newGuy.setStoreNew(null); + } + 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(node, PermissionService.READ_CONTENT)) + { + 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(node, PermissionService.READ_CHILDREN)) + { + 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(node, PermissionService.READ_CHILDREN)) + { + 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 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. + */ + @SuppressWarnings("unchecked") + public List getAVMStores() + { + List l = fAVMStoreDAO.getAll(); + List result = new ArrayList(); + for (AVMStore store : l) + { + 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); + } + + /** + * Issue a node id. + * + * @return The new id. + */ + public long issueID() + { + return fNodeIssuer.issue(); + } + + /** + * Issue a new layer id. + * + * @return The new id. + */ + public long issueLayerID() + { + return fLayerIssuer.issue(); + } + + /** + * 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(dirNode, PermissionService.READ_CHILDREN)) + { + 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); + } + 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(node, PermissionService.READ_CHILDREN)) + { + 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(node, PermissionService.READ_CHILDREN)) + { + 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(node, PermissionService.READ_CHILDREN)) + { + return null; + } + if (node.getIsRoot()) + { + AVMStore store = fAVMStoreDAO.getByRoot(node); + if (store != null) + { + return new Pair(-1, makePath(components, store.getName())); + } + VersionRoot vr = fVersionRootDAO.getByRoot(node); + if (vr != null) + { + 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(); + 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(node, PermissionService.READ_CHILDREN)) + { + 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(node, PermissionService.READ_CHILDREN)) + { + 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(lookup.getCurrentNode(), PermissionService.READ_PROPERTIES)) + { + 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) + { + String [] pathParts = path.split(":"); + if (pathParts.length != 2) + { + throw new AVMException("Invalid path: " + path); + } + return pathParts; + } + + /** + * 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(node, PermissionService.READ_PROPERTIES)) + { + 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++) + { + node = node.getAncestor(); + if (node == null) + { + break; + } + if (!can(node, PermissionService.READ_PROPERTIES)) + { + break; + } + history.add(node.getDescriptor("UNKNOWN", "UNKNOWN", "UNKNOWN", -1)); + } + 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."); + } + List matches = + fAVMStorePropertyDAO.queryByKeyPattern(st, + keyPattern); + Map results = new HashMap(); + for (AVMStoreProperty prop : matches) + { + results.put(prop.getName(), prop.getValue()); + } + return results; + } + + /** + * 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) + { + List matches = + fAVMStorePropertyDAO.queryByKeyPattern(keyPattern); + Map> results = + new HashMap>(); + for (AVMStoreProperty prop : matches) + { + String storeName = prop.getStore().getName(); + Map pairs = null; + if ((pairs = results.get(storeName)) == null) + { + pairs = new HashMap(); + results.put(storeName, pairs); + } + pairs.put(prop.getName(), prop.getValue()); + } + return results; + } + + /** + * 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(lNode, PermissionService.READ_PROPERTIES)) + { + throw new AccessDeniedException("Not allowed to read properties: " + left); + } + if (!can(rNode, PermissionService.READ_PROPERTIES)) + { + 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); + } + } + + + /** + * 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(dir, PermissionService.ADD_CHILDREN)) + { + 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(node, PermissionService.DELETE_CHILDREN)) + { + 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); + 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(node, PermissionService.READ)) + { + 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(node, PermissionService.READ_PROPERTIES)) + { + 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(node, PermissionService.READ_CONTENT)) + { + throw new AccessDeniedException("Not allowed to read: " + desc); + } + if (node.getType() == AVMNodeType.PLAIN_FILE) + { + PlainFileNode file = (PlainFileNode)node; + return file.getContentData(); + } + throw new AVMWrongTypeException("Not a Plain 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(node, PermissionService.READ_PROPERTIES)) + { + throw new AccessDeniedException("Not allowed to read properties: " + desc); + } + Set aspects = node.getAspects(); + return aspects; + } + + /** + * Evaluate permission on a node. I've got a bad feeling about this... + * + * @param node + * @param permission + * @return + */ + public boolean can(AVMNode node, String permission) + { + 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); + context.getAspects().addAll(node.getAspects()); + Map props = node.getProperties(); + Map properties = new HashMap(5); + for (Map.Entry entry : props.entrySet()) + { + PropertyDefinition def = fDictionaryService.getProperty(entry.getKey()); + if (def == null) + { + properties.put(entry.getKey(), entry.getValue().getValue(DataTypeDefinition.ANY)); + } + else + { + properties.put(entry.getKey(), entry.getValue().getValue(def.getDataType().getName())); + } + } + context.getProperties().putAll(properties); + Long aclId = null; + if(acl != null) + { + aclId = acl.getId(); + } + return fPermissionService.hasPermission(aclId, context, permission) + == AccessStatus.ALLOWED; + } +} diff --git a/source/java/org/alfresco/repo/avm/AVMServiceImpl.java b/source/java/org/alfresco/repo/avm/AVMServiceImpl.java index ace9b1497f..04439c56b1 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceImpl.java @@ -1,1536 +1,1574 @@ -/* - * 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.avm; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; - -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.PropertyValue; -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.AVMService; -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.repository.ContentData; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.cmr.repository.ContentWriter; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.Pair; -import org.alfresco.util.TempFileProvider; +/* + * 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.avm; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; + +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.security.permissions.ACLCopyMode; +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.AVMService; +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.repository.ContentData; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; +import org.alfresco.util.TempFileProvider; import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Implements the AVMService. - * @author britt - */ -public class AVMServiceImpl implements AVMService -{ - public static final String SYSTEM = "system"; - - @SuppressWarnings("unused") - private static Log fgLogger = LogFactory.getLog(AVMServiceImpl.class); - - /** - * The AVMRepository for each service thread. - */ - private AVMRepository fAVMRepository; - - /** - * Basic constructor for the service. - */ - public AVMServiceImpl() - { - } - - /** - * Set the repository reference. For Spring. - * @param avmRepository The repository reference. - */ - public void setAvmRepository(AVMRepository avmRepository) - { - fAVMRepository = avmRepository; - } - - /** - * Get an InputStream from a file. - * @param version The version to look under. - * @param path The absolute path. - * @return An InputStream - * @throws AVMNotFoundException When the path is invalid. - */ - public InputStream getFileInputStream(int version, String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path."); - } - return fAVMRepository.getInputStream(version, path); - } - - /** - * Get an InputStream from a descriptor. - * @param desc The descriptor. - * @return An InputStream. - * @throws AVMNotFoundException - */ - public InputStream getFileInputStream(AVMNodeDescriptor desc) - { - if (desc == null) - { - throw new AVMBadArgumentException("Illegal Null Argument."); - } - return fAVMRepository.getInputStream(desc); - } - - /** - * Get an output stream to a file. Triggers versioning. - */ - public OutputStream getFileOutputStream(String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path."); - } - return fAVMRepository.getOutputStream(path); - } - - /** - * 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) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path."); - } - return fAVMRepository.getContentReader(version, path); - } - - /** - * Get a ContentWriter to a file node. - * @param path The path to the file. - * @return A ContentWriter. - */ - public ContentWriter getContentWriter(String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path."); - } - return fAVMRepository.createContentWriter(path); - } - - /** - * Get a directory listing. - * @param version The version id to lookup. - * @param path The path to lookup. - */ - public SortedMap getDirectoryListing(int version, String path) - { - return getDirectoryListing(version, path, false); - } - - /** - * Get a listing of a Folder by name, with the option of seeing - * Deleted Nodes. - * @param version The version id to look in. - * @param path The simple absolute path to the file node. - * @param includeDeleted Whether to see Deleted Nodes. - * @return A Map of names to descriptors. - * @throws AVMNotFoundException If path is not found. - * @throws AVMWrongTypeException If path contains a non-terminal - * component that is not a directory, or if path is not pointing - * at a directory. - */ - public SortedMap getDirectoryListing(int version, String path, - boolean includeDeleted) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path."); - } - return fAVMRepository.getListing(version, path, includeDeleted); - } - - /** - * Get a directory listing as an Array of AVMNodeDescriptors. - * @param version The version to look under. - * @param path The path to the directory to be listed. - * @param includeDeleted Whether to include ghosts. - * @return An array of AVMNodeDescriptors. - */ - public AVMNodeDescriptor [] getDirectoryListingArray(int version, String path, - boolean includeDeleted) - { - Map listing = - getDirectoryListing(version, path, includeDeleted); - AVMNodeDescriptor [] result = new AVMNodeDescriptor[listing.size()]; - int off = 0; - for (AVMNodeDescriptor desc : listing.values()) - { - result[off++] = desc; - } - return result; - } - - /** - * Get a directory listing as an Array of node descriptors. - * @param dir The descriptor pointing at the directory to list. - * @param includeDeleted Whether to show ghosts. - * @return An array of AVMNodeDescriptors. - */ - public AVMNodeDescriptor [] getDirectoryListingArray(AVMNodeDescriptor dir, - boolean includeDeleted) - { - Map listing = - getDirectoryListing(dir, includeDeleted); - AVMNodeDescriptor [] result = new AVMNodeDescriptor[listing.size()]; - int off = 0; - for (AVMNodeDescriptor desc : listing.values()) - { - result[off++] = desc; - } - return result; - } - - /** - * Get a listing of all the directly contained children of a directory. - * @param dir The directory descriptor. - * @param includeDeleted Whether to include deleted children. - * @return A Map of Strings to descriptors. - */ - public SortedMap - getDirectoryListingDirect(AVMNodeDescriptor dir, boolean includeDeleted) - { - if (dir == null) - { - throw new AVMBadArgumentException("Illegal null descriptor."); - } - return fAVMRepository.getListingDirect(dir, includeDeleted); - } - - /** - * Get the listing of nodes contained directly in a directory. This is the - * same as getDirectoryListing for PlainDirectories, but returns only those that - * are directly contained in a layered directory. - * @param version The version to look up. - * @param path The full path to get listing for. - * @return A Map of names to descriptors. - * @throws AVMNotFoundException If path does not exist. - * @throws AVMWrongTypeException If path contains any non-directory - * elements. - */ - public SortedMap - getDirectoryListingDirect(int version, String path) - { - return getDirectoryListingDirect(version, path, false); - } - - /** - * Get the listing of nodes contained directly in a directory. This is the - * same as getDirectoryListing for PlainDirectories, but returns only those that - * are directly contained in a layered directory. This has the option of - * seeing Deleted Nodes. - * @param version The version to look up. - * @param path The full path to get listing for. - * @param includeDeleted Whether to see Deleted Nodes. - * @return A Map of names to descriptors. - * @throws AVMNotFoundException If path does not exist. - * @throws AVMWrongTypeException If path contains any non-directory - * elements. - */ - public SortedMap - getDirectoryListingDirect(int version, String path, boolean includeDeleted) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path."); - } - return fAVMRepository.getListingDirect(version, path, includeDeleted); - } - - /** - * Get a directory listing from a node descriptor. - * @param dir The directory node descriptor. - * @return A Map of names to node descriptors. - */ - public SortedMap getDirectoryListing(AVMNodeDescriptor dir) - { - return getDirectoryListing(dir, false); - } - - /** - * Get a directory listing from a node descriptor, with the option of - * seeing deleted nodes. - * @param dir The directory node descriptor. - * @param includeDeleted Whether to see Deleted Nodes. - * @return A Map of names to node descriptors. - * @throws AVMNotFoundException If the descriptor is stale. - * @throws AVMWrongTypeException If the descriptor does not point at a directory. - */ - public SortedMap getDirectoryListing(AVMNodeDescriptor dir, - boolean includeDeleted) - { - if (dir == null) - { - throw new AVMBadArgumentException("Null descriptor."); - } - return fAVMRepository.getListing(dir, includeDeleted); - } - - /** - * Get the names of nodes that have been deleted in a directory. - * @param version The version to look under. - * @param path The path of the directory. - * @return A List of names. - * @throws AVMNotFoundException If path does not exist. - * @throws AVMWrongTypeException If path contains any elements - * that are not directories. - */ - public List getDeleted(int version, String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path."); - } - return fAVMRepository.getDeleted(version, path); - } - - /** - * Create a new file. The file must not exist. - * @param path The path to the containing directory. - * @param name The name of the file. - * @return An output stream to the file. - */ - public OutputStream createFile(String path, String name) - { - if (path == null || name == null || !FileNameValidator.IsValid(name)) - { - throw new AVMBadArgumentException("Illegal argument."); - } - return fAVMRepository.createFile(path, name); - } - - /** - * Create a file with content specified by the InputStream. - * Guaranteed to be created atomically. - * @param path The path to the containing directory. - * @param name The name to give the file. - * @param in An InputStream containing data for file. - */ - public void createFile(String path, String name, InputStream in) - { - createFile(path, name, in, null, null); - } - - /* (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) - { - if (path == null || name == null || in == null || !FileNameValidator.IsValid(name)) - { - throw new AVMBadArgumentException("Illegal argument."); - } - // Save the contents to temp space. - File temp; - try - { - temp = TempFileProvider.createTempFile("alf", "tmp"); - OutputStream out = new FileOutputStream(temp); - byte [] buff = new byte[8192]; - int read; - while ((read = in.read(buff)) != -1) - { - out.write(buff, 0, read); - } - out.close(); - in.close(); - } - catch (IOException ie) - { - throw new AVMException("I/O Error."); - } - try - { - fAVMRepository.createFile(path, name, temp, aspects, properties); - } - finally - { - temp.delete(); - } - } - - /** - * Create a directory. The directory must not exist. - * @param path The path to the containing directory. - * @param name The name of the new directory. - */ - public void createDirectory(String path, String name) - { - createDirectory(path, name, null, null); - } - - /* (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) - { - if (path == null || name == null || !FileNameValidator.IsValid(name)) - { - throw new AVMBadArgumentException("Illegal argument."); - } - fAVMRepository.createDirectory(path, name, aspects, properties); - } - - /** - * Create a new layered file. It must not exist. - * @param srcPath The src path. Ie the target for the layering. - * @param parent The path to the parent directory. - * @param name The name to give the new file. - */ - public void createLayeredFile(String srcPath, String parent, String name) - { - if (srcPath == null || parent == null || name == null || - !FileNameValidator.IsValid(name)) - { - throw new AVMBadArgumentException("Illegal argument."); - } - fAVMRepository.createLayeredFile(srcPath, parent, name); - } - - /** - * Create a new layered directory. It must not exist. - * @param srcPath The src path. Ie the target for layering. - * @param parent The path to the parent directory. - * @param name The name for the new directory. - */ - public void createLayeredDirectory(String srcPath, String parent, String name) - { - if (srcPath == null || parent == null || name == null || - !FileNameValidator.IsValid(name)) - { - throw new AVMBadArgumentException("Illegal argument."); - } - fAVMRepository.createLayeredDirectory(srcPath, parent, name); - } - - /** - * Create an AVMStore with the given name. It must not exist. - * @param name The name to give the AVMStore. - */ - public void createStore(String name) - { - if (name == null || !FileNameValidator.IsValid(name)) - { - throw new AVMBadArgumentException("Bad Name."); - } - fAVMRepository.createAVMStore(name); - } - - /** - * Create a branch. - * @param version The version to branch from. - * @param srcPath The path to the thing to branch from. - * @param dstPath The path to the destination containing directory. - * @param name The name of the new branch. - */ - public void createBranch(int version, String srcPath, String dstPath, - String name) - { - if (srcPath == null || dstPath == null || name == null || - !FileNameValidator.IsValid(name)) - { - throw new AVMBadArgumentException("Illegal argument."); - } - fAVMRepository.createBranch(version, srcPath, dstPath, name); - } - - /** - * Remove a node. Beware, the node can be a directory and - * this acts recursively. - * @param parent The path to the parent. - * @param name The name of the node to remove. - */ - public void removeNode(String parent, String name) - { - if (parent == null || name == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - fAVMRepository.remove(parent, name); - } - - /** - * Remove a node by full path. - * @param path The full path to the node. - */ - public void removeNode(String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - String [] basePath = AVMNodeConverter.SplitBase(path); - if (basePath[0] == null) - { - throw new AVMBadArgumentException("Cannot remove root node: " + path); - } - fAVMRepository.remove(basePath[0], basePath[1]); - } - - /** - * Rename a node. - * @param srcParent The path to the source parent. - * @param srcName The name of the source node. - * @param dstParent The path to the destination parent. - * @param dstName The name to give the renamed node. - */ - public void rename(String srcParent, String srcName, String dstParent, - String dstName) - { - if (srcParent == null || srcName == null || dstParent == null || dstName == null || - !FileNameValidator.IsValid(dstName)) - { - throw new AVMBadArgumentException("Illegal argument."); - } - fAVMRepository.rename(srcParent, srcName, dstParent, dstName); - } - - /** - * 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) - { - if (dirPath == null || name == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - fAVMRepository.uncover(dirPath, name); - } - - /** - * Make name in dirPath transparent to what was underneath it. That is, this - * removes the offending node from its layered directory parent's direct ownership. - * @param dirPath The path to the layered directory. - * @param name The name of the item to flatten. - */ - public void makeTransparent(String dirPath, String name) - { - if (dirPath == null || name == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - fAVMRepository.flatten(dirPath, name); - } - - /** - * Get the Latest Version ID for an AVMStore. - * @param repName The name of the AVMStore. - * @return The Latest Version ID. - */ - public int getNextVersionID(String repName) - { - if (repName == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - return fAVMRepository.getLatestVersionID(repName); - } - - /** - * Get the latest snapshot id of a store. - * @param storeName The store name. - * @return The id of the latest extant version of the store. - * @throws AVMNotFoundException If storeName does not exist. - */ - public int getLatestSnapshotID(String storeName) - { - if (storeName == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - return fAVMRepository.getLatestSnapshotID(storeName); - } - - /* - * Snapshot an AVMRepository. - * @param store The name of the AVMStore. - * @param tag The short description. - * @param description The thick description. - * @return Map of implicitly and explicitly snapshotted stores. - */ - public Map createSnapshot(String store, String tag, String description) - { - if (store == null) - { - throw new AVMBadArgumentException("Store is null."); - } - return fAVMRepository.createSnapshot(store, tag, description); - } - - /** - * Look up information about a node. - * @param version The version to look up. - * @param path The path to look up. - * @return A Descriptor. - */ - public AVMNodeDescriptor lookup(int version, String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Illegal null path."); - } - return lookup(version, path, false); - } - - /** - * Lookup a node by version ids and path, with the option of - * seeing Deleted Nodes. - * @param version The version id to look under. - * @param path The simple absolute path to the parent directory. - * @param includeDeleted Whether to see Deleted Nodes. - * @return An AVMNodeDescriptor. - * @throws AVMNotFoundException If path does not exist or - * if version does not exist. - * @throws AVMWrongTypeException If path contains a non-terminal - * element that is not a directory. - */ - public AVMNodeDescriptor lookup(int version, String path, boolean includeDeleted) - { - if (path == null) - { - throw new AVMBadArgumentException("Path is null."); - } - try - { - Lookup lookup = fAVMRepository.lookup(version, path, includeDeleted); - if (lookup == null) - { - return null; - } - return lookup.getCurrentNode().getDescriptor(lookup); - } - catch (AVMNotFoundException e) - { - return null; - } - } - - /** - * Lookup a node descriptor from a directory node descriptor. - * @param dir The node descriptor of the directory. - * @param name The name to lookup. - * @return The node descriptor of the child. - */ - public AVMNodeDescriptor lookup(AVMNodeDescriptor dir, String name) - { - if (dir == null || name == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - return lookup(dir, name, false); - } - - /** - * Lookup a node from a directory node, with the option of seeing - * Deleted Nodes. - * @param dir The descriptor for the directory node. - * @param name The name to lookup. - * @param includeDeleted Whether to see Deleted Nodes. - * @return The descriptor for the child. - * @throws AVMNotFoundException If name does not exist or - * if dir is dangling. - * @throws AVMWrongTypeException If dir does not refer to a directory. - */ - public AVMNodeDescriptor lookup(AVMNodeDescriptor dir, String name, boolean includeDeleted) - { - if (dir == null || name == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - try - { - return fAVMRepository.lookup(dir, name, includeDeleted); - } - catch (AVMNotFoundException e) - { - return null; - } - } - - /** - * Get a list of all paths that a given node has. - * @param desc The node descriptor to get paths for. - * @return A List of version, path Pairs. - */ - public List> getPaths(AVMNodeDescriptor desc) - { - if (desc == null) - { - throw new AVMBadArgumentException("Descriptor is null."); - } - return fAVMRepository.getPaths(desc); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getAPath(org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ - public Pair getAPath(AVMNodeDescriptor desc) - { - if (desc == null) - { - throw new AVMBadArgumentException("Descriptor is null."); - } - return fAVMRepository.getAPath(desc); - } - - /** - * Get all paths that a given node has that are in the head version. - * @param desc The node descriptor to get paths for. - * @return A List of version, path Pairs. - */ - public List> getHeadPaths(AVMNodeDescriptor desc) - { - if (desc == null) - { - throw new AVMBadArgumentException("Descriptor is null."); - } - return fAVMRepository.getHeadPaths(desc); - } - - /** - * Get all paths to a node starting at the HEAD version of a store. - * @param desc The node descriptor. - * @param store The store. - * @return A List of all paths meeting the criteria. - */ - public List> getPathsInStoreHead(AVMNodeDescriptor desc, String store) - { - if (desc == null || store == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - return fAVMRepository.getPathsInStoreHead(desc, store); - } - - /* (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) - { - if (desc == null || store == null || version < 1) - { - throw new AVMBadArgumentException("Illegal null argument or invalid version."); - } - return fAVMRepository.getPathsInStoreVersion(desc, store, version); - } - - /** - * Purge an AVMStore. Permanently delete everything that - * is only referenced in that AVMStore. - * @param name The name of the AVMStore to purge. - */ - public void purgeStore(String name) - { - if (name == null) - { - throw new AVMBadArgumentException("Name is null."); - } - fAVMRepository.purgeAVMStore(name); - } - - /** - * Purge a particular version from a repository. - * @param version The id of the version to purge. - * @param name The name of the repository. - */ - public void purgeVersion(int version, String name) - { - if (name == null) - { - throw new AVMBadArgumentException("Name is null."); - } - fAVMRepository.purgeVersion(name, version); - } - - /** - * Get the indirection path of a layered node. - * @param version The version to lookup. - * @param path The path to lookup. - * @return The indirection path (target) of the layered node. - */ - public String getIndirectionPath(int version, String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Path is null."); - } - return fAVMRepository.getIndirectionPath(version, path); - } - - /** - * Get the extant version ids for an AVMStore. - * @param name The name of the AVMStore. - * @return A List of VersionDescriptors. - */ - public List getStoreVersions(String name) - { - if (name == null) - { - throw new AVMBadArgumentException("Name is null."); - } - return fAVMRepository.getAVMStoreVersions(name); - } - - /** - * Get version IDs by creation date. From or to may be null but not - * both. - * @param name The name of the AVMStore to search. - * @param from The earliest versions to return. - * @param to The latest versions to return. - * @return The Set of matching version IDs. - */ - public List getStoreVersions(String name, Date from, Date to) - { - if (name == null || (from == null && to == null)) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - return fAVMRepository.getAVMStoreVersions(name, from, to); - } - - /** - * Change what a layered directory points to. - * @param path The path to the layered directory. - */ - public void retargetLayeredDirectory(String path, String target) - { - if (path == null || target == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - fAVMRepository.retargetLayeredDirectory(path, target); - } - - /** - * Make the indicated directory a primary indirection. - * @param path The absolute path. - */ - public void makePrimary(String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Path is null."); - } - fAVMRepository.makePrimary(path); - } - - /** - * Get a list of all AVMStores. - * @return The AVMStores. - */ - public List getStores() - { - return fAVMRepository.getAVMStores(); - } - - /** - * Get a reposotory. - * @param name The name of the AVMStore to get. - * @return The AVMStore. - */ - public AVMStoreDescriptor getStore(String name) - { - if (name == null) - { - throw new AVMBadArgumentException("Null Store Name."); - } - try - { - return fAVMRepository.getAVMStore(name); - } - catch (AVMNotFoundException e) - { - return null; - } - } - - /** - * Get (and create if necessary) the system store. This store houses things - * like workflow packages. - * @return The descriptor. - */ - public AVMStoreDescriptor getSystemStore() - { - AVMStoreDescriptor store = getStore(SYSTEM); - if (store == null) - { - createStore(SYSTEM); - return getStore(SYSTEM); - } - return store; - } - - /** - * Get a descriptor for the specified AVMStore root. - * @param version The version to get. - * @param name The name of the AVMStore. - * @return The root descriptor. - */ - public AVMNodeDescriptor getStoreRoot(int version, String name) - { - if (name == null) - { - throw new AVMBadArgumentException("Name is null."); - } - return fAVMRepository.getAVMStoreRoot(version, name); - } - - /** - * Get the history of a node. - * @param desc The node to get history from. - * @param count The number of ancestors to fallow back. -1 means all. - * @return A List of ancestors most recent first. - */ - public List getHistory(AVMNodeDescriptor desc, int count) - { - if (desc == null) - { - throw new AVMBadArgumentException("Null descriptor."); - } - return fAVMRepository.getHistory(desc, count); - } - - /** - * Set the opacity of a layered directory. An opaque layer hides what - * its indirection points to. - * @param path The path to the layered directory. - * @param opacity True is opaque false is not. - */ - public void setOpacity(String path, boolean opacity) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path."); - } - fAVMRepository.setOpacity(path, opacity); - } - - /** - * Get layering information about 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) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path: " + path); - } - return fAVMRepository.getLayeringInfo(version, path); - } - - /** - * Get the common ancestor of two nodes if one exists. - * @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) - { - if (left == null || right == null) - { - throw new AVMBadArgumentException("Null node descriptor."); - } - return fAVMRepository.getCommonAncestor(left, right); - } - - /** - * Set a property on a node. - * @param path The path to the node to set the property on. - * @param name The QName of the property. - * @param value The property to set. - */ - public void setNodeProperty(String path, QName name, PropertyValue value) - { - if (path == null || name == null || value == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - fAVMRepository.setNodeProperty(path, name, value); - } - - /** - * Set a collection of properties on a node. - * @param path The path to the node. - * @param properties The Map of properties to set. - */ - public void setNodeProperties(String path, Map properties) - { - if (path == null || properties == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - fAVMRepository.setNodeProperties(path, properties); - } - - /** - * Get a property of a node by QName. - * @param version The version to look under. - * @param path The path to the node. - * @param name The QName. - * @return The PropertyValue or null if it doesn't exist. - */ - public PropertyValue getNodeProperty(int version, String path, QName name) - { - if (path == null || name == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - return fAVMRepository.getNodeProperty(version, path, name); - } - - /** - * Get all the properties associated with a node. - * @param version The version to look under. - * @param path The path to the node. - * @return A List of AVMNodeProperties. - */ - public Map getNodeProperties(int version, String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path."); - } - return fAVMRepository.getNodeProperties(version, path); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getNodeProperties(org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ - public Map getNodeProperties(AVMNodeDescriptor desc) - { - if (desc == null) - { - throw new AVMBadArgumentException("Null descriptor."); - } - return fAVMRepository.getNodeProperties(desc); - } - - /** - * Delete a property. - * @param path The path to the node. - * @param name The QName of the property to delete. - */ - public void deleteNodeProperty(String path, QName name) - { - if (path == null || name == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - fAVMRepository.deleteNodeProperty(path, name); - } - - /** - * Delete all the properties attached to an AVM node. - * @param path The path to the node. - */ - public void deleteNodeProperties(String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path."); - } - fAVMRepository.deleteNodeProperties(path); - } - - /** - * Set a property on a store. If the property exists it will be overwritten. - * @param store The store to set the property on. - * @param name The name of the property. - * @param value The value of the property. - */ - public void setStoreProperty(String store, QName name, PropertyValue value) - { - if (store == null || name == null || value == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - fAVMRepository.setStoreProperty(store, name, value); - } - - /** - * Set a group of properties on a store. Existing properties will be overwritten. - * @param store The name of the store. - * @param props A Map of the properties to set. - */ - public void setStoreProperties(String store, Map props) - { - if (store == null || props == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - fAVMRepository.setStoreProperties(store, props); - } - - /** - * Get a property from a store. - * @param store The name of the store. - * @param name The name of the property. - * @return A PropertyValue or null if non-existent. - */ - public PropertyValue getStoreProperty(String store, QName name) - { - if (store == null || name == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - return fAVMRepository.getStoreProperty(store, 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) - { - if (store == null || keyPattern == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - return fAVMRepository.queryStorePropertyKey(store, keyPattern); - } - - /** - * Queries all AVM stores for properties with keys that matcha 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) - { - if (keyPattern == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - return fAVMRepository.queryStoresPropertyKeys(keyPattern); - } - - /** - * Get all the properties associated with a store. - * @param store The name of the store. - * @return A Map of the stores properties. - */ - public Map getStoreProperties(String store) - { - if (store == null) - { - throw new AVMBadArgumentException("Null store name."); - } - return fAVMRepository.getStoreProperties(store); - } - - /** - * Delete a property on a store by name. - * @param store The name of the store. - * @param name The name of the property to delete. - */ - public void deleteStoreProperty(String store, QName name) - { - if (store == null || name == null) - { - throw new AVMBadArgumentException("Invalid null argument."); - } - fAVMRepository.deleteStoreProperty(store, name); - } - - /** - * Get the ContentData for a node. Only applies to a file. - * @param version The version to look under. - * @param path The path to the node. - * @return The ContentData object. - */ - public ContentData getContentDataForRead(int version, String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Null Path."); - } - return fAVMRepository.getContentDataForRead(version, path); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getContentDataForRead(org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ - public ContentData getContentDataForRead(AVMNodeDescriptor desc) - { - if (desc == null) - { - throw new AVMBadArgumentException("Null descriptor."); - } - return fAVMRepository.getContentDataForRead(desc); - } - - /** - * Get the Content data for writing. - * @param path The path to the node. - * @return The ContentData object. - */ - public ContentData getContentDataForWrite(String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Null Path."); - } - return fAVMRepository.getContentDataForWrite(path); - } - - /** - * Set the content data on a file. - * @param path The path to the file. - * @param data The ContentData to set. - * @throws AVMNotFoundException If path does not exist. - * @throws AVMWrongTypeException If path does not point - * to a file. - */ - public void setContentData(String path, ContentData data) - { - if (path == null || data == null) - { - throw new AVMBadArgumentException("Null Path."); - } - fAVMRepository.setContentData(path, data); - } - - /** - * Set all metadata on a node from another node. Aspects, properties, ACLs. - * @param path The path to the node to set. - * @param from The descriptor for the node to get metadata from. - */ - public void setMetaDataFrom(String path, AVMNodeDescriptor from) - { - if (path == null || from == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - fAVMRepository.setMetaDataFrom(path, from); - } - - /** - * Add an aspect to an AVM node. - * @param path The path to the node. - * @param aspectName The QName of the aspect. - * @throws AVMNotFoundException If path does not exist. - * @throws AVMExistsException If the aspect already exists. - */ - public void addAspect(String path, QName aspectName) - { - if (path == null || aspectName == null) - { - throw new AVMBadArgumentException("Illegal Null Argument."); - } - fAVMRepository.addAspect(path, aspectName); - } - - /** - * 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) - { - if (path == null) - { - throw new AVMBadArgumentException("Null path."); - } - return fAVMRepository.getAspects(version, path); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#getAspects(org.alfresco.service.cmr.avm.AVMNodeDescriptor) - */ - public Set getAspects(AVMNodeDescriptor desc) - { - if (desc == null) - { - throw new AVMBadArgumentException("Null descriptor: " + desc); - } - return fAVMRepository.getAspects(desc); - } - - /** - * Remove an aspect and 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) - { - if (path == null || aspectName == null) - { - throw new AVMBadArgumentException("Null path."); - } - fAVMRepository.removeAspect(path, aspectName); - } - - /** - * Does a node have a particular aspect. - * @param version The version to look under. - * @param path The path to the node. - * @param aspectName The aspect name to check. - * @return Whether the given node has the given aspect. - */ - public boolean hasAspect(int version, String path, QName aspectName) - { - if (path == null || aspectName == null) - { - throw new AVMBadArgumentException("Illegal Null Argument."); - } - return fAVMRepository.hasAspect(version, path, aspectName); - } - - /** - * This inserts a node into a parent directly. - * @param parentPath The path to the parent directory. - * @param name The name to give the node. - * @param toLink A descriptor for the node to insert. - */ - public void link(String parentPath, String name, AVMNodeDescriptor toLink) - { - if (parentPath == null || name == null || toLink == null) - { - throw new AVMBadArgumentException("Illegal Null Argument."); - } - fAVMRepository.link(parentPath, name, toLink); - } - - /** - * Force copy on write of a path. - * @param path The path to force. - */ - public AVMNodeDescriptor forceCopy(String path) - { - if (path == null) - { - throw new AVMBadArgumentException("Null Path."); - } - return fAVMRepository.forceCopy(path); - } - - /** - * Copy (possibly recursively) the source into the destination - * directory. - * @param srcVersion The version of the source. - * @param srcPath The path to the source. - * @param dstPath The destination directory. - * @param name The name to give the copy. - */ - public void copy(int srcVersion, String srcPath, String dstPath, String name) - { - if (srcPath == null || dstPath == null) - { - throw new AVMBadArgumentException("Null Path."); - } - if (srcVersion < 0) - { - String canonicalSrc = - AVMNodeConverter.ToAVMVersionPath( - AVMNodeConverter.ToNodeRef(srcVersion, srcPath)).getSecond(); - String canonicalDst = - AVMNodeConverter.ToAVMVersionPath( - AVMNodeConverter.ToNodeRef(-1, dstPath)).getSecond(); - if (!canonicalSrc.endsWith("/")) - { - canonicalSrc = canonicalSrc + "/"; - } - if (canonicalDst.indexOf(canonicalSrc) == 0) - { - throw new AVMBadArgumentException("Infinite Copy."); - } - } - if (!FileNameValidator.IsValid(name)) - { - throw new AVMBadArgumentException("Illegal name."); - } - AVMNodeDescriptor srcDesc = lookup(srcVersion, srcPath); - recursiveCopy(srcVersion, srcDesc, dstPath, name); - } - - /** - * Do the actual work of copying. - * @param desc The src descriptor. - * @param path The destination parent path. - * @param name The name to give the copy. - */ - private void recursiveCopy(int version, AVMNodeDescriptor desc, String path, String name) - { - String newPath = path + '/' + name; - AVMNodeDescriptor existing = lookup(-1, newPath); - if (desc.isFile()) - { - InputStream in = getFileInputStream(version, desc.getPath()); - if (existing != null) - { - removeNode(newPath); - } - createFile(path, name, in); - ContentData cd = getContentDataForRead(version, desc.getPath()); - setEncoding(newPath, cd.getEncoding()); - setMimeType(newPath, cd.getMimetype()); - } - else // desc is a directory. - { - if (existing != null && !existing.isDirectory()) - { - removeNode(newPath); - existing = null; - } - if (existing == null) - { - createDirectory(path, name); - } - Map listing = getDirectoryListing(desc); - for (Map.Entry entry : listing.entrySet()) - { - recursiveCopy(version, entry.getValue(), newPath, entry.getKey()); - } - } - // In either case copy properties, aspects, and acls. - Map props = getNodeProperties(version, desc.getPath()); - setNodeProperties(newPath, props); - Set aspects = getAspects(version, desc.getPath()); - for (QName aspect : aspects) - { - addAspect(newPath, aspect); - } - DbAccessControlList acl = fAVMRepository.getACL(version, desc.getPath()); - if (acl != null) - { - fAVMRepository.setACL(newPath, acl.getCopy()); - } - } - - /** - * Rename a store. - * @param sourceName The original name. - * @param destName The new name. - * @throws AVMNotFoundException - * @throws AVMExistsException - */ - public void renameStore(String sourceName, String destName) - { - if (sourceName == null || destName == null) - { - throw new AVMBadArgumentException("Illegal Null Argument."); - } - fAVMRepository.renameStore(sourceName, 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 node to revert. - * @param toRevertTo The descriptor of the version to revert to. - * @throws AVMNotFoundException - */ - public void revert(String path, AVMNodeDescriptor toRevertTo) - { - if (path == null || toRevertTo == null) - { - throw new AVMBadArgumentException("Illegal Null Argument."); - } - String [] baseName = AVMNodeConverter.SplitBase(path); - if (baseName.length != 2) - { - throw new AVMBadArgumentException("Cannot revert store root: " + path); - } - fAVMRepository.revert(baseName[0], baseName[1], toRevertTo); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#setGuid(java.lang.String, java.lang.String) - */ - public void setGuid(String path, String guid) - { - if (path == null || guid == null) - { - throw new AVMBadArgumentException("Illegal Null Argument."); - } - fAVMRepository.setGuid(path, guid); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#setEncoding(java.lang.String, java.lang.String) - */ - public void setEncoding(String path, String encoding) - { - if (path == null || encoding == null) - { - throw new AVMBadArgumentException("Illegal Null Argument."); - } - fAVMRepository.setEncoding(path, encoding); - } - - /* (non-Javadoc) - * @see org.alfresco.service.cmr.avm.AVMService#setMimeType(java.lang.String, java.lang.String) - */ - public void setMimeType(String path, String mimeType) - { - if (path == null || mimeType == null) - { - throw new AVMBadArgumentException("Illegal Null Argument."); - } - fAVMRepository.setMimeType(path, mimeType); - } -} +import org.apache.commons.logging.LogFactory; + +/** + * Implements the AVMService. + * @author britt + */ +public class AVMServiceImpl implements AVMService +{ + public static final String SYSTEM = "system"; + + @SuppressWarnings("unused") + private static Log fgLogger = LogFactory.getLog(AVMServiceImpl.class); + + /** + * The AVMRepository for each service thread. + */ + private AVMRepository fAVMRepository; + + /** + * Basic constructor for the service. + */ + public AVMServiceImpl() + { + } + + /** + * Set the repository reference. For Spring. + * @param avmRepository The repository reference. + */ + public void setAvmRepository(AVMRepository avmRepository) + { + fAVMRepository = avmRepository; + } + + /** + * Get an InputStream from a file. + * @param version The version to look under. + * @param path The absolute path. + * @return An InputStream + * @throws AVMNotFoundException When the path is invalid. + */ + public InputStream getFileInputStream(int version, String path) + { + if (path == null) + { + throw new AVMBadArgumentException("Null path."); + } + return fAVMRepository.getInputStream(version, path); + } + + /** + * Get an InputStream from a descriptor. + * @param desc The descriptor. + * @return An InputStream. + * @throws AVMNotFoundException + */ + public InputStream getFileInputStream(AVMNodeDescriptor desc) + { + if (desc == null) + { + throw new AVMBadArgumentException("Illegal Null Argument."); + } + return fAVMRepository.getInputStream(desc); + } + + /** + * Get an output stream to a file. Triggers versioning. + */ + public OutputStream getFileOutputStream(String path) + { + if (path == null) + { + throw new AVMBadArgumentException("Null path."); + } + return fAVMRepository.getOutputStream(path); + } + + /** + * 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) + { + if (path == null) + { + throw new AVMBadArgumentException("Null path."); + } + return fAVMRepository.getContentReader(version, path); + } + + /** + * Get a ContentWriter to a file node. + * @param path The path to the file. + * @return A ContentWriter. + */ + public ContentWriter getContentWriter(String path) + { + if (path == null) + { + throw new AVMBadArgumentException("Null path."); + } + return fAVMRepository.createContentWriter(path); + } + + /** + * Get a directory listing. + * @param version The version id to lookup. + * @param path The path to lookup. + */ + public SortedMap getDirectoryListing(int version, String path) + { + return getDirectoryListing(version, path, false); + } + + /** + * Get a listing of a Folder by name, with the option of seeing + * Deleted Nodes. + * @param version The version id to look in. + * @param path The simple absolute path to the file node. + * @param includeDeleted Whether to see Deleted Nodes. + * @return A Map of names to descriptors. + * @throws AVMNotFoundException If path is not found. + * @throws AVMWrongTypeException If path contains a non-terminal + * component that is not a directory, or if path is not pointing + * at a directory. + */ + public SortedMap getDirectoryListing(int version, String path, + boolean includeDeleted) + { + if (path == null) + { + throw new AVMBadArgumentException("Null path."); + } + return fAVMRepository.getListing(version, path, includeDeleted); + } + + /** + * Get a directory listing as an Array of AVMNodeDescriptors. + * @param version The version to look under. + * @param path The path to the directory to be listed. + * @param includeDeleted Whether to include ghosts. + * @return An array of AVMNodeDescriptors. + */ + public AVMNodeDescriptor [] getDirectoryListingArray(int version, String path, + boolean includeDeleted) + { + Map listing = + getDirectoryListing(version, path, includeDeleted); + AVMNodeDescriptor [] result = new AVMNodeDescriptor[listing.size()]; + int off = 0; + for (AVMNodeDescriptor desc : listing.values()) + { + result[off++] = desc; + } + return result; + } + + /** + * Get a directory listing as an Array of node descriptors. + * @param dir The descriptor pointing at the directory to list. + * @param includeDeleted Whether to show ghosts. + * @return An array of AVMNodeDescriptors. + */ + public AVMNodeDescriptor [] getDirectoryListingArray(AVMNodeDescriptor dir, + boolean includeDeleted) + { + Map listing = + getDirectoryListing(dir, includeDeleted); + AVMNodeDescriptor [] result = new AVMNodeDescriptor[listing.size()]; + int off = 0; + for (AVMNodeDescriptor desc : listing.values()) + { + result[off++] = desc; + } + return result; + } + + /** + * Get a listing of all the directly contained children of a directory. + * @param dir The directory descriptor. + * @param includeDeleted Whether to include deleted children. + * @return A Map of Strings to descriptors. + */ + public SortedMap + getDirectoryListingDirect(AVMNodeDescriptor dir, boolean includeDeleted) + { + if (dir == null) + { + throw new AVMBadArgumentException("Illegal null descriptor."); + } + return fAVMRepository.getListingDirect(dir, includeDeleted); + } + + /** + * Get the listing of nodes contained directly in a directory. This is the + * same as getDirectoryListing for PlainDirectories, but returns only those that + * are directly contained in a layered directory. + * @param version The version to look up. + * @param path The full path to get listing for. + * @return A Map of names to descriptors. + * @throws AVMNotFoundException If path does not exist. + * @throws AVMWrongTypeException If path contains any non-directory + * elements. + */ + public SortedMap + getDirectoryListingDirect(int version, String path) + { + return getDirectoryListingDirect(version, path, false); + } + + /** + * Get the listing of nodes contained directly in a directory. This is the + * same as getDirectoryListing for PlainDirectories, but returns only those that + * are directly contained in a layered directory. This has the option of + * seeing Deleted Nodes. + * @param version The version to look up. + * @param path The full path to get listing for. + * @param includeDeleted Whether to see Deleted Nodes. + * @return A Map of names to descriptors. + * @throws AVMNotFoundException If path does not exist. + * @throws AVMWrongTypeException If path contains any non-directory + * elements. + */ + public SortedMap + getDirectoryListingDirect(int version, String path, boolean includeDeleted) + { + if (path == null) + { + throw new AVMBadArgumentException("Null path."); + } + return fAVMRepository.getListingDirect(version, path, includeDeleted); + } + + /** + * Get a directory listing from a node descriptor. + * @param dir The directory node descriptor. + * @return A Map of names to node descriptors. + */ + public SortedMap getDirectoryListing(AVMNodeDescriptor dir) + { + return getDirectoryListing(dir, false); + } + + /** + * Get a directory listing from a node descriptor, with the option of + * seeing deleted nodes. + * @param dir The directory node descriptor. + * @param includeDeleted Whether to see Deleted Nodes. + * @return A Map of names to node descriptors. + * @throws AVMNotFoundException If the descriptor is stale. + * @throws AVMWrongTypeException If the descriptor does not point at a directory. + */ + public SortedMap getDirectoryListing(AVMNodeDescriptor dir, + boolean includeDeleted) + { + if (dir == null) + { + throw new AVMBadArgumentException("Null descriptor."); + } + return fAVMRepository.getListing(dir, includeDeleted); + } + + /** + * Get the names of nodes that have been deleted in a directory. + * @param version The version to look under. + * @param path The path of the directory. + * @return A List of names. + * @throws AVMNotFoundException If path does not exist. + * @throws AVMWrongTypeException If path contains any elements + * that are not directories. + */ + public List getDeleted(int version, String path) + { + if (path == null) + { + throw new AVMBadArgumentException("Null path."); + } + return fAVMRepository.getDeleted(version, path); + } + + /** + * Create a new file. The file must not exist. + * @param path The path to the containing directory. + * @param name The name of the file. + * @return An output stream to the file. + */ + public OutputStream createFile(String path, String name) + { + if (path == null || name == null || !FileNameValidator.IsValid(name)) + { + throw new AVMBadArgumentException("Illegal argument."); + } + return fAVMRepository.createFile(path, name); + } + + /** + * Create a file with content specified by the InputStream. + * Guaranteed to be created atomically. + * @param path The path to the containing directory. + * @param name The name to give the file. + * @param in An InputStream containing data for file. + */ + public void createFile(String path, String name, InputStream in) + { + createFile(path, name, in, null, null); + } + + /* (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) + { + if (path == null || name == null || in == null || !FileNameValidator.IsValid(name)) + { + throw new AVMBadArgumentException("Illegal argument."); + } + // Save the contents to temp space. + File temp; + try + { + temp = TempFileProvider.createTempFile("alf", "tmp"); + OutputStream out = new FileOutputStream(temp); + byte [] buff = new byte[8192]; + int read; + while ((read = in.read(buff)) != -1) + { + out.write(buff, 0, read); + } + out.close(); + in.close(); + } + catch (IOException ie) + { + throw new AVMException("I/O Error."); + } + try + { + fAVMRepository.createFile(path, name, temp, aspects, properties); + } + finally + { + temp.delete(); + } + } + + /** + * Create a directory. The directory must not exist. + * @param path The path to the containing directory. + * @param name The name of the new directory. + */ + public void createDirectory(String path, String name) + { + createDirectory(path, name, null, null); + } + + /* (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) + { + if (path == null || name == null || !FileNameValidator.IsValid(name)) + { + throw new AVMBadArgumentException("Illegal argument."); + } + fAVMRepository.createDirectory(path, name, aspects, properties); + } + + /** + * Create a new layered file. It must not exist. + * @param srcPath The src path. Ie the target for the layering. + * @param parent The path to the parent directory. + * @param name The name to give the new file. + */ + public void createLayeredFile(String srcPath, String parent, String name) + { + if (srcPath == null || parent == null || name == null || + !FileNameValidator.IsValid(name)) + { + throw new AVMBadArgumentException("Illegal argument."); + } + fAVMRepository.createLayeredFile(srcPath, parent, name); + } + + /** + * Create a new layered directory. It must not exist. + * @param srcPath The src path. Ie the target for layering. + * @param parent The path to the parent directory. + * @param name The name for the new directory. + */ + public void createLayeredDirectory(String srcPath, String parent, String name) + { + if (srcPath == null || parent == null || name == null || + !FileNameValidator.IsValid(name)) + { + throw new AVMBadArgumentException("Illegal argument."); + } + fAVMRepository.createLayeredDirectory(srcPath, parent, name); + } + + /** + * Create an AVMStore with the given name. It must not exist. + * @param name The name to give the AVMStore. + */ + public void createStore(String name) + { + if (name == null || !FileNameValidator.IsValid(name)) + { + throw new AVMBadArgumentException("Bad Name."); + } + fAVMRepository.createAVMStore(name); + } + + /** + * Create a branch. + * @param version The version to branch from. + * @param srcPath The path to the thing to branch from. + * @param dstPath The path to the destination containing directory. + * @param name The name of the new branch. + */ + public void createBranch(int version, String srcPath, String dstPath, + String name) + { + if (srcPath == null || dstPath == null || name == null || + !FileNameValidator.IsValid(name)) + { + throw new AVMBadArgumentException("Illegal argument."); + } + fAVMRepository.createBranch(version, srcPath, dstPath, name); + } + + /** + * Remove a node. Beware, the node can be a directory and + * this acts recursively. + * @param parent The path to the parent. + * @param name The name of the node to remove. + */ + public void removeNode(String parent, String name) + { + if (parent == null || name == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + fAVMRepository.remove(parent, name); + } + + /** + * Remove a node by full path. + * @param path The full path to the node. + */ + public void removeNode(String path) + { + if (path == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + String [] basePath = AVMNodeConverter.SplitBase(path); + if (basePath[0] == null) + { + throw new AVMBadArgumentException("Cannot remove root node: " + path); + } + fAVMRepository.remove(basePath[0], basePath[1]); + } + + /** + * Rename a node. + * @param srcParent The path to the source parent. + * @param srcName The name of the source node. + * @param dstParent The path to the destination parent. + * @param dstName The name to give the renamed node. + */ + public void rename(String srcParent, String srcName, String dstParent, + String dstName) + { + if (srcParent == null || srcName == null || dstParent == null || dstName == null || + !FileNameValidator.IsValid(dstName)) + { + throw new AVMBadArgumentException("Illegal argument."); + } + fAVMRepository.rename(srcParent, srcName, dstParent, dstName); + } + + /** + * 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) + { + if (dirPath == null || name == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + fAVMRepository.uncover(dirPath, name); + } + + /** + * Make name in dirPath transparent to what was underneath it. That is, this + * removes the offending node from its layered directory parent's direct ownership. + * @param dirPath The path to the layered directory. + * @param name The name of the item to flatten. + */ + public void makeTransparent(String dirPath, String name) + { + if (dirPath == null || name == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + fAVMRepository.flatten(dirPath, name); + } + + /** + * Get the Latest Version ID for an AVMStore. + * @param repName The name of the AVMStore. + * @return The Latest Version ID. + */ + public int getNextVersionID(String repName) + { + if (repName == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + return fAVMRepository.getLatestVersionID(repName); + } + + /** + * Get the latest snapshot id of a store. + * @param storeName The store name. + * @return The id of the latest extant version of the store. + * @throws AVMNotFoundException If storeName does not exist. + */ + public int getLatestSnapshotID(String storeName) + { + if (storeName == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + return fAVMRepository.getLatestSnapshotID(storeName); + } + + /* + * Snapshot an AVMRepository. + * @param store The name of the AVMStore. + * @param tag The short description. + * @param description The thick description. + * @return Map of implicitly and explicitly snapshotted stores. + */ + public Map createSnapshot(String store, String tag, String description) + { + if (store == null) + { + throw new AVMBadArgumentException("Store is null."); + } + return fAVMRepository.createSnapshot(store, tag, description); + } + + /** + * Look up information about a node. + * @param version The version to look up. + * @param path The path to look up. + * @return A Descriptor. + */ + public AVMNodeDescriptor lookup(int version, String path) + { + if (path == null) + { + throw new AVMBadArgumentException("Illegal null path."); + } + return lookup(version, path, false); + } + + /** + * Lookup a node by version ids and path, with the option of + * seeing Deleted Nodes. + * @param version The version id to look under. + * @param path The simple absolute path to the parent directory. + * @param includeDeleted Whether to see Deleted Nodes. + * @return An AVMNodeDescriptor. + * @throws AVMNotFoundException If path does not exist or + * if version does not exist. + * @throws AVMWrongTypeException If path contains a non-terminal + * element that is not a directory. + */ + public AVMNodeDescriptor lookup(int version, String path, boolean includeDeleted) + { + if (path == null) + { + throw new AVMBadArgumentException("Path is null."); + } + try + { + Lookup lookup = fAVMRepository.lookup(version, path, includeDeleted); + if (lookup == null) + { + return null; + } + return lookup.getCurrentNode().getDescriptor(lookup); + } + catch (AVMNotFoundException e) + { + return null; + } + } + + /** + * Lookup a node descriptor from a directory node descriptor. + * @param dir The node descriptor of the directory. + * @param name The name to lookup. + * @return The node descriptor of the child. + */ + public AVMNodeDescriptor lookup(AVMNodeDescriptor dir, String name) + { + if (dir == null || name == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + return lookup(dir, name, false); + } + + /** + * Lookup a node from a directory node, with the option of seeing + * Deleted Nodes. + * @param dir The descriptor for the directory node. + * @param name The name to lookup. + * @param includeDeleted Whether to see Deleted Nodes. + * @return The descriptor for the child. + * @throws AVMNotFoundException If name does not exist or + * if dir is dangling. + * @throws AVMWrongTypeException If dir does not refer to a directory. + */ + public AVMNodeDescriptor lookup(AVMNodeDescriptor dir, String name, boolean includeDeleted) + { + if (dir == null || name == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + try + { + return fAVMRepository.lookup(dir, name, includeDeleted); + } + catch (AVMNotFoundException e) + { + return null; + } + } + + /** + * Get a list of all paths that a given node has. + * @param desc The node descriptor to get paths for. + * @return A List of version, path Pairs. + */ + public List> getPaths(AVMNodeDescriptor desc) + { + if (desc == null) + { + throw new AVMBadArgumentException("Descriptor is null."); + } + return fAVMRepository.getPaths(desc); + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.avm.AVMService#getAPath(org.alfresco.service.cmr.avm.AVMNodeDescriptor) + */ + public Pair getAPath(AVMNodeDescriptor desc) + { + if (desc == null) + { + throw new AVMBadArgumentException("Descriptor is null."); + } + return fAVMRepository.getAPath(desc); + } + + /** + * Get all paths that a given node has that are in the head version. + * @param desc The node descriptor to get paths for. + * @return A List of version, path Pairs. + */ + public List> getHeadPaths(AVMNodeDescriptor desc) + { + if (desc == null) + { + throw new AVMBadArgumentException("Descriptor is null."); + } + return fAVMRepository.getHeadPaths(desc); + } + + /** + * Get all paths to a node starting at the HEAD version of a store. + * @param desc The node descriptor. + * @param store The store. + * @return A List of all paths meeting the criteria. + */ + public List> getPathsInStoreHead(AVMNodeDescriptor desc, String store) + { + if (desc == null || store == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + return fAVMRepository.getPathsInStoreHead(desc, store); + } + + /* (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) + { + if (desc == null || store == null || version < 1) + { + throw new AVMBadArgumentException("Illegal null argument or invalid version."); + } + return fAVMRepository.getPathsInStoreVersion(desc, store, version); + } + + /** + * Purge an AVMStore. Permanently delete everything that + * is only referenced in that AVMStore. + * @param name The name of the AVMStore to purge. + */ + public void purgeStore(String name) + { + if (name == null) + { + throw new AVMBadArgumentException("Name is null."); + } + fAVMRepository.purgeAVMStore(name); + } + + /** + * Purge a particular version from a repository. + * @param version The id of the version to purge. + * @param name The name of the repository. + */ + public void purgeVersion(int version, String name) + { + if (name == null) + { + throw new AVMBadArgumentException("Name is null."); + } + fAVMRepository.purgeVersion(name, version); + } + + /** + * Get the indirection path of a layered node. + * @param version The version to lookup. + * @param path The path to lookup. + * @return The indirection path (target) of the layered node. + */ + public String getIndirectionPath(int version, String path) + { + if (path == null) + { + throw new AVMBadArgumentException("Path is null."); + } + return fAVMRepository.getIndirectionPath(version, path); + } + + /** + * Get the extant version ids for an AVMStore. + * @param name The name of the AVMStore. + * @return A List of VersionDescriptors. + */ + public List getStoreVersions(String name) + { + if (name == null) + { + throw new AVMBadArgumentException("Name is null."); + } + return fAVMRepository.getAVMStoreVersions(name); + } + + /** + * Get version IDs by creation date. From or to may be null but not + * both. + * @param name The name of the AVMStore to search. + * @param from The earliest versions to return. + * @param to The latest versions to return. + * @return The Set of matching version IDs. + */ + public List getStoreVersions(String name, Date from, Date to) + { + if (name == null || (from == null && to == null)) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + return fAVMRepository.getAVMStoreVersions(name, from, to); + } + + /** + * Change what a layered directory points to. + * @param path The path to the layered directory. + */ + public void retargetLayeredDirectory(String path, String target) + { + if (path == null || target == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + fAVMRepository.retargetLayeredDirectory(path, target); + } + + /** + * Make the indicated directory a primary indirection. + * @param path The absolute path. + */ + public void makePrimary(String path) + { + if (path == null) + { + throw new AVMBadArgumentException("Path is null."); + } + fAVMRepository.makePrimary(path); + } + + /** + * Get a list of all AVMStores. + * @return The AVMStores. + */ + public List getStores() + { + return fAVMRepository.getAVMStores(); + } + + /** + * Get a reposotory. + * @param name The name of the AVMStore to get. + * @return The AVMStore. + */ + public AVMStoreDescriptor getStore(String name) + { + if (name == null) + { + throw new AVMBadArgumentException("Null Store Name."); + } + try + { + return fAVMRepository.getAVMStore(name); + } + catch (AVMNotFoundException e) + { + return null; + } + } + + /** + * Get (and create if necessary) the system store. This store houses things + * like workflow packages. + * @return The descriptor. + */ + public AVMStoreDescriptor getSystemStore() + { + AVMStoreDescriptor store = getStore(SYSTEM); + if (store == null) + { + createStore(SYSTEM); + return getStore(SYSTEM); + } + return store; + } + + /** + * Get a descriptor for the specified AVMStore root. + * @param version The version to get. + * @param name The name of the AVMStore. + * @return The root descriptor. + */ + public AVMNodeDescriptor getStoreRoot(int version, String name) + { + if (name == null) + { + throw new AVMBadArgumentException("Name is null."); + } + return fAVMRepository.getAVMStoreRoot(version, name); + } + + /** + * Get the history of a node. + * @param desc The node to get history from. + * @param count The number of ancestors to fallow back. -1 means all. + * @return A List of ancestors most recent first. + */ + public List getHistory(AVMNodeDescriptor desc, int count) + { + if (desc == null) + { + throw new AVMBadArgumentException("Null descriptor."); + } + return fAVMRepository.getHistory(desc, count); + } + + /** + * Set the opacity of a layered directory. An opaque layer hides what + * its indirection points to. + * @param path The path to the layered directory. + * @param opacity True is opaque false is not. + */ + public void setOpacity(String path, boolean opacity) + { + if (path == null) + { + throw new AVMBadArgumentException("Null path."); + } + fAVMRepository.setOpacity(path, opacity); + } + + /** + * Get layering information about 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) + { + if (path == null) + { + throw new AVMBadArgumentException("Null path: " + path); + } + return fAVMRepository.getLayeringInfo(version, path); + } + + /** + * Get the common ancestor of two nodes if one exists. + * @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) + { + if (left == null || right == null) + { + throw new AVMBadArgumentException("Null node descriptor."); + } + return fAVMRepository.getCommonAncestor(left, right); + } + + /** + * Set a property on a node. + * @param path The path to the node to set the property on. + * @param name The QName of the property. + * @param value The property to set. + */ + public void setNodeProperty(String path, QName name, PropertyValue value) + { + if (path == null || name == null || value == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + fAVMRepository.setNodeProperty(path, name, value); + } + + /** + * Set a collection of properties on a node. + * @param path The path to the node. + * @param properties The Map of properties to set. + */ + public void setNodeProperties(String path, Map properties) + { + if (path == null || properties == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + fAVMRepository.setNodeProperties(path, properties); + } + + /** + * Get a property of a node by QName. + * @param version The version to look under. + * @param path The path to the node. + * @param name The QName. + * @return The PropertyValue or null if it doesn't exist. + */ + public PropertyValue getNodeProperty(int version, String path, QName name) + { + if (path == null || name == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + return fAVMRepository.getNodeProperty(version, path, name); + } + + /** + * Get all the properties associated with a node. + * @param version The version to look under. + * @param path The path to the node. + * @return A List of AVMNodeProperties. + */ + public Map getNodeProperties(int version, String path) + { + if (path == null) + { + throw new AVMBadArgumentException("Null path."); + } + return fAVMRepository.getNodeProperties(version, path); + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.avm.AVMService#getNodeProperties(org.alfresco.service.cmr.avm.AVMNodeDescriptor) + */ + public Map getNodeProperties(AVMNodeDescriptor desc) + { + if (desc == null) + { + throw new AVMBadArgumentException("Null descriptor."); + } + return fAVMRepository.getNodeProperties(desc); + } + + /** + * Delete a property. + * @param path The path to the node. + * @param name The QName of the property to delete. + */ + public void deleteNodeProperty(String path, QName name) + { + if (path == null || name == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + fAVMRepository.deleteNodeProperty(path, name); + } + + /** + * Delete all the properties attached to an AVM node. + * @param path The path to the node. + */ + public void deleteNodeProperties(String path) + { + if (path == null) + { + throw new AVMBadArgumentException("Null path."); + } + fAVMRepository.deleteNodeProperties(path); + } + + /** + * Set a property on a store. If the property exists it will be overwritten. + * @param store The store to set the property on. + * @param name The name of the property. + * @param value The value of the property. + */ + public void setStoreProperty(String store, QName name, PropertyValue value) + { + if (store == null || name == null || value == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + fAVMRepository.setStoreProperty(store, name, value); + } + + /** + * Set a group of properties on a store. Existing properties will be overwritten. + * @param store The name of the store. + * @param props A Map of the properties to set. + */ + public void setStoreProperties(String store, Map props) + { + if (store == null || props == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + fAVMRepository.setStoreProperties(store, props); + } + + /** + * Get a property from a store. + * @param store The name of the store. + * @param name The name of the property. + * @return A PropertyValue or null if non-existent. + */ + public PropertyValue getStoreProperty(String store, QName name) + { + if (store == null || name == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + return fAVMRepository.getStoreProperty(store, 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) + { + if (store == null || keyPattern == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + return fAVMRepository.queryStorePropertyKey(store, keyPattern); + } + + /** + * Queries all AVM stores for properties with keys that matcha 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) + { + if (keyPattern == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + return fAVMRepository.queryStoresPropertyKeys(keyPattern); + } + + /** + * Get all the properties associated with a store. + * @param store The name of the store. + * @return A Map of the stores properties. + */ + public Map getStoreProperties(String store) + { + if (store == null) + { + throw new AVMBadArgumentException("Null store name."); + } + return fAVMRepository.getStoreProperties(store); + } + + /** + * Delete a property on a store by name. + * @param store The name of the store. + * @param name The name of the property to delete. + */ + public void deleteStoreProperty(String store, QName name) + { + if (store == null || name == null) + { + throw new AVMBadArgumentException("Invalid null argument."); + } + fAVMRepository.deleteStoreProperty(store, name); + } + + /** + * Get the ContentData for a node. Only applies to a file. + * @param version The version to look under. + * @param path The path to the node. + * @return The ContentData object. + */ + public ContentData getContentDataForRead(int version, String path) + { + if (path == null) + { + throw new AVMBadArgumentException("Null Path."); + } + return fAVMRepository.getContentDataForRead(version, path); + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.avm.AVMService#getContentDataForRead(org.alfresco.service.cmr.avm.AVMNodeDescriptor) + */ + public ContentData getContentDataForRead(AVMNodeDescriptor desc) + { + if (desc == null) + { + throw new AVMBadArgumentException("Null descriptor."); + } + return fAVMRepository.getContentDataForRead(desc); + } + + /** + * Get the Content data for writing. + * @param path The path to the node. + * @return The ContentData object. + */ + public ContentData getContentDataForWrite(String path) + { + if (path == null) + { + throw new AVMBadArgumentException("Null Path."); + } + return fAVMRepository.getContentDataForWrite(path); + } + + /** + * Set the content data on a file. + * @param path The path to the file. + * @param data The ContentData to set. + * @throws AVMNotFoundException If path does not exist. + * @throws AVMWrongTypeException If path does not point + * to a file. + */ + public void setContentData(String path, ContentData data) + { + if (path == null || data == null) + { + throw new AVMBadArgumentException("Null Path."); + } + fAVMRepository.setContentData(path, data); + } + + /** + * Set all metadata on a node from another node. Aspects, properties, ACLs. + * @param path The path to the node to set. + * @param from The descriptor for the node to get metadata from. + */ + public void setMetaDataFrom(String path, AVMNodeDescriptor from) + { + if (path == null || from == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + fAVMRepository.setMetaDataFrom(path, from); + } + + /** + * Add an aspect to an AVM node. + * @param path The path to the node. + * @param aspectName The QName of the aspect. + * @throws AVMNotFoundException If path does not exist. + * @throws AVMExistsException If the aspect already exists. + */ + public void addAspect(String path, QName aspectName) + { + if (path == null || aspectName == null) + { + throw new AVMBadArgumentException("Illegal Null Argument."); + } + fAVMRepository.addAspect(path, aspectName); + } + + /** + * 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) + { + if (path == null) + { + throw new AVMBadArgumentException("Null path."); + } + return fAVMRepository.getAspects(version, path); + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.avm.AVMService#getAspects(org.alfresco.service.cmr.avm.AVMNodeDescriptor) + */ + public Set getAspects(AVMNodeDescriptor desc) + { + if (desc == null) + { + throw new AVMBadArgumentException("Null descriptor: " + desc); + } + return fAVMRepository.getAspects(desc); + } + + /** + * Remove an aspect and 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) + { + if (path == null || aspectName == null) + { + throw new AVMBadArgumentException("Null path."); + } + fAVMRepository.removeAspect(path, aspectName); + } + + /** + * Does a node have a particular aspect. + * @param version The version to look under. + * @param path The path to the node. + * @param aspectName The aspect name to check. + * @return Whether the given node has the given aspect. + */ + public boolean hasAspect(int version, String path, QName aspectName) + { + if (path == null || aspectName == null) + { + throw new AVMBadArgumentException("Illegal Null Argument."); + } + return fAVMRepository.hasAspect(version, path, aspectName); + } + + /** + * This inserts a node into a parent directly. + * @param parentPath The path to the parent directory. + * @param name The name to give the node. + * @param toLink A descriptor for the node to insert. + */ + public void link(String parentPath, String name, AVMNodeDescriptor toLink) + { + if (parentPath == null || name == null || toLink == null) + { + throw new AVMBadArgumentException("Illegal Null Argument."); + } + fAVMRepository.link(parentPath, name, toLink); + } + + /** + * Force copy on write of a path. + * @param path The path to force. + */ + public AVMNodeDescriptor forceCopy(String path) + { + if (path == null) + { + throw new AVMBadArgumentException("Null Path."); + } + return fAVMRepository.forceCopy(path); + } + + /** + * Copy (possibly recursively) the source into the destination + * directory. + * @param srcVersion The version of the source. + * @param srcPath The path to the source. + * @param dstPath The destination directory. + * @param name The name to give the copy. + */ + public void copy(int srcVersion, String srcPath, String dstPath, String name) + { + if (srcPath == null || dstPath == null) + { + throw new AVMBadArgumentException("Null Path."); + } + if (srcVersion < 0) + { + String canonicalSrc = + AVMNodeConverter.ToAVMVersionPath( + AVMNodeConverter.ToNodeRef(srcVersion, srcPath)).getSecond(); + String canonicalDst = + AVMNodeConverter.ToAVMVersionPath( + AVMNodeConverter.ToNodeRef(-1, dstPath)).getSecond(); + if (!canonicalSrc.endsWith("/")) + { + canonicalSrc = canonicalSrc + "/"; + } + if (canonicalDst.indexOf(canonicalSrc) == 0) + { + throw new AVMBadArgumentException("Infinite Copy."); + } + } + if (!FileNameValidator.IsValid(name)) + { + throw new AVMBadArgumentException("Illegal name."); + } + AVMNodeDescriptor srcDesc = lookup(srcVersion, srcPath); + recursiveCopy(srcVersion, srcDesc, dstPath, name); + } + + + private DbAccessControlList getAclAsSystem(final int version, final String path) + { + return AuthenticationUtil.runAs(new RunAsWork(){ + + public DbAccessControlList doWork() throws Exception + { + return fAVMRepository.getACL(version, path); + }}, AuthenticationUtil.getSystemUserName()); + } + + private void setAclAsSystem(final String path, final DbAccessControlList acl) + { + AuthenticationUtil.runAs(new RunAsWork(){ + + public Object doWork() throws Exception + { + fAVMRepository.setACL(path, acl); + return null; + }}, AuthenticationUtil.getSystemUserName()); + } + + /** + * Do the actual work of copying. + * @param desc The src descriptor. + * @param path The destination parent path. + * @param name The name to give the copy. + */ + private void recursiveCopy(int version, AVMNodeDescriptor desc, String path, String name) + { + String newPath = path + '/' + name; + AVMNodeDescriptor existing = lookup(-1, newPath); + DbAccessControlList parentAcl = getAclAsSystem(-1, path); + Long parentAclId = null; + if(parentAcl != null) + { + parentAclId = parentAcl.getId(); + } + DbAccessControlList acl = getAclAsSystem(version, desc.getPath()); + + if (desc.isFile()) + { + InputStream in = getFileInputStream(version, desc.getPath()); + if (existing != null) + { + removeNode(newPath); + } + // Set the acl underneath + createFile(path, name, in); + if (acl != null) + { + setAclAsSystem(newPath, acl.getCopy(parentAclId, ACLCopyMode.COPY)); + } + ContentData cd = getContentDataForRead(version, desc.getPath()); + setEncoding(newPath, cd.getEncoding()); + setMimeType(newPath, cd.getMimetype()); + } + else // desc is a directory. + { + if (existing != null && !existing.isDirectory()) + { + removeNode(newPath); + existing = null; + } + if (existing == null) + { + createDirectory(path, name); + // Set acl before creating children as acls inherit :-) + if (acl != null) + { + setAclAsSystem(newPath, acl.getCopy(parentAclId, ACLCopyMode.COPY)); + } + } + Map listing = getDirectoryListing(desc); + for (Map.Entry entry : listing.entrySet()) + { + recursiveCopy(version, entry.getValue(), newPath, entry.getKey()); + } + } + // In either case copy properties, aspects, and acls. + Map props = getNodeProperties(version, desc.getPath()); + setNodeProperties(newPath, props); + Set aspects = getAspects(version, desc.getPath()); + for (QName aspect : aspects) + { + addAspect(newPath, aspect); + } + } + + /** + * Rename a store. + * @param sourceName The original name. + * @param destName The new name. + * @throws AVMNotFoundException + * @throws AVMExistsException + */ + public void renameStore(String sourceName, String destName) + { + if (sourceName == null || destName == null) + { + throw new AVMBadArgumentException("Illegal Null Argument."); + } + fAVMRepository.renameStore(sourceName, 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 node to revert. + * @param toRevertTo The descriptor of the version to revert to. + * @throws AVMNotFoundException + */ + public void revert(String path, AVMNodeDescriptor toRevertTo) + { + if (path == null || toRevertTo == null) + { + throw new AVMBadArgumentException("Illegal Null Argument."); + } + String [] baseName = AVMNodeConverter.SplitBase(path); + if (baseName.length != 2) + { + throw new AVMBadArgumentException("Cannot revert store root: " + path); + } + fAVMRepository.revert(baseName[0], baseName[1], toRevertTo); + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.avm.AVMService#setGuid(java.lang.String, java.lang.String) + */ + public void setGuid(String path, String guid) + { + if (path == null || guid == null) + { + throw new AVMBadArgumentException("Illegal Null Argument."); + } + fAVMRepository.setGuid(path, guid); + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.avm.AVMService#setEncoding(java.lang.String, java.lang.String) + */ + public void setEncoding(String path, String encoding) + { + if (path == null || encoding == null) + { + throw new AVMBadArgumentException("Illegal Null Argument."); + } + fAVMRepository.setEncoding(path, encoding); + } + + /* (non-Javadoc) + * @see org.alfresco.service.cmr.avm.AVMService#setMimeType(java.lang.String, java.lang.String) + */ + public void setMimeType(String path, String mimeType) + { + if (path == null || mimeType == null) + { + throw new AVMBadArgumentException("Illegal Null Argument."); + } + fAVMRepository.setMimeType(path, mimeType); + } +} diff --git a/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java b/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java new file mode 100644 index 0000000000..1ce18ff183 --- /dev/null +++ b/source/java/org/alfresco/repo/avm/AVMServicePermissionsTest.java @@ -0,0 +1,2388 @@ +/* + * 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.avm; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.transaction.RollbackException; +import javax.transaction.Status; +import javax.transaction.UserTransaction; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.domain.AccessControlListDAO; +import org.alfresco.repo.domain.DbAccessControlList; +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; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.dictionary.DictionaryService; +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.AccessPermission; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.namespace.NamespacePrefixResolver; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.Pair; +import org.odmg.DSet; +import org.springframework.context.ApplicationContext; +import org.springframework.orm.hibernate3.LocalSessionFactoryBean; + +import junit.framework.TestCase; + +/** + * Specifically test AVM permissions with the updated ACL schema + * + * @author andyh + */ +public class AVMServicePermissionsTest extends TestCase +{ + private static ApplicationContext applicationContext = ApplicationContextHelper.getApplicationContext(); + + protected NodeService nodeService; + + protected DictionaryService dictionaryService; + + protected PermissionServiceSPI permissionService; + + protected AuthenticationService authenticationService; + + private MutableAuthenticationDao authenticationDAO; + + protected LocalSessionFactoryBean sessionFactory; + + protected NodeRef rootNodeRef; + + protected NamespacePrefixResolver namespacePrefixResolver; + + protected ServiceRegistry serviceRegistry; + + protected NodeRef systemNodeRef; + + protected AuthenticationComponent authenticationComponent; + + protected ModelDAO permissionModelDAO; + + protected PersonService personService; + + protected AuthorityService authorityService; + + private AclDaoComponent aclDaoComponent; + + private UserTransaction testTX; + + private TransactionService transactionService; + + private AVMService avmService; + + private AccessControlListDAO avmACLDAO; + + private AVMNodeDAO avmNodeDAO; + + public AVMServicePermissionsTest() + { + super(); + } + + public void setUp() throws Exception + { + avmNodeDAO = (AVMNodeDAO) applicationContext.getBean("avmNodeDAO"); + + avmACLDAO = (AccessControlListDAO) applicationContext.getBean("avmACLDAO"); + + aclDaoComponent = (AclDaoComponent) applicationContext.getBean("aclDaoComponent"); + avmService = (AVMService) applicationContext.getBean("avmService"); + + nodeService = (NodeService) applicationContext.getBean("nodeService"); + dictionaryService = (DictionaryService) applicationContext.getBean(ServiceRegistry.DICTIONARY_SERVICE.getLocalName()); + permissionService = (PermissionServiceSPI) applicationContext.getBean("permissionService"); + namespacePrefixResolver = (NamespacePrefixResolver) applicationContext.getBean(ServiceRegistry.NAMESPACE_SERVICE.getLocalName()); + authenticationService = (AuthenticationService) applicationContext.getBean("authenticationService"); + authenticationComponent = (AuthenticationComponent) applicationContext.getBean("authenticationComponent"); + serviceRegistry = (ServiceRegistry) applicationContext.getBean(ServiceRegistry.SERVICE_REGISTRY); + permissionModelDAO = (ModelDAO) applicationContext.getBean("permissionsModelDAO"); + personService = (PersonService) applicationContext.getBean("personService"); + authorityService = (AuthorityService) applicationContext.getBean("authorityService"); + + authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName()); + authenticationDAO = (MutableAuthenticationDao) applicationContext.getBean("authenticationDao"); + transactionService = (TransactionService) applicationContext.getBean("transactionComponent"); + + testTX = transactionService.getUserTransaction(); + testTX.begin(); + this.authenticationComponent.setSystemUserAsCurrentUser(); + + StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.nanoTime()); + rootNodeRef = nodeService.getRootNode(storeRef); + + QName children = ContentModel.ASSOC_CHILDREN; + QName system = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "system"); + QName container = ContentModel.TYPE_CONTAINER; + QName types = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "people"); + + systemNodeRef = nodeService.createNode(rootNodeRef, children, system, container).getChildRef(); + NodeRef typesNodeRef = nodeService.createNode(systemNodeRef, children, types, container).getChildRef(); + Map props = createPersonProperties("andy"); + nodeService.createNode(typesNodeRef, children, ContentModel.TYPE_PERSON, container, props).getChildRef(); + props = createPersonProperties("lemur"); + nodeService.createNode(typesNodeRef, children, ContentModel.TYPE_PERSON, container, props).getChildRef(); + + // create an authentication object e.g. the user + if (authenticationDAO.userExists("andy")) + { + authenticationService.deleteAuthentication("andy"); + } + authenticationService.createAuthentication("andy", "andy".toCharArray()); + + if (authenticationDAO.userExists("lemur")) + { + authenticationService.deleteAuthentication("lemur"); + } + authenticationService.createAuthentication("lemur", "lemur".toCharArray()); + + if (authenticationDAO.userExists("admin")) + { + authenticationService.deleteAuthentication("admin"); + } + authenticationService.createAuthentication("admin", "admin".toCharArray()); + + if (authenticationDAO.userExists("manager")) + { + authenticationService.deleteAuthentication("manager"); + } + authenticationService.createAuthentication("manager", "manager".toCharArray()); + + if (authenticationDAO.userExists("publisher")) + { + authenticationService.deleteAuthentication("publisher"); + } + authenticationService.createAuthentication("publisher", "publisher".toCharArray()); + + if (authenticationDAO.userExists("contributor")) + { + authenticationService.deleteAuthentication("contributor"); + } + authenticationService.createAuthentication("contributor", "contributor".toCharArray()); + + if (authenticationDAO.userExists("reviewer")) + { + authenticationService.deleteAuthentication("reviewer"); + } + authenticationService.createAuthentication("reviewer", "reviewer".toCharArray()); + + authenticationComponent.clearCurrentSecurityContext(); + } + + protected void tearDown() throws Exception + { + + try + { + testTX.commit(); + } + catch (Throwable t) + { + t.printStackTrace(); + } + finally + { + AuthenticationUtil.clearCurrentSecurityContext(); + super.tearDown(); + } + } + + protected void runAs(String userName) + { + authenticationService.authenticate(userName, userName.toCharArray()); + assertNotNull(authenticationService.getCurrentUserName()); + // for(GrantedAuthority authority : woof.getAuthorities()) + // { + // System.out.println("Auth = "+authority.getAuthority()); + // } + + } + + private Map createPersonProperties(String userName) + { + HashMap properties = new HashMap(); + properties.put(ContentModel.PROP_USERNAME, userName); + return properties; + } + + protected PermissionReference getPermission(String permission) + { + return permissionModelDAO.getPermissionReference(null, permission); + } + + private void buildBaseStructure(String base) + { + avmService.createStore(base); + avmService.createDirectory(base + ":/", "base"); + avmService.createDirectory(base + ":/base", "d-a"); + avmService.createDirectory(base + ":/base/d-a", "d-aa"); + avmService.createDirectory(base + ":/base/d-a", "d-ab"); + avmService.createDirectory(base + ":/base/d-a", "d-ac"); + avmService.createFile(base + ":/base/d-a", "f-aa"); + avmService.createDirectory(base + ":/base", "d-b"); + avmService.createDirectory(base + ":/base/d-b", "d-ba"); + avmService.createDirectory(base + ":/base/d-b", "d-bb"); + avmService.createDirectory(base + ":/base/d-b", "d-bc"); + avmService.createFile(base + ":/base/d-b", "f-ba"); + avmService.createDirectory(base + ":/base", "d-c"); + avmService.createDirectory(base + ":/base/d-c", "d-ca"); + avmService.createDirectory(base + ":/base/d-c", "d-cb"); + avmService.createDirectory(base + ":/base/d-c", "d-cc"); + avmService.createFile(base + ":/base/d-c", "f-ca"); + avmService.createFile(base + ":/base", "f-a"); + + avmService.createDirectory(base + ":/base", "d-d"); + avmService.createLayeredDirectory(base + ":/base/d-a", base + ":/base/d-d", "layer-d-a"); + avmService.createLayeredDirectory(base + ":/base/d-b", base + ":/base/d-d", "layer-d-b"); + avmService.createLayeredDirectory(base + ":/base/d-c", base + ":/base/d-d", "layer-d-c"); + avmService.createLayeredFile(base + ":/base/f-a", base + ":/base/d-d", "layer-fa"); + + avmService.createLayeredDirectory(base + ":/base", base + ":/", "layer"); + + String layeredStore1 = base + "-layer-base"; + avmService.createStore(layeredStore1); + avmService.createLayeredDirectory(base + ":/base", layeredStore1 + ":/", "layer-to-base"); + + String layeredStore2 = base + "-layer-a"; + avmService.createStore(layeredStore2); + avmService.createLayeredDirectory(base + ":/base/d-a", layeredStore2 + ":/", "layer-to-d-a"); + + String layeredStore3 = base + "-layer-b"; + avmService.createStore(layeredStore3); + avmService.createLayeredDirectory(base + ":/base/d-b", layeredStore3 + ":/", "layer-to-d-b"); + + String layeredStore4 = base + "-layer-c"; + avmService.createStore(layeredStore4); + avmService.createLayeredDirectory(base + ":/base/d-c", layeredStore4 + ":/", "layer-to-d-c"); + + String layeredStore5 = base + "-layer-d"; + avmService.createStore(layeredStore5); + avmService.createLayeredDirectory(base + ":/base/d-d", layeredStore5 + ":/", "layer-to-d-d"); + + String layeredStore6 = base + "-layer-layer-base"; + avmService.createStore(layeredStore6); + avmService.createLayeredDirectory(layeredStore1 + ":/layer-to-base", layeredStore6 + ":/", "layer-to-layer-to-base"); + + String layeredStore7 = base + "-layer-layer-layer-base"; + avmService.createStore(layeredStore7); + avmService.createLayeredDirectory(layeredStore6 + ":/layer-to-layer-to-base", layeredStore7 + ":/", "layer-to-layer-to-layer-to-base"); + } + + private boolean checkPermission(String user, String path, String permission, boolean allowed) + { + String curentUser = AuthenticationUtil.getCurrentUserName(); + try + { + runAs(user); + AVMNodeDescriptor desc = avmService.lookup(-1, path); + AVMNode node = avmNodeDAO.getByID(desc.getId()); + boolean can = AVMRepository.GetInstance().can(node, permission); + return allowed ? can : !can; + } + finally + { + runAs(curentUser); + } + } + + public void testComplexStore_AlterInheritance() + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + buildBaseStructure(storeName); + + checkHeadPermissionNotSetForPath(storeName + ":/base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-base:/layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-a:/layer-to-d-a", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-b:/layer-to-d-b", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-c:/layer-to-d-c", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, + null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, + PermissionService.ALL_PERMISSIONS, true, null); + + AVMNodeDescriptor desc = avmService.lookup(-1, storeName + "-layer-base:/layer-to-base"); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true); + + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.READ, true)); + assertTrue(checkPermission("admin", storeName + "-layer-base:/layer-to-base", PermissionService.READ, true)); + assertTrue(checkPermission("admin", storeName + "-layer-base:/layer-to-base", PermissionService.ALL_PERMISSIONS, true)); + // True as unset defaults to allow + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.READ, true)); + assertTrue(checkPermission("lemur", storeName + "-layer-base:/layer-to-base", PermissionService.READ, true)); + assertTrue(checkPermission("lemur", storeName + "-layer-base:/layer-to-base", PermissionService.ALL_PERMISSIONS, true)); + + desc = avmService.lookup(-1, storeName + ":/base"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true); + permissionService.deletePermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS); + + assertTrue(checkPermission("admin", storeName + ":/base", PermissionService.READ, true)); + assertTrue(checkPermission("admin", storeName + "-layer-base:/layer-to-base", PermissionService.READ, true)); + assertTrue(checkPermission("admin", storeName + "-layer-base:/layer-to-base", PermissionService.ALL_PERMISSIONS, true)); + // True as unset defaults to allow + assertTrue(checkPermission("lemur", storeName + ":/base", PermissionService.READ, false)); + assertTrue(checkPermission("lemur", storeName + "-layer-base:/layer-to-base", PermissionService.READ, true)); + assertTrue(checkPermission("lemur", storeName + "-layer-base:/layer-to-base", PermissionService.ALL_PERMISSIONS, true)); + + String[] excludeL = new String[] { storeName + "-layer-base:/layer-to-base/d-d/layer-d-a" }; + String[] excludeLL = new String[] { storeName + "-layer-layer-base:/layer-to-layer-to-base/d-d/layer-d-a" }; + String[] excludeLLL = new String[] { storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base/d-d/layer-d-a" }; + + checkHeadPermissionNotSetForPath(storeName + ":/base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-base:/layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, excludeL); + checkHeadPermissionNotSetForPath(storeName + "-layer-a:/layer-to-d-a", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-b:/layer-to-d-b", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-c:/layer-to-d-c", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, + excludeLL); + checkHeadPermissionForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, + PermissionService.ALL_PERMISSIONS, true, excludeLLL); + + desc = avmService.lookup(-1, storeName + "-layer-base:/layer-to-base/d-a"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setInheritParentPermissions(nodeRef, false); + + String[] excludeL2 = new String[] { storeName + "-layer-base:/layer-to-base/d-d/layer-d-a", storeName + "-layer-base:/layer-to-base/d-a" }; + String[] excludeLL2 = new String[] { storeName + "-layer-layer-base:/layer-to-layer-to-base/d-d/layer-d-a", storeName + "-layer-layer-base:/layer-to-layer-to-base/d-a" }; + String[] excludeLLL2 = new String[] { storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base/d-d/layer-d-a", + storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base/d-a" }; + + checkHeadPermissionNotSetForPath(storeName + ":/base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-base:/layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, excludeL2); + checkHeadPermissionNotSetForPath(storeName + "-layer-base:/layer-to-base/d-a", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-a:/layer-to-d-a", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-b:/layer-to-d-b", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-c:/layer-to-d-c", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, + excludeLL2); + checkHeadPermissionForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, + PermissionService.ALL_PERMISSIONS, true, excludeLLL2); + + desc = avmService.lookup(-1, storeName + "-layer-base:/layer-to-base/d-a"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setInheritParentPermissions(nodeRef, true); + + checkHeadPermissionNotSetForPath(storeName + ":/base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-base:/layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, excludeL); + checkHeadPermissionNotSetForPath(storeName + "-layer-a:/layer-to-d-a", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-b:/layer-to-d-b", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-c:/layer-to-d-c", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, + excludeLL); + checkHeadPermissionForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, + PermissionService.ALL_PERMISSIONS, true, excludeLLL); + + } + finally + { + avmService.purgeStore(storeName); + } + } + + public void testComplexStore_AddPermissionsToMiddle() + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + buildBaseStructure(storeName); + + checkHeadPermissionNotSetForPath(storeName + ":/base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-base:/layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-a:/layer-to-d-a", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-b:/layer-to-d-b", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-c:/layer-to-d-c", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, + null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, + PermissionService.ALL_PERMISSIONS, true, null); + + AVMNodeDescriptor desc = avmService.lookup(-1, storeName + "-layer-a:/layer-to-d-a"); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true); + + checkHeadPermissionNotSetForPath(storeName + ":/base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-base:/layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-a:/layer-to-d-a", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-b:/layer-to-d-b", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-c:/layer-to-d-c", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, + null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, + PermissionService.ALL_PERMISSIONS, true, null); + + desc = avmService.lookup(-1, storeName + "-layer-base:/layer-to-base"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + + // debugPermissions(storeName + ":/base"); + // debugPermissions(storeName + "-layer-base:/layer-to-base"); + // + // DbAccessControlList acl = avmACLDAO.getAccessControlList(nodeRef); + // List nodes = aclDaoComponent.getAvmNodesByACL(acl.getId()); + // for (Long id : nodes) + // { + // AVMNodeDescriptor layerDesc = new AVMNodeDescriptor(null, null, 0, null, null, null, 0, 0, 0, id, null, + // 0, null, 0, false, 0, false, 0, 0); + // List> paths = avmService.getHeadPaths(layerDesc); + // for(Pair path : paths) + // { + // NodeRef testRef = AVMNodeConverter.ToNodeRef(-1, path.getSecond()); + // System.out.println("--> "+id +" "+path.getSecond()+ " "+path.getFirst()+ " + // "+avmACLDAO.getAccessControlList(testRef)); + // } + // } + + permissionService.setPermission(nodeRef, "loon", PermissionService.ALL_PERMISSIONS, true); + + // debugPermissions(storeName + ":/base"); + // debugPermissions(storeName + "-layer-base:/layer-to-base"); + // + // acl = avmACLDAO.getAccessControlList(nodeRef); + // nodes = aclDaoComponent.getAvmNodesByACL(acl.getId()); + // for (Long id : nodes) + // { + // AVMNodeDescriptor layerDesc = new AVMNodeDescriptor(null, null, 0, null, null, null, 0, 0, 0, id, null, + // 0, null, 0, false, 0, false, 0, 0); + // List> paths = avmService.getHeadPaths(layerDesc); + // for(Pair path : paths) + // { + // NodeRef testRef = AVMNodeConverter.ToNodeRef(-1, path.getSecond()); + // System.out.println("--> "+id +" "+path.getSecond()+ " "+path.getFirst()+ " + // "+avmACLDAO.getAccessControlList(testRef)); + // } + // } + // + + checkHeadPermissionNotSetForPath(storeName + ":/base", "loon", PermissionService.ALL_PERMISSIONS, true, null); + String[] excludeL = new String[] { storeName + "-layer-base:/layer-to-base/d-d/layer-d-a" }; + checkHeadPermissionForPath(storeName + "-layer-base:/layer-to-base", "loon", PermissionService.ALL_PERMISSIONS, true, excludeL); + checkHeadPermissionNotSetForPath(storeName + "-layer-a:/layer-to-d-a", "loon", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-b:/layer-to-d-b", "loon", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-c:/layer-to-d-c", "loon", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d", "loon", PermissionService.ALL_PERMISSIONS, true, null); + String[] excludeLL = new String[] { storeName + "-layer-layer-base:/layer-to-layer-to-base/d-d/layer-d-a" }; + checkHeadPermissionForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", "loon", PermissionService.ALL_PERMISSIONS, true, excludeLL); + String[] excludeLLL = new String[] { storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base/d-d/layer-d-a" }; + checkHeadPermissionForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", "loon", PermissionService.ALL_PERMISSIONS, true, excludeLLL); + + desc = avmService.lookup(-1, storeName + "-layer-base:/layer-to-base"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "monkey", PermissionService.ALL_PERMISSIONS, true); + + debugPermissions(storeName + ":/base"); + debugPermissions(storeName + "-layer-base:/layer-to-base"); + + // acl = avmACLDAO.getAccessControlList(nodeRef); + // nodes = aclDaoComponent.getAvmNodesByACL(acl.getId()); + // for (Long id : nodes) + // { + // // need to fix up inheritance as is has changed + // AVMNodeDescriptor layerDesc = new AVMNodeDescriptor(null, null, 0, null, null, null, 0, 0, 0, id, null, + // 0, null, 0, false, 0, false, 0, 0); + // List> paths = avmService.getHeadPaths(layerDesc); + // for(Pair path : paths) + // { + // NodeRef testRef = AVMNodeConverter.ToNodeRef(-1, path.getSecond()); + // System.out.println("--> "+id +" "+path.getSecond()+ " "+path.getFirst()+ " + // "+avmACLDAO.getAccessControlList(testRef)); + // } + // } + + checkHeadPermissionNotSetForPath(storeName + ":/base", "monkey", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-base:/layer-to-base", "monkey", PermissionService.ALL_PERMISSIONS, true, excludeL); + checkHeadPermissionNotSetForPath(storeName + "-layer-a:/layer-to-d-a", "monkey", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-b:/layer-to-d-b", "monkey", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-c:/layer-to-d-c", "monkey", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d", "monkey", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", "monkey", PermissionService.ALL_PERMISSIONS, true, excludeLL); + checkHeadPermissionForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", "monkey", PermissionService.ALL_PERMISSIONS, true, excludeLLL); + + debugPermissions(storeName + ":/base"); + debugPermissions(storeName + "-layer-base:/layer-to-base"); + + // acl = avmACLDAO.getAccessControlList(nodeRef); + // nodes = aclDaoComponent.getAvmNodesByACL(acl.getId()); + // for (Long id : nodes) + // { + // // need to fix up inheritance as is has changed + // AVMNodeDescriptor layerDesc = new AVMNodeDescriptor(null, null, 0, null, null, null, 0, 0, 0, id, null, + // 0, null, 0, false, 0, false, 0, 0); + // List> paths = avmService.getHeadPaths(layerDesc); + // for(Pair path : paths) + // { + // NodeRef testRef = AVMNodeConverter.ToNodeRef(-1, path.getSecond()); + // System.out.println("--> "+id +" "+path.getSecond()+ " "+path.getFirst()+ " + // "+avmACLDAO.getAccessControlList(testRef)); + // } + // } + // + desc = avmService.lookup(-1, storeName + ":/base"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "base", PermissionService.ALL_PERMISSIONS, true); + + debugPermissions(storeName + ":/base"); + debugPermissions(storeName + "-layer-base:/layer-to-base"); + checkHeadPermissionForPath(storeName + ":/base", "base", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-base:/layer-to-base", "base", PermissionService.ALL_PERMISSIONS, true, excludeL); + checkHeadPermissionNotSetForPath(storeName + "-layer-a:/layer-to-d-a", "base", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-b:/layer-to-d-b", "base", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-c:/layer-to-d-c", "base", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-d:/layer-to-d-d", "base", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", "base", PermissionService.ALL_PERMISSIONS, true, excludeLL); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", "base", PermissionService.ALL_PERMISSIONS, true, excludeLLL); + + } + finally + { + avmService.purgeStore(storeName); + } + } + + public void testComplexStore_AddPermissionsToBottom() + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + buildBaseStructure(storeName); + + checkHeadPermissionNotSetForPath(storeName + ":/base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-base:/layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-a:/layer-to-d-a", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-b:/layer-to-d-b", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-c:/layer-to-d-c", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, + null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, + PermissionService.ALL_PERMISSIONS, true, null); + + AVMNodeDescriptor desc = avmService.lookup(-1, storeName + ":/base"); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true); + + checkHeadPermissionForPath(storeName + ":/base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-base:/layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-a:/layer-to-d-a", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-b:/layer-to-d-b", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-c:/layer-to-d-c", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-d:/layer-to-d-d", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, + PermissionService.ALL_PERMISSIONS, true, null); + + permissionService.setPermission(nodeRef, "squid", PermissionService.ALL_PERMISSIONS, true); + + checkHeadPermissionForPath(storeName + ":/base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-base:/layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-a:/layer-to-d-a", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-b:/layer-to-d-b", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-c:/layer-to-d-c", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-d:/layer-to-d-d", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, + PermissionService.ALL_PERMISSIONS, true, null); + + checkHeadPermissionForPath(storeName + ":/base", "squid", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-base:/layer-to-base", "squid", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-a:/layer-to-d-a", "squid", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-b:/layer-to-d-b", "squid", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-c:/layer-to-d-c", "squid", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-d:/layer-to-d-d", "squid", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", "squid", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", "squid", PermissionService.ALL_PERMISSIONS, true, null); + + permissionService.deletePermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS); + + checkHeadPermissionNotSetForPath(storeName + ":/base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-base:/layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-a:/layer-to-d-a", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-b:/layer-to-d-b", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-c:/layer-to-d-c", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, + null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, + PermissionService.ALL_PERMISSIONS, true, null); + + permissionService.setPermission(nodeRef, "me", PermissionService.ALL_PERMISSIONS, true); + + checkHeadPermissionNotSetForPath(storeName + ":/base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-base:/layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-a:/layer-to-d-a", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-b:/layer-to-d-b", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-c:/layer-to-d-c", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, + null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, + PermissionService.ALL_PERMISSIONS, true, null); + + checkHeadPermissionForPath(storeName + ":/base", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-base:/layer-to-base", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-a:/layer-to-d-a", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-b:/layer-to-d-b", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-c:/layer-to-d-c", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-d:/layer-to-d-d", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", "me", PermissionService.ALL_PERMISSIONS, true, null); + + desc = avmService.lookup(-1, storeName + ":/base/d-a"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "lemon", PermissionService.READ, true); + + checkHeadPermissionNotSetForPath(storeName + ":/base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-base:/layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-a:/layer-to-d-a", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-b:/layer-to-d-b", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-c:/layer-to-d-c", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true, + null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", PermissionService.ALL_AUTHORITIES, + PermissionService.ALL_PERMISSIONS, true, null); + + checkHeadPermissionForPath(storeName + ":/base", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-base:/layer-to-base", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-a:/layer-to-d-a", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-b:/layer-to-d-b", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-c:/layer-to-d-c", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-d:/layer-to-d-d", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base", "me", PermissionService.ALL_PERMISSIONS, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base", "me", PermissionService.ALL_PERMISSIONS, true, null); + + checkHeadPermissionForPath(storeName + ":/base/d-a", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + ":/base/d-b", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + ":/base/d-c", "lemon", PermissionService.READ, true, null); + checkHeadPermissionForPath(storeName + ":/base/d-d/layer-d-a", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + ":/base/d-d/layer-d-b", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + ":/base/d-d/layer-d-c", "lemon", PermissionService.READ, true, null); + checkHeadPermissionForPath(storeName + "-layer-base:/layer-to-base/d-a", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-base:/layer-to-base/d-b", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-base:/layer-to-base/d-c", "lemon", PermissionService.READ, true, null); + checkHeadPermissionForPath(storeName + "-layer-base:/layer-to-base/d-d/layer-d-a", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-base:/layer-to-base/d-d/layer-d-b", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-base:/layer-to-base/d-d/layer-d-c", "lemon", PermissionService.READ, true, null); + + checkHeadPermissionForPath(storeName + "-layer-a:/layer-to-d-a", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-b:/layer-to-d-b", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-c:/layer-to-d-c", "lemon", PermissionService.READ, true, null); + checkHeadPermissionForPath(storeName + "-layer-d:/layer-to-d-d/layer-d-a", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d/layer-d-b", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-d:/layer-to-d-d/layer-d-c", "lemon", PermissionService.READ, true, null); + + checkHeadPermissionForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base/d-a", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base/d-b", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base/d-c", "lemon", PermissionService.READ, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base/d-d/layer-d-a", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base/d-d/layer-d-b", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-base:/layer-to-layer-to-base/d-d/layer-d-c", "lemon", PermissionService.READ, true, null); + + checkHeadPermissionForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base/d-a", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base/d-b", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base/d-c", "lemon", PermissionService.READ, true, null); + checkHeadPermissionForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base/d-d/layer-d-a", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base/d-d/layer-d-b", "lemon", PermissionService.READ, true, null); + checkHeadPermissionNotSetForPath(storeName + "-layer-layer-layer-base:/layer-to-layer-to-layer-to-base/d-d/layer-d-c", "lemon", PermissionService.READ, true, null); + } + finally + { + avmService.purgeStore(storeName); + } + + } + + private void checkHeadPermissionForPath(String path, String authority, String permission, boolean allow, String[] excludes) + { + AVMNodeDescriptor desc = avmService.lookup(-1, path); + checkHeadPermission(desc, authority, permission, allow); + if (desc.isDirectory()) + { + Map children = avmService.getDirectoryListing(desc); + for (String child : children.keySet()) + { + String newPath = path + "/" + child; + if (excludes != null) + { + for (String exclude : excludes) + { + if (newPath.startsWith(exclude)) + { + return; + } + } + } + checkHeadPermissionForPath(newPath, authority, permission, allow, excludes); + } + } + } + + private void checkHeadPermissionNotSetForPath(String path, String authority, String permission, boolean allow, String[] excludes) + { + AVMNodeDescriptor desc = avmService.lookup(-1, path); + checkHeadPermissionNotSet(desc, authority, permission, allow); + if (desc.isDirectory()) + { + Map children = avmService.getDirectoryListing(desc); + for (String child : children.keySet()) + { + String newPath = path + "/" + child; + if (excludes != null) + { + for (String exclude : excludes) + { + if (newPath.startsWith(exclude)) + { + return; + } + } + } + checkHeadPermissionNotSetForPath(newPath, authority, permission, allow, excludes); + } + } + } + + private void checkHeadPermissionForNode(String path, String authority, String permission, boolean allow) + { + AVMNodeDescriptor desc = avmService.lookup(-1, path); + checkHeadPermission(desc, authority, permission, allow); + } + + private void checkHeadPermissionNotSetForNode(String path, String authority, String permission, boolean allow) + { + AVMNodeDescriptor desc = avmService.lookup(-1, path); + checkHeadPermissionNotSet(desc, authority, permission, allow); + } + + private void checkHeadPermission(AVMNodeDescriptor desc, String authority, String permission, boolean allow) + { + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + Set set = permissionService.getAllSetPermissions(nodeRef); + for (AccessPermission p : set) + { + if (p.getAuthority().equals(authority)) + { + if (p.getPermission().equals(permission)) + { + // debugPermissions(desc.getPath()); + return; + } + } + } + debugPermissions(desc.getPath()); + fail("Permisssions not found at " + desc.getPath()); + // System.err.println("Permisssions not found at "+desc.getPath()); + } + + private void checkHeadPermissionNotSet(AVMNodeDescriptor desc, String authority, String permission, boolean allow) + { + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + Set set = permissionService.getAllSetPermissions(nodeRef); + for (AccessPermission p : set) + { + if (p.getAuthority().equals(authority)) + { + if (p.getPermission().equals(permission)) + { + debugPermissions(desc.getPath()); + fail("Permisssions found at " + desc.getPath()); + } + } + } + // debugPermissions(desc.getPath()); + // fail("Permisssions not found at "+desc.getPath()); + // System.err.println("Permisssions not found at "+desc.getPath()); + } + + public void testRedirectLayeredDirectory() + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + avmService.createStore(storeName); + avmService.createDirectory(storeName + ":/", "www"); + avmService.createDirectory(storeName + ":/www", "avm-web-apps"); + avmService.createFile(storeName + ":/www", "dog"); + avmService.createDirectory(storeName + ":/www/avm-web-apps", "ROOT"); + avmService.createFile(storeName + ":/www/avm-web-apps", "cat"); + + AVMNodeDescriptor desc = avmService.lookup(-1, storeName + ":/www"); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.READ, true); + assertTrue(checkPermission("lemur", storeName + ":/www", PermissionService.READ, true)); + assertTrue(checkPermission("manager", storeName + ":/www", PermissionService.READ, true)); + assertTrue(checkPermission("publisher", storeName + ":/www", PermissionService.READ, true)); + assertTrue(checkPermission("contributor", storeName + ":/www", PermissionService.READ, true)); + assertTrue(checkPermission("reviewer", storeName + ":/www", PermissionService.READ, true)); + assertTrue(checkPermission("lemur", storeName + ":/www", "Coordinator", false)); + assertTrue(checkPermission("manager", storeName + ":/www", "Coordinator", false)); + assertTrue(checkPermission("publisher", storeName + ":/www", "Coordinator", false)); + assertTrue(checkPermission("contributor", storeName + ":/www", "Coordinator", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www", "Coordinator", false)); + assertTrue(checkPermission("lemur", storeName + ":/www", "Collaborator", false)); + assertTrue(checkPermission("manager", storeName + ":/www", "Collaborator", false)); + assertTrue(checkPermission("publisher", storeName + ":/www", "Collaborator", false)); + assertTrue(checkPermission("contributor", storeName + ":/www", "Collaborator", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www", "Collaborator", false)); + assertTrue(checkPermission("lemur", storeName + ":/www", "Contributor", false)); + assertTrue(checkPermission("manager", storeName + ":/www", "Contributor", false)); + assertTrue(checkPermission("publisher", storeName + ":/www", "Contributor", false)); + assertTrue(checkPermission("contributor", storeName + ":/www", "Contributor", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www", "Contributor", false)); + assertTrue(checkPermission("lemur", storeName + ":/www", "Editor", false)); + assertTrue(checkPermission("manager", storeName + ":/www", "Editor", false)); + assertTrue(checkPermission("publisher", storeName + ":/www", "Editor", false)); + assertTrue(checkPermission("contributor", storeName + ":/www", "Editor", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www", "Editor", false)); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "manager", "ContentManager", true); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps", PermissionService.READ, true)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps", PermissionService.READ, true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps", PermissionService.READ, true)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps", PermissionService.READ, true)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps", PermissionService.READ, true)); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps", "ContentManager", false)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps", "ContentManager", true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps", "ContentManager", false)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps", "ContentManager", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps", "ContentManager", false)); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps", "ContentPublisher", false)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps", "ContentPublisher", true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps", "ContentPublisher", false)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps", "ContentPublisher", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps", "ContentPublisher", false)); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps", "ContentContributor", false)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps", "ContentContributor", true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps", "ContentContributor", false)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps", "ContentContributor", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps", "ContentContributor", false)); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps", "ContentReviewer", false)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps", "ContentReviewer", true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps", "ContentReviewer", false)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps", "ContentReviewer", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps", "ContentReviewer", false)); + desc = avmService.lookup(-1, storeName + ":/www/dog"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "publisher", "Collaborator", true); + assertTrue(checkPermission("lemur", storeName + ":/www/dog", PermissionService.READ, true)); + assertTrue(checkPermission("manager", storeName + ":/www/dog", PermissionService.READ, true)); + assertTrue(checkPermission("publisher", storeName + ":/www/dog", PermissionService.READ, true)); + assertTrue(checkPermission("contributor", storeName + ":/www/dog", PermissionService.READ, true)); + assertTrue(checkPermission("reviewer", storeName + ":/www/dog", PermissionService.READ, true)); + assertTrue(checkPermission("lemur", storeName + ":/www/dog", "Coordinator", false)); + assertTrue(checkPermission("manager", storeName + ":/www/dog", "Coordinator", false)); + assertTrue(checkPermission("publisher", storeName + ":/www/dog", "Coordinator", false)); + assertTrue(checkPermission("contributor", storeName + ":/www/dog", "Coordinator", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www/dog", "Coordinator", false)); + assertTrue(checkPermission("lemur", storeName + ":/www/dog", "Collaborator", false)); + assertTrue(checkPermission("manager", storeName + ":/www/dog", "Collaborator", false)); + assertTrue(checkPermission("publisher", storeName + ":/www/dog", "Collaborator", true)); + assertTrue(checkPermission("contributor", storeName + ":/www/dog", "Collaborator", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www/dog", "Collaborator", false)); + assertTrue(checkPermission("lemur", storeName + ":/www/dog", "Contributor", false)); + assertTrue(checkPermission("manager", storeName + ":/www/dog", "Contributor", false)); + assertTrue(checkPermission("publisher", storeName + ":/www/dog", "Contributor", true)); + assertTrue(checkPermission("contributor", storeName + ":/www/dog", "Contributor", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www/dog", "Contributor", false)); + assertTrue(checkPermission("lemur", storeName + ":/www/dog", "Editor", false)); + assertTrue(checkPermission("manager", storeName + ":/www/dog", "Editor", false)); + assertTrue(checkPermission("publisher", storeName + ":/www/dog", "Editor", true)); + assertTrue(checkPermission("contributor", storeName + ":/www/dog", "Editor", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www/dog", "Editor", false)); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "contributor", "Coordinator", true); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps/ROOT", PermissionService.READ, true)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps/ROOT", PermissionService.READ, true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps/ROOT", PermissionService.READ, true)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps/ROOT", PermissionService.READ, true)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps/ROOT", PermissionService.READ, true)); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps/ROOT", "Coordinator", false)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps/ROOT", "Coordinator", true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps/ROOT", "Coordinator", false)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps/ROOT", "Coordinator", true)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps/ROOT", "Coordinator", false)); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps/ROOT", "Collaborator", false)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps/ROOT", "Collaborator", true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps/ROOT", "Collaborator", false)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps/ROOT", "Collaborator", true)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps/ROOT", "Collaborator", false)); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps/ROOT", "Contributor", false)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps/ROOT", "Contributor", true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps/ROOT", "Contributor", false)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps/ROOT", "Contributor", true)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps/ROOT", "Contributor", false)); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps/ROOT", "Editor", false)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps/ROOT", "Editor", true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps/ROOT", "Editor", false)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps/ROOT", "Editor", true)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps/ROOT", "Editor", false)); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/cat"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "reviewer", "Editor", true); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps/cat", PermissionService.READ, true)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps/cat", PermissionService.READ, true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps/cat", PermissionService.READ, true)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps/cat", PermissionService.READ, true)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps/cat", PermissionService.READ, true)); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps/cat", "Coordinator", false)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps/cat", "Coordinator", true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps/cat", "Coordinator", false)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps/cat", "Coordinator", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps/cat", "Coordinator", false)); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps/cat", "Collaborator", false)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps/cat", "Collaborator", true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps/cat", "Collaborator", false)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps/cat", "Collaborator", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps/cat", "Collaborator", false)); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps/cat", "Contributor", false)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps/cat", "Contributor", true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps/cat", "Contributor", false)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps/cat", "Contributor", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps/cat", "Contributor", false)); + assertTrue(checkPermission("lemur", storeName + ":/www/avm-web-apps/cat", "Editor", false)); + assertTrue(checkPermission("manager", storeName + ":/www/avm-web-apps/cat", "Editor", true)); + assertTrue(checkPermission("publisher", storeName + ":/www/avm-web-apps/cat", "Editor", false)); + assertTrue(checkPermission("contributor", storeName + ":/www/avm-web-apps/cat", "Editor", false)); + assertTrue(checkPermission("reviewer", storeName + ":/www/avm-web-apps/cat", "Editor", true)); + + avmService.createSnapshot(storeName, null, null); + avmService.createLayeredDirectory(storeName + ":/www", storeName + ":/", "layer"); + + desc = avmService.lookup(-1, storeName + ":/layer"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/layer/dog"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/cat"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + + avmService.retargetLayeredDirectory(storeName + ":/layer", storeName + ":/www/avm-web-apps"); + + desc = avmService.lookup(-1, storeName + ":/layer"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/layer/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/cat"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + + avmService.retargetLayeredDirectory(storeName + ":/layer", storeName + ":/www"); + + desc = avmService.lookup(-1, storeName + ":/layer"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/layer/dog"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/cat"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + + desc = avmService.lookup(-1, storeName + ":/layer"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "monkey", PermissionService.READ, true); + avmService.createDirectory(storeName + ":/layer", "l-d"); + desc = avmService.lookup(-1, storeName + ":/layer/l-d"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "directory-monkey", PermissionService.READ, true); + avmService.createFile(storeName + ":/layer", "l-f"); + desc = avmService.lookup(-1, storeName + ":/layer/l-f"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "file-monkey", PermissionService.READ, true); + + desc = avmService.lookup(-1, storeName + ":/layer"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/layer/l-d"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/l-f"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/dog"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/cat"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + debugPermissions(storeName + ":/layer/avm-web-apps/cat"); + + // As we have set permissions on this node it has done COW and now defined its own permissions. + // Changing the target does not change the permissions just the content and locations + // Some underlying nodes have not been COWed - and so pick up underlygin changes + // - it is only layer and its direct children that will now hace fixed permissions. + // Joy all round + + // Note copy on writed nodes will move taking context.... so cat appears in two places + // / over layed as cat .... and also as avm-web-apps from the previous copy on write and then move .... + + avmService.retargetLayeredDirectory(storeName + ":/layer", storeName + ":/www/avm-web-apps"); + + desc = avmService.lookup(-1, storeName + ":/layer"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/layer/l-d"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/l-f"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + desc = avmService.lookup(-1, storeName + ":/layer/cat"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/cat"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + + avmService.retargetLayeredDirectory(storeName + ":/layer", storeName + ":/www"); + + desc = avmService.lookup(-1, storeName + ":/layer"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/layer/l-d"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/l-f"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/dog"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/cat"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + + } + finally + { + avmService.purgeStore(storeName); + } + } + + public void testCopy() + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + avmService.createStore(storeName); + avmService.createDirectory(storeName + ":/", "www"); + avmService.createDirectory(storeName + ":/www", "avm-web-apps"); + avmService.createDirectory(storeName + ":/www/avm-web-apps", "ROOT"); + AVMNodeDescriptor desc = avmService.lookup(-1, storeName + ":/www"); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + Map s1 = avmService.createSnapshot(storeName, null, null); + desc = avmService.lookup(-1, storeName + ":/www"); + permissionService.setPermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true); + Map s2 = avmService.createSnapshot(storeName, null, null); + desc = avmService.lookup(-1, storeName + ":/www"); + permissionService.setPermission(nodeRef, "manager", "ContentManager", true); + Map s3 = avmService.createSnapshot(storeName, null, null); + desc = avmService.lookup(-1, storeName + ":/www"); + permissionService.setPermission(nodeRef, "publisher", "ContentPublisher", true); + Map s4 = avmService.createSnapshot(storeName, null, null); + desc = avmService.lookup(-1, storeName + ":/www"); + permissionService.setPermission(nodeRef, "contributor", "ContentContributor", true); + Map s5 = avmService.createSnapshot(storeName, null, null); + desc = avmService.lookup(-1, storeName + ":/www"); + permissionService.setPermission(nodeRef, "reviewer", "ContentReviewer", true); + Map s6 = avmService.createSnapshot(storeName, null, null); + desc = avmService.lookup(-1, storeName + ":/www"); + + avmService.copy(-1, storeName + ":/www", storeName + ":/", "head"); + desc = avmService.lookup(-1, storeName + ":/head"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + desc = avmService.lookup(-1, storeName + ":/head/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + + avmService.copy(s1.get(storeName), storeName + ":/www", storeName + ":/", "s1"); + desc = avmService.lookup(-1, storeName + ":/s1"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 0); + desc = avmService.lookup(-1, storeName + ":/s1/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 0); + + avmService.copy(s2.get(storeName), storeName + ":/www", storeName + ":/", "s2"); + desc = avmService.lookup(-1, storeName + ":/s2"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + desc = avmService.lookup(-1, storeName + ":/s2/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.copy(s3.get(storeName), storeName + ":/www", storeName + ":/", "s3"); + desc = avmService.lookup(-1, storeName + ":/s3"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/s3/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + + avmService.copy(s4.get(storeName), storeName + ":/www", storeName + ":/", "s4"); + desc = avmService.lookup(-1, storeName + ":/s4"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/s4/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + + avmService.copy(s5.get(storeName), storeName + ":/www", storeName + ":/", "s5"); + desc = avmService.lookup(-1, storeName + ":/s5"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + desc = avmService.lookup(-1, storeName + ":/s5/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + + avmService.copy(s6.get(storeName), storeName + ":/www", storeName + ":/", "s6"); + desc = avmService.lookup(-1, storeName + ":/s6"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + desc = avmService.lookup(-1, storeName + ":/s6/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "monkey", "ContentReviewer", true); + + avmService.copy(s6.get(storeName), storeName + ":/www", storeName + ":/", "s6"); + desc = avmService.lookup(-1, storeName + ":/s6"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + desc = avmService.lookup(-1, storeName + ":/s6/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "monkey", "ContentReviewer", true); + + avmService.copy(s6.get(storeName), storeName + ":/www", storeName + ":/", "s6"); + desc = avmService.lookup(-1, storeName + ":/s6"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + desc = avmService.lookup(-1, storeName + ":/s6/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + + } + finally + { + avmService.purgeStore(storeName); + } + } + + public void testBranches() + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + avmService.createStore(storeName); + avmService.createDirectory(storeName + ":/", "www"); + avmService.createDirectory(storeName + ":/www", "avm-web-apps"); + avmService.createDirectory(storeName + ":/www/avm-web-apps", "ROOT"); + AVMNodeDescriptor desc = avmService.lookup(-1, storeName + ":/www"); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + Map s1 = avmService.createSnapshot(storeName, null, null); + desc = avmService.lookup(-1, storeName + ":/www"); + permissionService.setPermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true); + Map s2 = avmService.createSnapshot(storeName, null, null); + desc = avmService.lookup(-1, storeName + ":/www"); + permissionService.setPermission(nodeRef, "manager", "ContentManager", true); + Map s3 = avmService.createSnapshot(storeName, null, null); + desc = avmService.lookup(-1, storeName + ":/www"); + permissionService.setPermission(nodeRef, "publisher", "ContentPublisher", true); + Map s4 = avmService.createSnapshot(storeName, null, null); + desc = avmService.lookup(-1, storeName + ":/www"); + permissionService.setPermission(nodeRef, "contributor", "ContentContributor", true); + Map s5 = avmService.createSnapshot(storeName, null, null); + desc = avmService.lookup(-1, storeName + ":/www"); + permissionService.setPermission(nodeRef, "reviewer", "ContentReviewer", true); + Map s6 = avmService.createSnapshot(storeName, null, null); + desc = avmService.lookup(-1, storeName + ":/www"); + + avmService.createBranch(-1, storeName + ":/www", storeName + ":/", "head"); + desc = avmService.lookup(-1, storeName + ":/head"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + desc = avmService.lookup(-1, storeName + ":/head/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + + avmService.createBranch(s1.get(storeName), storeName + ":/www", storeName + ":/", "s1"); + desc = avmService.lookup(-1, storeName + ":/s1"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 0); + desc = avmService.lookup(-1, storeName + ":/s1/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 0); + + avmService.createBranch(s2.get(storeName), storeName + ":/www", storeName + ":/", "s2"); + desc = avmService.lookup(-1, storeName + ":/s2"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + desc = avmService.lookup(-1, storeName + ":/s2/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createBranch(s3.get(storeName), storeName + ":/www", storeName + ":/", "s3"); + desc = avmService.lookup(-1, storeName + ":/s3"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/s3/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + + avmService.createBranch(s4.get(storeName), storeName + ":/www", storeName + ":/", "s4"); + desc = avmService.lookup(-1, storeName + ":/s4"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/s4/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + + avmService.createBranch(s5.get(storeName), storeName + ":/www", storeName + ":/", "s5"); + desc = avmService.lookup(-1, storeName + ":/s5"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + desc = avmService.lookup(-1, storeName + ":/s5/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + + avmService.createBranch(s6.get(storeName), storeName + ":/www", storeName + ":/", "s6"); + desc = avmService.lookup(-1, storeName + ":/s6"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + desc = avmService.lookup(-1, storeName + ":/s6/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "monkey", "ContentReviewer", true); + + avmService.createBranch(s6.get(storeName), storeName + ":/www", storeName + ":/", "s6"); + desc = avmService.lookup(-1, storeName + ":/s6"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + desc = avmService.lookup(-1, storeName + ":/s6/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "monkey", "ContentReviewer", true); + + avmService.createBranch(s6.get(storeName), storeName + ":/www", storeName + ":/", "s6"); + desc = avmService.lookup(-1, storeName + ":/s6"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + desc = avmService.lookup(-1, storeName + ":/s6/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + + } + finally + { + avmService.purgeStore(storeName); + } + } + + /* + * Test the basic permission model where + */ + public void testSimpleExternalLayer() throws Exception + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + avmService.createStore(storeName); + avmService.createDirectory(storeName + ":/", "www"); + avmService.createDirectory(storeName + ":/www", "avm-web-apps"); + avmService.createDirectory(storeName + ":/www/avm-web-apps", "ROOT"); + AVMNodeDescriptor desc = avmService.lookup(-1, storeName + ":/www"); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + Long definingId = avmACLDAO.getAccessControlList(nodeRef).getId(); + String definingGuid = aclDaoComponent.getAccessControlListProperties(definingId).getAclId(); + + permissionService.setPermission(nodeRef, "manager", "ContentManager", true); + permissionService.setPermission(nodeRef, "publisher", "ContentPublisher", true); + permissionService.setPermission(nodeRef, "contributor", "ContentContributor", true); + permissionService.setPermission(nodeRef, "reviewer", "ContentReviewer", true); + + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(definingId, avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + avmService.createDirectory(storeName + ":/www/avm-web-apps/ROOT", "directory"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/directory"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + avmService.createFile(storeName + ":/www/avm-web-apps/ROOT", "file"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/file"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + // simple layer + + avmService.createSnapshot(storeName, null, null); + avmService.createStore(storeName + "-a-"); + avmService.createLayeredDirectory(storeName + ":/www", storeName + "-a-:/", "www"); + avmService.createSnapshot(storeName, null, null); + avmService.createSnapshot(storeName + "-a-", null, null); + + desc = avmService.lookup(-1, storeName + "-a-:/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps/ROOT/directory"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps/ROOT/file"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + // Add permissions beneath and check they appear up + // Check version has not moved and the id is the same as they are in the same TX and will not have COWed + + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + + // debugPermissionsut.println("BEFORE:"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/file"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/directory"); + // debugPermissions(storeName + "-a-:/"); + // debugPermissions(storeName + "-a-:/www"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps/ROOT/file"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps/ROOT/directory"); + + testTX.commit(); + testTX = transactionService.getUserTransaction(); + testTX.begin(); + + permissionService.setPermission(nodeRef, "andy", "ContentReviewer", true); + + // System.out.println("AFTER:"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/file"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/directory"); + // debugPermissions(storeName + "-a-:/"); + // debugPermissions(storeName + "-a-:/www"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps/ROOT/file"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps/ROOT/directory"); + + Long newId = avmACLDAO.getAccessControlList(nodeRef).getId(); + assertFalse(newId.equals(definingId)); + assertEquals(definingGuid, aclDaoComponent.getAccessControlListProperties(newId).getAclId()); + assertEquals(aclDaoComponent.getAccessControlListProperties(definingId).getAclVersion().longValue() + 1, aclDaoComponent.getAccessControlListProperties(newId) + .getAclVersion().longValue()); + + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(newId, avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/directory"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/file"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + "-a-:/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps/ROOT/directory"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps/ROOT/file"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + // Add permissions to the layer + + desc = avmService.lookup(-1, storeName + "-a-:/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "bob", "ContentReviewer", true); + + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(newId, avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/directory"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/file"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + "-a-:/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 7); + newId = avmACLDAO.getAccessControlList(nodeRef).getId(); + + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 7); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 7); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps/ROOT/directory"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 7); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps/ROOT/file"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 7); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + } + finally + { + avmService.purgeStore(storeName); + } + } + + public void testSimpleInternalLayer() + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + avmService.createStore(storeName); + avmService.createDirectory(storeName + ":/", "www"); + avmService.createDirectory(storeName + ":/www", "avm-web-apps"); + avmService.createDirectory(storeName + ":/www/avm-web-apps", "ROOT"); + AVMNodeDescriptor desc = avmService.lookup(-1, storeName + ":/www"); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + Long definingId = avmACLDAO.getAccessControlList(nodeRef).getId(); + String definingGuid = aclDaoComponent.getAccessControlListProperties(definingId).getAclId(); + + permissionService.setPermission(nodeRef, "manager", "ContentManager", true); + permissionService.setPermission(nodeRef, "publisher", "ContentPublisher", true); + permissionService.setPermission(nodeRef, "contributor", "ContentContributor", true); + permissionService.setPermission(nodeRef, "reviewer", "ContentReviewer", true); + + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(definingId, avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + avmService.createDirectory(storeName + ":/www/avm-web-apps/ROOT", "directory"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/directory"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + avmService.createFile(storeName + ":/www/avm-web-apps/ROOT", "file"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/file"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + // simple layer + + avmService.createSnapshot(storeName, null, null); + + avmService.createLayeredDirectory(storeName + ":/www", storeName + ":/", "layer"); + avmService.createSnapshot(storeName, null, null); + avmService.createSnapshot(storeName, null, null); + + desc = avmService.lookup(-1, storeName + ":/layer"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT/directory"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT/file"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + assertEquals(aclDaoComponent.getInheritedAccessControlList(definingId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + // Add permissions beneath and check they appear up + // Check version has not moved and the id is the same as they are in the same TX and will not have COWed + + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + + // System.out.println("BEFORE:"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/file"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/directory"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/layer"); + // debugPermissions(storeName + ":/layer/avm-web-apps"); + // debugPermissions(storeName + ":/layer/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/layer/avm-web-apps/ROOT/file"); + // debugPermissions(storeName + ":/layer/avm-web-apps/ROOT/directory"); + + permissionService.setPermission(nodeRef, "andy", "ContentReviewer", true); + + // System.out.println("AFTER:"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/file"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/directory"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/layer"); + // debugPermissions(storeName + ":/layer/avm-web-apps"); + // debugPermissions(storeName + ":/layer/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/layer/avm-web-apps/ROOT/file"); + // debugPermissions(storeName + ":/layer/avm-web-apps/ROOT/directory"); + + Long newId = avmACLDAO.getAccessControlList(nodeRef).getId(); + assertFalse(newId.equals(definingId)); + assertEquals(definingGuid, aclDaoComponent.getAccessControlListProperties(newId).getAclId()); + assertEquals(aclDaoComponent.getAccessControlListProperties(definingId).getAclVersion().longValue() + 1, aclDaoComponent.getAccessControlListProperties(newId) + .getAclVersion().longValue()); + + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(newId, avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/directory"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/file"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/layer"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT/directory"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT/file"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + // Add permissions to the layer + + desc = avmService.lookup(-1, storeName + ":/layer"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "bob", "ContentReviewer", true); + + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(newId, avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/directory"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/file"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 6); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/layer"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 7); + newId = avmACLDAO.getAccessControlList(nodeRef).getId(); + + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 7); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 7); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT/directory"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 7); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + desc = avmService.lookup(-1, storeName + ":/layer/avm-web-apps/ROOT/file"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 7); + assertEquals(aclDaoComponent.getInheritedAccessControlList(newId), avmACLDAO.getAccessControlList(nodeRef).getId()); + + } + finally + { + avmService.purgeStore(storeName); + } + } + + private void debugPermissions(String path) + { + AVMNodeDescriptor desc = avmService.lookup(-1, path); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + DbAccessControlList acl = avmACLDAO.getAccessControlList(nodeRef); + System.out.println(path); + System.out.println("\t => Ind=" + + desc.getIndirection() + "Deleted,=" + desc.isDeleted() + ",LD=" + desc.isLayeredDirectory() + ",LF=" + desc.isLayeredFile() + ",PD=" + desc.isPlainDirectory() + + ",PF=" + desc.isPlainFile() + ",Primary=" + desc.isPrimary()); + System.out.println("\t => " + acl); + } + + public void testMutationsWithSimpleLayers() + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + avmService.createStore(storeName); + avmService.createDirectory(storeName + ":/", "www"); + avmService.createDirectory(storeName + ":/www", "avm-web-apps"); + avmService.createDirectory(storeName + ":/www/avm-web-apps", "ROOT"); + + AVMNodeDescriptor desc = avmService.lookup(-1, storeName + ":/www"); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + + // debugPermissions(storeName + ":/"); + // /debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + permissionService.setPermission(nodeRef, PermissionService.ALL_AUTHORITIES, PermissionService.ALL_PERMISSIONS, true); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + permissionService.setPermission(nodeRef, "manager", "ContentManager", true); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + permissionService.setPermission(nodeRef, "publisher", "ContentPublisher", true); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + permissionService.setPermission(nodeRef, "contributor", "ContentContributor", true); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + permissionService.setPermission(nodeRef, "reviewer", "ContentReviewer", true); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + + avmService.createSnapshot(storeName, null, null); + + // System.out.println("Snapshot"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + + avmService.createStore(storeName + "-a-"); + avmService.createLayeredDirectory(storeName + ":/www", storeName + "-a-:/", "www"); + + // System.out.println("Layered"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + + avmService.createDirectory(storeName + ":/www/avm-web-apps/ROOT", "directory"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/directory"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + // System.out.println("New Dir"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/directory"); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + + avmService.createDirectory(storeName + "-a-:/www/avm-web-apps/ROOT", "directory2"); + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps/ROOT/directory2"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 5); + + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + // System.out.println("Before Andy"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/directory"); + permissionService.setPermission(nodeRef, "andy", "ContentReviewer", true); + // System.out.println("Before Lemur"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/directory"); + permissionService.setPermission(nodeRef, "lemur", "ContentReviewer", true); + // System.out.println("After"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + + desc = avmService.lookup(-1, storeName + "-a-:/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "bob", "ContentReviewer", true); + permissionService.setPermission(nodeRef, "jim", "ContentReviewer", true); + permissionService.setPermission(nodeRef, "dave", "ContentReviewer", true); + + avmService.createFile(storeName + ":/www/avm-web-apps/ROOT", "file"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/file"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + // TODO: Check this + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 7); + + avmService.createFile(storeName + "-a-:/www/avm-web-apps/ROOT", "file2"); + desc = avmService.lookup(-1, storeName + "-a-:/www/avm-web-apps/ROOT/file2"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 10); + + } + finally + { + avmService.purgeStore(storeName); + } + } + + public void testRenamePlainDirectory() + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + AVMNodeDescriptor desc; + NodeRef nodeRef; + + avmService.createStore(storeName); + + avmService.createDirectory(storeName + ":/", "www"); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "one", PermissionService.ALL_PERMISSIONS, true); + // System.out.println("After One"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createDirectory(storeName + ":/www", "avm-web-apps"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "two", PermissionService.ALL_PERMISSIONS, true); + // System.out.println("After Two"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createDirectory(storeName + ":/www/avm-web-apps", "ROOT"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "three", PermissionService.ALL_PERMISSIONS, true); + // System.out.println("After Three"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createDirectory(storeName + ":/www/avm-web-apps/ROOT", "test"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/test"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "four", PermissionService.ALL_PERMISSIONS, true); + // System.out.println("After Four"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/test"); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.rename(storeName + ":/www/avm-web-apps/ROOT", "test", storeName + ":/www/avm-web-apps/ROOT", "lemon"); + // System.out.println("After Rename to lemon"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/lemon"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/lemon"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.rename(storeName + ":/www/avm-web-apps/ROOT", "lemon", storeName + ":/www/avm-web-apps", "orange"); + // System.out.println("After move up and rename 1"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/orange"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/orange"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + + avmService.rename(storeName + ":/www/avm-web-apps", "orange", storeName + ":/www", "blue"); + // System.out.println("After move up and rename 2"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/blue"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/orange"); + desc = avmService.lookup(-1, storeName + ":/www/blue"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + + } + finally + { + avmService.purgeStore(storeName); + } + } + + public void testRenamePlainFile() + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + AVMNodeDescriptor desc; + NodeRef nodeRef; + + avmService.createStore(storeName); + + avmService.createDirectory(storeName + ":/", "www"); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "one", PermissionService.ALL_PERMISSIONS, true); + // System.out.println("After One"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createDirectory(storeName + ":/www", "avm-web-apps"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "two", PermissionService.ALL_PERMISSIONS, true); + // System.out.println("After Two"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createDirectory(storeName + ":/www/avm-web-apps", "ROOT"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "three", PermissionService.ALL_PERMISSIONS, true); + // System.out.println("After Three"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createFile(storeName + ":/www/avm-web-apps/ROOT", "test"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/test"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "four", PermissionService.ALL_PERMISSIONS, true); + // System.out.println("After Four"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/test"); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.rename(storeName + ":/www/avm-web-apps/ROOT", "test", storeName + ":/www/avm-web-apps/ROOT", "lemon"); + // System.out.println("After Rename to lemon"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/lemon"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/lemon"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.rename(storeName + ":/www/avm-web-apps/ROOT", "lemon", storeName + ":/www/avm-web-apps", "orange"); + // System.out.println("After move up and rename 1"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/orange"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/orange"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + + avmService.rename(storeName + ":/www/avm-web-apps", "orange", storeName + ":/www", "blue"); + // System.out.println("After move up and rename 2"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/blue"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/orange"); + desc = avmService.lookup(-1, storeName + ":/www/blue"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + } + finally + { + avmService.purgeStore(storeName); + } + } + + public void testRenamePlainDirectoryIntoLayer() + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + AVMNodeDescriptor desc; + NodeRef nodeRef; + + avmService.createStore(storeName); + + avmService.createDirectory(storeName + ":/", "www"); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "one", PermissionService.ALL_PERMISSIONS, true); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createDirectory(storeName + ":/www", "avm-web-apps"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "two", PermissionService.ALL_PERMISSIONS, true); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createDirectory(storeName + ":/www/avm-web-apps", "ROOT"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "three", PermissionService.ALL_PERMISSIONS, true); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createDirectory(storeName + ":/www/avm-web-apps/ROOT", "test"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/test"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "four", PermissionService.ALL_PERMISSIONS, true); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createSnapshot(storeName, null, null); + avmService.createStore(storeName + "-a-"); + avmService.createLayeredDirectory(storeName + ":/www", storeName + "-a-:/", "www"); + + avmService.rename(storeName + "-a-:/www/avm-web-apps/ROOT", "test", storeName + "-a-:/www/avm-web-apps/ROOT", "banana"); + // System.out.println("In Source"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/test"); + // System.out.println("In Layer"); + // debugPermissions(storeName + "-a-:/"); + // debugPermissions(storeName + "-a-:/www"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps/ROOT/banana"); + } + finally + { + avmService.purgeStore(storeName); + } + } + + public void testRenamePlainFileIntoLayer() + { + runAs("admin"); + String storeName = "PermissionsTest-" + getName() + "-" + (new Date().getTime()); + try + { + AVMNodeDescriptor desc; + NodeRef nodeRef; + + avmService.createStore(storeName); + + avmService.createDirectory(storeName + ":/", "www"); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "one", PermissionService.ALL_PERMISSIONS, true); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createDirectory(storeName + ":/www", "avm-web-apps"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "two", PermissionService.ALL_PERMISSIONS, true); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createDirectory(storeName + ":/www/avm-web-apps", "ROOT"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "three", PermissionService.ALL_PERMISSIONS, true); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createFile(storeName + ":/www/avm-web-apps/ROOT", "test"); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT/test"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + permissionService.setPermission(nodeRef, "four", PermissionService.ALL_PERMISSIONS, true); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 4); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps/ROOT"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 3); + desc = avmService.lookup(-1, storeName + ":/www/avm-web-apps"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 2); + desc = avmService.lookup(-1, storeName + ":/www"); + nodeRef = AVMNodeConverter.ToNodeRef(-1, desc.getPath()); + assertEquals(permissionService.getSetPermissions(nodeRef).getPermissionEntries().size(), 1); + + avmService.createSnapshot(storeName, null, null); + avmService.createStore(storeName + "-a-"); + avmService.createLayeredDirectory(storeName + ":/www", storeName + "-a-:/", "www"); + + avmService.rename(storeName + "-a-:/www/avm-web-apps/ROOT", "test", storeName + "-a-:/www/avm-web-apps/ROOT", "banana"); + // System.out.println("File In Source"); + // debugPermissions(storeName + ":/"); + // debugPermissions(storeName + ":/www"); + // debugPermissions(storeName + ":/www/avm-web-apps"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + ":/www/avm-web-apps/ROOT/test"); + // System.out.println("File In Layer"); + // debugPermissions(storeName + "-a-:/"); + // debugPermissions(storeName + "-a-:/www"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps/ROOT"); + // debugPermissions(storeName + "-a-:/www/avm-web-apps/ROOT/banana"); + } + finally + { + avmService.purgeStore(storeName); + } + } +} diff --git a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java index 6e201914c4..ae17679e40 100644 --- a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java @@ -42,6 +42,7 @@ 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.permissions.ACLCopyMode; import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.service.cmr.avm.AVMBadArgumentException; import org.alfresco.service.cmr.avm.AVMException; @@ -349,7 +350,7 @@ public class AVMStoreImpl implements AVMStore, Serializable // a LayeredDirectoryNode that gets its indirection from // its parent. { - newDir = new LayeredDirectoryNodeImpl((String)null, this, null); + newDir = new LayeredDirectoryNodeImpl((String)null, this, null, null, ACLCopyMode.INHERIT); ((LayeredDirectoryNodeImpl)newDir).setPrimaryIndirection(false); ((LayeredDirectoryNodeImpl)newDir).setLayerID(lPath.getTopLayer().getLayerID()); } @@ -373,7 +374,7 @@ public class AVMStoreImpl implements AVMStore, Serializable newDir.getProperties().putAll(properties); } DbAccessControlList acl = dir.getAcl(); - newDir.setAcl(acl != null ? acl.getCopy() : null); + newDir.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null); } /** @@ -397,8 +398,9 @@ public class AVMStoreImpl implements AVMStore, Serializable { throw new AVMExistsException("Child exists: " + name); } + Long parentAcl = dir.getAcl() == null ? null : dir.getAcl().getId(); LayeredDirectoryNode newDir = - new LayeredDirectoryNodeImpl(srcPath, this, null); + new LayeredDirectoryNodeImpl(srcPath, this, null, parentAcl, ACLCopyMode.INHERIT); if (lPath.isLayered()) { // When a layered directory is made inside of a layered context, @@ -458,7 +460,7 @@ public class AVMStoreImpl implements AVMStore, Serializable -1, "UTF-8")); DbAccessControlList acl = dir.getAcl(); - file.setAcl(acl != null ? acl.getCopy() : null); + file.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null); ContentWriter writer = createContentWriter(AVMNodeConverter.ExtendAVMPath(path, name)); return writer.getContentOutputStream(); } @@ -508,7 +510,7 @@ public class AVMStoreImpl implements AVMStore, Serializable file.getProperties().putAll(properties); } DbAccessControlList acl = dir.getAcl(); - file.setAcl(acl != null ? acl.getCopy() : null); + file.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null); // Yet another flush. AVMDAOs.Instance().fAVMNodeDAO.flush(); ContentWriter writer = createContentWriter(AVMNodeConverter.ExtendAVMPath(path, name)); @@ -541,7 +543,7 @@ public class AVMStoreImpl implements AVMStore, Serializable } // TODO Reexamine decision to not check validity of srcPath. LayeredFileNodeImpl newFile = - new LayeredFileNodeImpl(srcPath, this); + new LayeredFileNodeImpl(srcPath, this, null); if (child != null) { newFile.setAncestor(child); @@ -549,7 +551,7 @@ public class AVMStoreImpl implements AVMStore, Serializable dir.updateModTime(); dir.putChild(name, newFile); DbAccessControlList acl = dir.getAcl(); - newFile.setAcl(acl != null ? acl.getCopy() : null); + newFile.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null); // newFile.setVersionID(getNextVersionID()); } @@ -1431,7 +1433,7 @@ public class AVMStoreImpl implements AVMStore, Serializable { throw new AccessDeniedException("Not allowed to write properties: " + path); } - node.copyMetaDataFrom(from); + node.copyMetaDataFrom(from, node.getAcl() == null ? null : node.getAcl().getInheritsFrom()); node.setGuid(GUID.generate()); } @@ -1565,7 +1567,7 @@ public class AVMStoreImpl implements AVMStore, Serializable } if (!fAVMRepository.can(lPath.getCurrentNode(), PermissionService.READ_PERMISSIONS)) { - throw new AccessDeniedException("Not allowed to read permissions: " + path); + throw new AccessDeniedException("Not allowed to read permissions: " + path + " in "+getName()); } return lPath.getCurrentNode().getAcl(); } diff --git a/source/java/org/alfresco/repo/avm/DeletedNodeImpl.java b/source/java/org/alfresco/repo/avm/DeletedNodeImpl.java index 6bdf04600c..0209f01eeb 100644 --- a/source/java/org/alfresco/repo/avm/DeletedNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/DeletedNodeImpl.java @@ -1,216 +1,225 @@ -/* - * 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.avm; - -import org.alfresco.service.cmr.avm.AVMNodeDescriptor; - -/** - * Place holder for a deleted node. - * @author britt - */ -public class DeletedNodeImpl extends AVMNodeImpl implements DeletedNode -{ - private static final long serialVersionUID = 7283526790174482993L; - - /** - * The type of node that this is a deleted node for. - */ - private int fDeletedType; - - /** - * For Hibernate's use. - */ - protected DeletedNodeImpl() - { - } - - /** - * Create a new one from scratch. - * @param id The node id. - * @param store The store it's being created in. - */ - public DeletedNodeImpl(long id, - AVMStore store) - { - super(id, store); - } - - public DeletedNodeImpl(DeletedNode other, - AVMStore store) - { - super(store.getAVMRepository().issueID(), store); - AVMDAOs.Instance().fAVMNodeDAO.save(this); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - copyProperties(other); - copyAspects(other); - copyACLs(other); - } - - /** - * Setter. - */ - public void setDeletedType(int type) - { - fDeletedType = type; - } - - /** - * Getter. - */ - public int getDeletedType() - { - return fDeletedType; - } - - // TODO What happens when this is called? Does it muck anything up. - /** - * This is only called rarely. - */ - public AVMNode copy(Lookup lPath) - { - AVMNode newMe = new DeletedNodeImpl(this, lPath.getAVMStore()); - newMe.setAncestor(this); - return newMe; - } - - /** - * Get a descriptor. - * @param lPath The Lookup to this node's parent. - * @param name The name of this node. - * @return An AVMNodeDescriptor - */ - public AVMNodeDescriptor getDescriptor(Lookup lPath, String name) - { - BasicAttributes attrs = getBasicAttributes(); - String path = lPath.getRepresentedPath(); - if (path.endsWith("/")) - { - path = path + name; - } - else - { - path = path + "/" + name; - } - return new AVMNodeDescriptor(path, - name, - AVMNodeType.DELETED_NODE, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - null, - -1, - false, - -1, - false, - -1, - fDeletedType); - } - - /** - * Get a descriptor. - * @param lPath The full Lookup to this. - * @return An AVMNodeDescriptor. - */ - public AVMNodeDescriptor getDescriptor(Lookup lPath) - { - BasicAttributes attrs = getBasicAttributes(); - String path = lPath.getRepresentedPath(); - return new AVMNodeDescriptor(path, - path.substring(path.lastIndexOf("/") + 1), - AVMNodeType.DELETED_NODE, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - null, - -1, - false, - -1, - false, - -1, - fDeletedType); - } - - /** - * Get a descriptor. - * @param parentPath - * @param name - * @param parentIndirection Ignored. - * @return An AVMNodeDescriptor. - */ - public AVMNodeDescriptor getDescriptor(String parentPath, String name, String parentIndirection, int parentIndirectionVersion) - { - BasicAttributes attrs = getBasicAttributes(); - String path = parentPath.endsWith("/") ? parentPath + name : parentPath + "/" + name; - return new AVMNodeDescriptor(path, - name, - AVMNodeType.DELETED_NODE, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - null, - -1, - false, - -1, - false, - -1, - fDeletedType); - } - - /** - * Get the type of this node. - * @return The AVMNodeType of this. - */ - public int getType() - { - return AVMNodeType.DELETED_NODE; - } - - /** - * Get a descriptive string representation. - * @param lPath The lookup we've been found through. - * @return A String representation. - */ - public String toString(Lookup lPath) - { - return "[DN:" + getId() + "]"; - } -} +/* + * 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.avm; + +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.security.permissions.ACLCopyMode; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; + +/** + * Place holder for a deleted node. + * @author britt + */ +public class DeletedNodeImpl extends AVMNodeImpl implements DeletedNode +{ + private static final long serialVersionUID = 7283526790174482993L; + + /** + * The type of node that this is a deleted node for. + */ + private int fDeletedType; + + /** + * For Hibernate's use. + */ + protected DeletedNodeImpl() + { + } + + /** + * Create a new one from scratch. + * @param id The node id. + * @param store The store it's being created in. + */ + public DeletedNodeImpl(long id, + AVMStore store, DbAccessControlList acl) + { + super(id, store); + this.setAcl(acl); + } + + public DeletedNodeImpl(DeletedNode other, + AVMStore store, Long parentAcl, ACLCopyMode mode) + { + super(store.getAVMRepository().issueID(), store); + AVMDAOs.Instance().fAVMNodeDAO.save(this); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + copyProperties(other); + copyAspects(other); + copyACLs(other, parentAcl, mode); + } + + /** + * Setter. + */ + public void setDeletedType(int type) + { + fDeletedType = type; + } + + /** + * Getter. + */ + public int getDeletedType() + { + return fDeletedType; + } + + // TODO What happens when this is called? Does it muck anything up. + /** + * This is only called rarely. + */ + public AVMNode copy(Lookup lPath) + { + DirectoryNode dir = lPath.getCurrentNodeDirectory(); + Long parentAclId = null; + if((dir != null) && (dir.getAcl() != null)) + { + parentAclId = dir.getAcl().getId(); + } + AVMNode newMe = new DeletedNodeImpl(this, lPath.getAVMStore(), parentAclId, ACLCopyMode.COPY); + newMe.setAncestor(this); + return newMe; + } + + /** + * Get a descriptor. + * @param lPath The Lookup to this node's parent. + * @param name The name of this node. + * @return An AVMNodeDescriptor + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath, String name) + { + BasicAttributes attrs = getBasicAttributes(); + String path = lPath.getRepresentedPath(); + if (path.endsWith("/")) + { + path = path + name; + } + else + { + path = path + "/" + name; + } + return new AVMNodeDescriptor(path, + name, + AVMNodeType.DELETED_NODE, + attrs.getCreator(), + attrs.getOwner(), + attrs.getLastModifier(), + attrs.getCreateDate(), + attrs.getModDate(), + attrs.getAccessDate(), + getId(), + getGuid(), + getVersionID(), + null, + -1, + false, + -1, + false, + -1, + fDeletedType); + } + + /** + * Get a descriptor. + * @param lPath The full Lookup to this. + * @return An AVMNodeDescriptor. + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath) + { + BasicAttributes attrs = getBasicAttributes(); + String path = lPath.getRepresentedPath(); + return new AVMNodeDescriptor(path, + path.substring(path.lastIndexOf("/") + 1), + AVMNodeType.DELETED_NODE, + attrs.getCreator(), + attrs.getOwner(), + attrs.getLastModifier(), + attrs.getCreateDate(), + attrs.getModDate(), + attrs.getAccessDate(), + getId(), + getGuid(), + getVersionID(), + null, + -1, + false, + -1, + false, + -1, + fDeletedType); + } + + /** + * Get a descriptor. + * @param parentPath + * @param name + * @param parentIndirection Ignored. + * @return An AVMNodeDescriptor. + */ + public AVMNodeDescriptor getDescriptor(String parentPath, String name, String parentIndirection, int parentIndirectionVersion) + { + BasicAttributes attrs = getBasicAttributes(); + String path = parentPath.endsWith("/") ? parentPath + name : parentPath + "/" + name; + return new AVMNodeDescriptor(path, + name, + AVMNodeType.DELETED_NODE, + attrs.getCreator(), + attrs.getOwner(), + attrs.getLastModifier(), + attrs.getCreateDate(), + attrs.getModDate(), + attrs.getAccessDate(), + getId(), + getGuid(), + getVersionID(), + null, + -1, + false, + -1, + false, + -1, + fDeletedType); + } + + /** + * Get the type of this node. + * @return The AVMNodeType of this. + */ + public int getType() + { + return AVMNodeType.DELETED_NODE; + } + + /** + * Get a descriptive string representation. + * @param lPath The lookup we've been found through. + * @return A String representation. + */ + public String toString(Lookup lPath) + { + return "[DN:" + getId() + "]"; + } +} diff --git a/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java index ae4c5dcd1a..573ca020bf 100644 --- a/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java @@ -1,79 +1,80 @@ -/* - * 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.avm; - -import org.alfresco.service.cmr.avm.AVMBadArgumentException; -import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.cmr.avm.AVMNotFoundException; - -/** - * Base class for Directories. - * @author britt - */ -abstract class DirectoryNodeImpl extends AVMNodeImpl implements DirectoryNode -{ - /** - * Default constructor. - */ - protected DirectoryNodeImpl() - { - } - - /** - * A pass through constructor. Called when a new concrete subclass - * instance is created. - * @param id - * @param repo - */ - protected DirectoryNodeImpl(long id, AVMStore repo) - { - super(id, repo); - } - - /** - * Dangerous version of link. - * @param name The name to give the child. - * @param toLink The child to link in. - */ - public void link(String name, AVMNodeDescriptor toLink) - { - AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(toLink.getId()); - if (node == null) - { - throw new AVMNotFoundException("Child node not found."); - } - if (node.getType() == AVMNodeType.LAYERED_DIRECTORY && - !((LayeredDirectoryNode)node).getPrimaryIndirection()) - { - throw new AVMBadArgumentException("Non primary layered directories cannot be linked."); - } - // Make the new ChildEntry and save. - ChildKey key = new ChildKey(this, name); - ChildEntry newChild = new ChildEntryImpl(key, node); - AVMDAOs.Instance().fChildEntryDAO.save(newChild); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - AVMDAOs.Instance().fChildEntryDAO.evict(newChild); - AVMDAOs.Instance().fAVMNodeDAO.evict(node); - } -} +/* + * 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.avm; + +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.service.cmr.avm.AVMBadArgumentException; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.cmr.avm.AVMNotFoundException; + +/** + * Base class for Directories. + * @author britt + */ +abstract class DirectoryNodeImpl extends AVMNodeImpl implements DirectoryNode +{ + /** + * Default constructor. + */ + protected DirectoryNodeImpl() + { + } + + /** + * A pass through constructor. Called when a new concrete subclass + * instance is created. + * @param id + * @param repo + */ + protected DirectoryNodeImpl(long id, AVMStore repo) + { + super(id, repo); + } + + /** + * Dangerous version of link. + * @param name The name to give the child. + * @param toLink The child to link in. + */ + public void link(String name, AVMNodeDescriptor toLink) + { + AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(toLink.getId()); + if (node == null) + { + throw new AVMNotFoundException("Child node not found."); + } + if (node.getType() == AVMNodeType.LAYERED_DIRECTORY && + !((LayeredDirectoryNode)node).getPrimaryIndirection()) + { + throw new AVMBadArgumentException("Non primary layered directories cannot be linked."); + } + // Make the new ChildEntry and save. + ChildKey key = new ChildKey(this, name); + ChildEntry newChild = new ChildEntryImpl(key, node); + AVMDAOs.Instance().fChildEntryDAO.save(newChild); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + AVMDAOs.Instance().fChildEntryDAO.evict(newChild); + AVMDAOs.Instance().fAVMNodeDAO.evict(node); + } +} diff --git a/source/java/org/alfresco/repo/avm/FileNodeImpl.java b/source/java/org/alfresco/repo/avm/FileNodeImpl.java index 2121758dd5..af6e12ff25 100644 --- a/source/java/org/alfresco/repo/avm/FileNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/FileNodeImpl.java @@ -1,48 +1,50 @@ -/* - * 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.avm; - -/** - * Base class for file objects. - * @author britt - */ -abstract class FileNodeImpl extends AVMNodeImpl implements FileNode -{ - /** - * Default constructor. - */ - protected FileNodeImpl() - { - } - - /** - * Pass through constructor. - * @param id The newly assigned object id. - * @param store The AVMStore we belong to. - */ - public FileNodeImpl(long id, AVMStore store) - { - super(id, store); - } -} +/* + * 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.avm; + +import org.alfresco.repo.domain.DbAccessControlList; + +/** + * Base class for file objects. + * @author britt + */ +abstract class FileNodeImpl extends AVMNodeImpl implements FileNode +{ + /** + * Default constructor. + */ + protected FileNodeImpl() + { + } + + /** + * Pass through constructor. + * @param id The newly assigned object id. + * @param store The AVMStore we belong to. + */ + public FileNodeImpl(long id, AVMStore store) + { + super(id, store); + } +} diff --git a/source/java/org/alfresco/repo/avm/LayeredDirectoryNode.java b/source/java/org/alfresco/repo/avm/LayeredDirectoryNode.java index e193e37486..9ea2d43939 100644 --- a/source/java/org/alfresco/repo/avm/LayeredDirectoryNode.java +++ b/source/java/org/alfresco/repo/avm/LayeredDirectoryNode.java @@ -1,92 +1,92 @@ -package org.alfresco.repo.avm; - -/** - * Interface for Layered Directories. - * @author britt - */ -public interface LayeredDirectoryNode extends DirectoryNode, Layered -{ - /** - * Does this node have a primary indirection. - * @return Whether this is a primary indirection. - */ - public boolean getPrimaryIndirection(); - - /** - * Set whether this has a primary indirection. - * @param has Whether this has a primary indirection. - */ - public void setPrimaryIndirection(boolean has); - - /** - * Get the layer id for this node. - * @return The layer id. - */ - public long getLayerID(); - - /** - * Set the layer id for this node. - * @param id The id to set. - */ - public void setLayerID(long id); - - /** - * Set this to be a primary indirection from the path - * passed in. - * @param path The indirection path. - */ - public void rawSetPrimary(String path); - - /** - * Turn this node into a primary indirection node with the indirection - * taken from the Lookup passed in. - * Performs a copy on write. - * @param lPath - */ - public void turnPrimary(Lookup lPath); - - /** - * Retarget this directory. - * @param lPath The Lookup. - * @param target The new target path. - */ - public void retarget(Lookup lPath, String target); - - /** - * Make visible a node deleted in a layer. - * @param lPath The Lookup. - * @param name The name to make visible. - */ - public void uncover(Lookup lPath, String name); - - /** - * Remove name without leaving behind a deleted node. - * @param name The name of the child to flatten. - */ - public void flatten(String name); - - /** - * Set the indirection. - * @param indirection - */ - public void setIndirection(String indirection); - - /** - * Get the indirection version. - * @return The indirection version. - */ - public Integer getIndirectionVersion(); - - /** - * Set the opacity of this. - * @param opacity Whether this should be opaque, i.e. not see the things it - * in its indirection. - */ - public void setOpacity(boolean opacity); - - /** - * Get the opacity of this. - * @return The opacity. - */ - public boolean getOpacity(); +package org.alfresco.repo.avm; + +/** + * Interface for Layered Directories. + * @author britt + */ +public interface LayeredDirectoryNode extends DirectoryNode, Layered +{ + /** + * Does this node have a primary indirection. + * @return Whether this is a primary indirection. + */ + public boolean getPrimaryIndirection(); + + /** + * Set whether this has a primary indirection. + * @param has Whether this has a primary indirection. + */ + public void setPrimaryIndirection(boolean has); + + /** + * Get the layer id for this node. + * @return The layer id. + */ + public long getLayerID(); + + /** + * Set the layer id for this node. + * @param id The id to set. + */ + public void setLayerID(long id); + + /** + * Set this to be a primary indirection from the path + * passed in. + * @param path The indirection path. + */ + public void rawSetPrimary(Lookup lPath, String path); + + /** + * Turn this node into a primary indirection node with the indirection + * taken from the Lookup passed in. + * Performs a copy on write. + * @param lPath + */ + public void turnPrimary(Lookup lPath); + + /** + * Retarget this directory. + * @param lPath The Lookup. + * @param target The new target path. + */ + public void retarget(Lookup lPath, String target); + + /** + * Make visible a node deleted in a layer. + * @param lPath The Lookup. + * @param name The name to make visible. + */ + public void uncover(Lookup lPath, String name); + + /** + * Remove name without leaving behind a deleted node. + * @param name The name of the child to flatten. + */ + public void flatten(String name); + + /** + * Set the indirection. + * @param indirection + */ + public void setIndirection(String indirection); + + /** + * Get the indirection version. + * @return The indirection version. + */ + public Integer getIndirectionVersion(); + + /** + * Set the opacity of this. + * @param opacity Whether this should be opaque, i.e. not see the things it + * in its indirection. + */ + public void setOpacity(boolean opacity); + + /** + * Get the opacity of this. + * @return The opacity. + */ + public boolean getOpacity(); } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java index 9cdb7d2305..109351ce08 100644 --- a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java @@ -1,1038 +1,1205 @@ -/* - * 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.avm; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.SortedMap; -import java.util.TreeMap; - -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.security.PermissionService; -import org.alfresco.util.Pair; - -/** - * A layered directory node. A layered directory node points at - * an underlying directory, which may or may not exist. The visible - * contents of a layered directory node is the contents of the underlying node - * pointed at plus those nodes added to or modified in the layered directory node minus - * those nodes which have been deleted in the layered directory node. - * @author britt - */ -class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirectoryNode -{ - static final long serialVersionUID = 4623043057918181724L; - - /** - * The layer id. - */ - private long fLayerID; - - /** - * The pointer to the underlying directory. - */ - private String fIndirection; - - /** - * Whether this is a primary indirection node. - */ - private boolean fPrimaryIndirection; - - /** - * Whether this is opaque. - */ - private boolean fOpacity; - - /** - * The indirection version. - */ - private int fIndirectionVersion; - - /** - * Default constructor. Called by Hibernate. - */ - protected LayeredDirectoryNodeImpl() - { - } - - /** - * Make a new one from a specified indirection path. - * @param indirection The indirection path to set. - * @param store The store that owns this node. - */ - public LayeredDirectoryNodeImpl(String indirection, AVMStore store, AVMNode toCopy) - { - super(store.getAVMRepository().issueID(), store); - fLayerID = -1; - fIndirection = indirection; - fIndirectionVersion = -1; - fPrimaryIndirection = true; - fOpacity = false; - if (toCopy != null) - { - setVersionID(toCopy.getVersionID() + 1); - } - else - { - setVersionID(1); - } - AVMDAOs.Instance().fAVMNodeDAO.save(this); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - if (toCopy != null) - { - copyProperties(toCopy); - copyACLs(toCopy); - copyAspects(toCopy); - } - } - - /** - * Kind of copy constructor, sort of. - * @param other The LayeredDirectoryNode we are copied from. - * @param repos The AVMStore object we use. - */ - @SuppressWarnings("unchecked") - public LayeredDirectoryNodeImpl(LayeredDirectoryNode other, - AVMStore repos, - Lookup lookup, boolean copyAll) - { - super(repos.getAVMRepository().issueID(), repos); - fIndirection = other.getIndirection(); - fPrimaryIndirection = other.getPrimaryIndirection(); - fIndirectionVersion = -1; - fLayerID = -1; - fOpacity = false; - AVMDAOs.Instance().fAVMNodeDAO.save(this); - Map children = null; - if (copyAll) - { - children = other.getListing(lookup, true); - } - else - { - children = other.getListingDirect(lookup, true); - } - for (Map.Entry child : children.entrySet()) - { - ChildKey key = new ChildKey(this, child.getKey()); - ChildEntry entry = new ChildEntryImpl(key, child.getValue()); - AVMDAOs.Instance().fChildEntryDAO.save(entry); - } - setVersionID(other.getVersionID() + 1); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - copyProperties(other); - copyAspects(other); - copyACLs(other); - } - - /** - * Construct one from a PlainDirectoryNode. Called when a COW is performed in a layered - * context. - * @param other The PlainDirectoryNode. - * @param store The AVMStore we should belong to. - * @param lPath The Lookup object. - */ - @SuppressWarnings("unchecked") - public LayeredDirectoryNodeImpl(PlainDirectoryNode other, - AVMStore store, - Lookup lPath, - boolean copyContents) - { - super(store.getAVMRepository().issueID(), store); - fIndirection = null; - fPrimaryIndirection = false; - fIndirectionVersion = -1; - fLayerID = -1; - fOpacity = false; - AVMDAOs.Instance().fAVMNodeDAO.save(this); - if (copyContents) - { - for (ChildEntry child : AVMDAOs.Instance().fChildEntryDAO.getByParent(other)) - { - ChildKey key = new ChildKey(this, child.getKey().getName()); - ChildEntryImpl newChild = new ChildEntryImpl(key, - child.getChild()); - AVMDAOs.Instance().fChildEntryDAO.save(newChild); - } - } - setVersionID(other.getVersionID() + 1); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - copyProperties(other); - copyAspects(other); - copyACLs(other); - } - - /** - * Create a new layered directory based on a directory we are being named from - * that is in not in the layer of the source lookup. - * @param dir The directory - * @param store The store - * @param srcLookup The source lookup. - * @param name The name of the target. - */ - public LayeredDirectoryNodeImpl(DirectoryNode dir, - AVMStore store, - Lookup srcLookup, - String name) - { - super(store.getAVMRepository().issueID(), store); - fIndirection = srcLookup.getIndirectionPath() + "/" + name; - fPrimaryIndirection = true; - fIndirectionVersion = -1; - fLayerID = -1; - fOpacity = false; - setVersionID(dir.getVersionID() + 1); - AVMDAOs.Instance().fAVMNodeDAO.save(this); - Map children = dir.getListing(srcLookup, true); - for (Map.Entry child : children.entrySet()) - { - ChildKey key = new ChildKey(this, child.getKey()); - ChildEntry entry = new ChildEntryImpl(key, child.getValue()); - AVMDAOs.Instance().fChildEntryDAO.save(entry); - } - AVMDAOs.Instance().fAVMNodeDAO.flush(); - copyProperties(dir); - copyAspects(dir); - copyACLs(dir); - } - - /** - * Is this a primary indirection node. - * @return Whether this is a primary indirection. - */ - public boolean getPrimaryIndirection() - { - return fPrimaryIndirection; - } - - /** - * Set the primary indirection state of this. - * @param has Whether this is a primary indirection node. - */ - public void setPrimaryIndirection(boolean has) - { - fPrimaryIndirection = has; - } - - /** - * Get the indirection path. - * @return The indirection path. - */ - public String getIndirection() - { - return fIndirection; - } - - /** - * Get the underlying path in the Lookup's context. - * @param lPath The Lookup. - * @return The underlying path. - */ - public String getUnderlying(Lookup lPath) - { - if (fPrimaryIndirection) - { - return fIndirection; - } - return lPath.getCurrentIndirection(); - } - - /** - * Get the underlying version in the lookup path context. - * @param lPath The Lookup. - * @return The effective underlying version. - */ - public int getUnderlyingVersion(Lookup lPath) - { - if (lPath.getVersion() == -1) - { - return -1; - } - if (fPrimaryIndirection) - { - return fIndirectionVersion; - } - return lPath.getCurrentIndirectionVersion(); - } - - /** - * Get the layer id. - * @return The layer id. - */ - public long getLayerID() - { - return fLayerID; - } - - /** - * Set the layer id. - * @param id The id to set. - */ - public void setLayerID(long id) - { - fLayerID = id; - } - - /** - * Copy on write logic. - * @param lPath - * @return The copy or null. - */ - public AVMNode copy(Lookup lPath) - { - // Capture the store. - AVMStore store = lPath.getAVMStore(); - LayeredDirectoryNodeImpl newMe = null; - if (!lPath.isInThisLayer()) - { - // This means that this is being seen indirectly through the topmost - // layer. The following creates a node that will inherit its - // indirection from its parent. - newMe = new LayeredDirectoryNodeImpl((String)null, - store, this); - newMe.setPrimaryIndirection(false); - newMe.setLayerID(lPath.getTopLayer().getLayerID()); - } - else - { - // A simple copy is made. - newMe = new LayeredDirectoryNodeImpl(this, - store, - lPath, - false); - newMe.setLayerID(getLayerID()); - } - newMe.setAncestor(this); - return newMe; - } - - /** - * Insert a child node without COW. - * @param name The name to give the child. - */ - public void putChild(String name, AVMNode node) - { - if (DEBUG) - { - checkReadOnly(); - } - ChildKey key = new ChildKey(this, name); - ChildEntry existing = AVMDAOs.Instance().fChildEntryDAO.get(key); - if (existing != null) - { - AVMDAOs.Instance().fChildEntryDAO.delete(existing); - } - ChildEntry entry = new ChildEntryImpl(key, node); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - AVMDAOs.Instance().fChildEntryDAO.save(entry); - } - - - /** - * 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.getByParentChild(this, node) != null; - } - - /** - * Get a listing of the virtual contents of this directory. - * @param lPath The Lookup. - * @return A Map from names to nodes. This is a sorted Map. - */ - @SuppressWarnings("unchecked") - public Map getListing(Lookup lPath, boolean includeDeleted) - { - // Get the base listing from the thing we indirect to. - Map listing = new HashMap(); - if (!fOpacity) - { - Lookup lookup = AVMRepository.GetInstance().lookupDirectory(getUnderlyingVersion(lPath), getUnderlying(lPath)); - if (lookup != null) - { - DirectoryNode dir = (DirectoryNode)lookup.getCurrentNode(); - Map underListing = dir.getListing(lookup, includeDeleted); - for (Map.Entry entry : underListing.entrySet()) - { - if (entry.getValue().getType() == AVMNodeType.LAYERED_DIRECTORY || - entry.getValue().getType() == AVMNodeType.PLAIN_DIRECTORY) - { - if (!AVMRepository.GetInstance().can(entry.getValue(), PermissionService.READ_CHILDREN)) - { - continue; - } - } - listing.put(entry.getKey(), entry.getValue()); - } - } - } - for (ChildEntry entry : AVMDAOs.Instance().fChildEntryDAO.getByParent(this)) - { - if (entry.getChild().getType() == AVMNodeType.LAYERED_DIRECTORY || - entry.getChild().getType() == AVMNodeType.PLAIN_DIRECTORY) - { - if (!AVMRepository.GetInstance().can(entry.getChild(), PermissionService.READ_CHILDREN)) - { - continue; - } - } - if (!includeDeleted && entry.getChild().getType() == AVMNodeType.DELETED_NODE) - { - listing.remove(entry.getKey().getName()); - } - else - { - listing.put(entry.getKey().getName(), entry.getChild()); - } - } - return listing; - } - - /** - * Get a listing of the nodes directly contained by a directory. - * @param lPath The Lookup to this directory. - * @return A Map of names to nodes. - */ - public Map getListingDirect(Lookup lPath, boolean includeDeleted) - { - Map listing = new HashMap(); - for (ChildEntry entry : AVMDAOs.Instance().fChildEntryDAO.getByParent(this)) - { - if (entry.getChild().getType() == AVMNodeType.LAYERED_DIRECTORY || - entry.getChild().getType() == AVMNodeType.PLAIN_DIRECTORY) - { - if (!AVMRepository.GetInstance().can(entry.getChild(), PermissionService.READ_CHILDREN)) - { - continue; - } - } - if (includeDeleted || entry.getChild().getType() != AVMNodeType.DELETED_NODE) - { - listing.put(entry.getKey().getName(), entry.getChild()); - } - } - return listing; - } - - /** - * Get the direct contents of this directory. - * @param dir The descriptor that describes us. - * @param includeDeleted Whether to inlude deleted nodes. - * @return A Map of Strings to descriptors. - */ - public SortedMap getListingDirect(AVMNodeDescriptor dir, - boolean includeDeleted) - { - List children = AVMDAOs.Instance().fChildEntryDAO.getByParent(this); - SortedMap listing = new TreeMap(); - for (ChildEntry child : children) - { - AVMNode childNode = child.getChild(); - if (childNode.getType() == AVMNodeType.LAYERED_DIRECTORY || - childNode.getType() == AVMNodeType.PLAIN_DIRECTORY) - { - if (!AVMRepository.GetInstance().can(childNode, PermissionService.READ_CHILDREN)) - { - continue; - } - } - if (!includeDeleted && childNode.getType() == AVMNodeType.DELETED_NODE) - { - continue; - } - AVMNodeDescriptor childDesc = - childNode.getDescriptor(dir.getPath(), child.getKey().getName(), dir.getIndirection(), dir.getIndirectionVersion()); - listing.put(child.getKey().getName(), childDesc); - } - return listing; - } - - /** - * Get a listing from a directory node descriptor. - * @param dir The directory node descriptor. - * @param includeDeleted Should DeletedNodes be shown. - * @return A Map of names to node descriptors. - */ - public SortedMap getListing(AVMNodeDescriptor dir, - boolean includeDeleted) - { - if (dir.getPath() == null || dir.getIndirection() == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - SortedMap baseListing = new TreeMap(); - // If we are not opaque, get the underlying base listing. - if (!fOpacity) - { - Lookup lookup = AVMRepository.GetInstance().lookupDirectory(-1, dir.getIndirection()); - if (lookup != null) - { - DirectoryNode dirNode = (DirectoryNode)lookup.getCurrentNode(); - Map listing = dirNode.getListing(lookup, includeDeleted); - for (Map.Entry entry : listing.entrySet()) - { - if (entry.getValue().getType() == AVMNodeType.LAYERED_DIRECTORY || - entry.getValue().getType() == AVMNodeType.PLAIN_DIRECTORY) - { - if (!AVMRepository.GetInstance().can(entry.getValue(), PermissionService.READ_CHILDREN)) - { - continue; - } - } - baseListing.put(entry.getKey(), - entry.getValue().getDescriptor(dir.getPath(), entry.getKey(), - lookup.getCurrentIndirection(), - lookup.getCurrentIndirectionVersion())); - } - } - } - List children = AVMDAOs.Instance().fChildEntryDAO.getByParent(this); - for (ChildEntry child : children) - { - if (child.getChild().getType() == AVMNodeType.LAYERED_DIRECTORY || - child.getChild().getType() == AVMNodeType.PLAIN_DIRECTORY) - { - if (!AVMRepository.GetInstance().can(child.getChild(), PermissionService.READ_CHILDREN)) - { - continue; - } - } - if (!includeDeleted && child.getChild().getType() == AVMNodeType.DELETED_NODE) - { - baseListing.remove(child.getKey().getName()); - } - else - { - baseListing.put(child.getKey().getName(), - child.getChild().getDescriptor(dir.getPath(), - child.getKey().getName(), - dir.getIndirection(), - dir.getIndirectionVersion())); - } - } - return baseListing; - } - - /** - * Get the names of nodes deleted in this directory. - * @return A List of names. - */ - public List getDeletedNames() - { - List children = AVMDAOs.Instance().fChildEntryDAO.getByParent(this); - List listing = new ArrayList(); - for (ChildEntry entry : children) - { - if (entry.getChild().getType() == AVMNodeType.DELETED_NODE) - { - listing.add(entry.getKey().getName()); - } - } - return listing; - } - - /** - * Lookup a child by name. - * @param lPath The Lookup. - * @param name The name we are looking. - * @param version The version in which we are looking. - * @param write Whether this lookup is occurring in a write context. - * @return The child or null if not found. - */ - @SuppressWarnings("unchecked") - public Pair lookupChild(Lookup lPath, String name, boolean includeDeleted) - { - ChildKey key = new ChildKey(this, name); - ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); - if (entry != null) - { - if (!includeDeleted && entry.getChild().getType() == AVMNodeType.DELETED_NODE) - { - return null; - } - Pair result = new Pair(AVMNodeUnwrapper.Unwrap(entry.getChild()), true); - return result; - } - // Don't check our underlying directory if we are opaque. - if (fOpacity) - { - return null; - } - // Not here so check our indirection. - Lookup lookup = AVMRepository.GetInstance().lookupDirectory(getUnderlyingVersion(lPath), getUnderlying(lPath)); - if (lookup != null) - { - DirectoryNode dir = (DirectoryNode)lookup.getCurrentNode(); - Pair retVal = dir.lookupChild(lookup, name, includeDeleted); - if (retVal != null) - { - retVal.setSecond(false); - } - lPath.setFinalStore(lookup.getFinalStore()); - return retVal; - } - else - { - return null; - } - } - - /** - * Lookup a child using a node descriptor as context. - * @param mine The node descriptor for this, - * @param name The name to lookup, - * @return The node descriptor. - */ - public AVMNodeDescriptor lookupChild(AVMNodeDescriptor mine, String name, boolean includeDeleted) - { - if (mine.getPath() == null || mine.getIndirection() == null) - { - throw new AVMBadArgumentException("Illegal null argument."); - } - ChildKey key = new ChildKey(this, name); - ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); - if (entry != null) - { - if (!includeDeleted && entry.getChild().getType() == AVMNodeType.DELETED_NODE) - { - return null; - } - AVMNodeDescriptor desc = entry.getChild().getDescriptor(mine.getPath(), - name, - mine.getIndirection(), - mine.getIndirectionVersion()); - return desc; - } - // If we are opaque don't check underneath. - if (fOpacity) - { - return null; - } - Lookup lookup = AVMRepository.GetInstance().lookupDirectory(mine.getIndirectionVersion(), mine.getIndirection()); - if (lookup != null) - { - DirectoryNode dir = (DirectoryNode)lookup.getCurrentNode(); - Pair child = dir.lookupChild(lookup, name, includeDeleted); - if (child == null) - { - return null; - } - AVMNodeDescriptor desc = child.getFirst().getDescriptor(lookup); - return desc; - } - else - { - return null; - } - } - - /** - * Directly remove a child. Do not COW. Do not pass go etc. - * @param lPath The lookup that arrived at this. - * @param name The name of the child to remove. - */ - @SuppressWarnings("unchecked") - public void removeChild(Lookup lPath, String name) - { - if (DEBUG) - { - checkReadOnly(); - } - ChildKey key = new ChildKey(this, name); - ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); - AVMNode child = null; - boolean indirect = false; - if (entry != null) - { - child = entry.getChild(); - if (child.getType() == AVMNodeType.DELETED_NODE) - { - return; - } - AVMDAOs.Instance().fChildEntryDAO.delete(entry); - } - else - { - Pair temp = lookupChild(lPath, name, false); - if (temp == null) - { - child = null; - } - else - { - child = temp.getFirst(); - } - indirect = true; - } - if (child != null && (indirect || child.getStoreNew() == null || child.getAncestor() != null)) - { - DeletedNodeImpl ghost = new DeletedNodeImpl(lPath.getAVMStore().getAVMRepository().issueID(), - lPath.getAVMStore()); - AVMDAOs.Instance().fAVMNodeDAO.save(ghost); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - ghost.setAncestor(child); - ghost.setDeletedType(child.getType()); - this.putChild(name, ghost); - } - else - { - AVMDAOs.Instance().fAVMNodeDAO.flush(); - } - } - - /** - * Get the type of this node. - * @return The type of this node. - */ - public int getType() - { - return AVMNodeType.LAYERED_DIRECTORY; - } - - /** - * For diagnostics. Get a String representation. - * @param lPath The Lookup. - * @return A String representation. - */ - public String toString(Lookup lPath) - { - return "[LD:" + getId() + ":" + getUnderlying(lPath) + "]"; - } - - /** - * Set the primary indirection. No COW. - * @param path The indirection path. - */ - public void rawSetPrimary(String path) - { - if (DEBUG) - { - checkReadOnly(); - } - fIndirection = path; - fPrimaryIndirection = true; - } - - /** - * Make this node become a primary indirection. COW. - * @param lPath The Lookup. - */ - public void turnPrimary(Lookup lPath) - { - if (DEBUG) - { - checkReadOnly(); - } - String path = lPath.getCurrentIndirection(); - rawSetPrimary(path); - } - - /** - * Make this point at a new target. - * @param lPath The Lookup. - */ - public void retarget(Lookup lPath, String target) - { - if (DEBUG) - { - checkReadOnly(); - } - rawSetPrimary(target); - } - - /** - * Let anything behind name in this become visible. - * @param lPath The Lookup. - * @param name The name to uncover. - */ - public void uncover(Lookup lPath, String name) - { - if (DEBUG) - { - checkReadOnly(); - } - ChildKey key = new ChildKey(this, name); - ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); - if (entry.getChild().getType() != AVMNodeType.DELETED_NODE) - { - throw new AVMException("One can only uncover deleted nodes."); - } - if (entry != null) - { - AVMDAOs.Instance().fChildEntryDAO.delete(entry); - } - } - - /** - * Get the descriptor for this node. - * @param lPath The Lookup. - * @return A descriptor. - */ - public AVMNodeDescriptor getDescriptor(Lookup lPath, String name) - { - BasicAttributes attrs = getBasicAttributes(); - String path = lPath.getRepresentedPath(); - path = AVMNodeConverter.ExtendAVMPath(path, name); - String indirect = null; - int indirectionVersion = -1; - if (fPrimaryIndirection) - { - indirect = fIndirection; - indirectionVersion = fIndirectionVersion; - } - else - { - indirect = AVMNodeConverter.ExtendAVMPath(lPath.getCurrentIndirection(), name); - indirectionVersion = lPath.getCurrentIndirectionVersion(); - } - return new AVMNodeDescriptor(path, - name, - AVMNodeType.LAYERED_DIRECTORY, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - indirect, - indirectionVersion, - fPrimaryIndirection, - fLayerID, - fOpacity, - -1, - -1); - } - - /** - * Get the descriptor for this node. - * @param lPath The Lookup. - * @return A descriptor. - */ - public AVMNodeDescriptor getDescriptor(Lookup lPath) - { - BasicAttributes attrs = getBasicAttributes(); - String path = lPath.getRepresentedPath(); - String name = path.substring(path.lastIndexOf("/") + 1); - return new AVMNodeDescriptor(path, - name, - AVMNodeType.LAYERED_DIRECTORY, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - getUnderlying(lPath), - getUnderlyingVersion(lPath), - fPrimaryIndirection, - fLayerID, - fOpacity, - -1, - -1); - } - - /** - * Get a descriptor for this. - * @param parentPath The parent path. - * @param name The name this was looked up with. - * @param parentIndirection The indirection of the parent. - * @return The descriptor. - */ - public AVMNodeDescriptor getDescriptor(String parentPath, String name, String parentIndirection, int parentIndirectionVersion) - { - BasicAttributes attrs = getBasicAttributes(); - String path = parentPath.endsWith("/") ? parentPath + name : parentPath + "/" + name; - String indirection = null; - int indirectionVersion = -1; - if (fPrimaryIndirection) - { - indirection = fIndirection; - indirectionVersion = fIndirectionVersion; - } - else - { - indirection = parentIndirection.endsWith("/") ? parentIndirection + name : - parentIndirection + "/" + name; - indirectionVersion = parentIndirectionVersion; - } - return new AVMNodeDescriptor(path, - name, - AVMNodeType.LAYERED_DIRECTORY, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - indirection, - indirectionVersion, - fPrimaryIndirection, - fLayerID, - fOpacity, - -1, - -1); - } - - /** - * Set the indirection. - * @param indirection - */ - public void setIndirection(String indirection) - { - fIndirection = indirection; - } - - /** - * Does nothing because LayeredDirectoryNodes can't be roots. - * @param isRoot - */ - public void setIsRoot(boolean isRoot) - { - } - - /** - * Get the opacity of this. - * @return The opacity. - */ - public boolean getOpacity() - { - return fOpacity; - } - - /** - * Set the opacity of this, ie, whether it blocks things normally - * seen through its indirection. - * @param opacity - */ - public void setOpacity(boolean opacity) - { - fOpacity = opacity; - } - - /** - * Link a node with the given id into this directory. - * @param lPath The Lookup for this. - * @param name The name to give the node. - * @param toLink The node to link in. - */ - public void link(Lookup lPath, String name, AVMNodeDescriptor toLink) - { - if (DEBUG) - { - checkReadOnly(); - } - AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(toLink.getId()); - if (node == null) - { - throw new AVMNotFoundException("Not Found: " + toLink.getId()); - } - if (node.getType() == AVMNodeType.LAYERED_DIRECTORY && - !((LayeredDirectoryNode)node).getPrimaryIndirection()) - { - throw new AVMBadArgumentException("Non primary layered directories cannot be linked."); - } - // Look for an existing child of that name. - Pair temp = lookupChild(lPath, name, true); - AVMNode existing = (temp == null) ? null : temp.getFirst(); - ChildKey key = new ChildKey(this, name); - if (existing != null) - { - if (existing.getType() != AVMNodeType.DELETED_NODE) - { - // If the existing child is not a DELETED_NODE it's an error. - throw new AVMExistsException(name + " exists."); - } - // Only if the existing DELETED_NODE child exists directly in this - // directory do we delete it. - if (directlyContains(existing)) - { - ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); - AVMDAOs.Instance().fChildEntryDAO.delete(entry); - } - } - // Make the new ChildEntry and save. - ChildEntry newChild = new ChildEntryImpl(key, node); - AVMDAOs.Instance().fChildEntryDAO.save(newChild); - } - - /** - * Remove name without leaving behind a deleted node. - * @param name The name of the child to flatten. - */ - public void flatten(String name) - { - if (DEBUG) - { - checkReadOnly(); - } - ChildKey key = new ChildKey(this, name); - ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); - if (entry != null) - { - AVMDAOs.Instance().fChildEntryDAO.delete(entry); - } - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.LayeredDirectoryNode#setIndirectionVersion(int) - */ - public void setIndirectionVersion(Integer version) - { - if (version == null) - { - fIndirectionVersion = -1; - } - else - { - fIndirectionVersion = version; - } - } - - /** - * Get the indirection version. - * @return The indirection version. - */ - public Integer getIndirectionVersion() - { - return fIndirectionVersion; - } -} +/* + * 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.avm; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +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; +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.security.PermissionService; +import org.alfresco.util.Pair; + +/** + * A layered directory node. A layered directory node points at an underlying directory, which may or may not exist. The + * visible contents of a layered directory node is the contents of the underlying node pointed at plus those nodes added + * to or modified in the layered directory node minus those nodes which have been deleted in the layered directory node. + * + * @author britt + */ +class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirectoryNode +{ + static final long serialVersionUID = 4623043057918181724L; + + /** + * The layer id. + */ + private long fLayerID; + + /** + * The pointer to the underlying directory. + */ + private String fIndirection; + + /** + * Whether this is a primary indirection node. + */ + private boolean fPrimaryIndirection; + + /** + * Whether this is opaque. + */ + private boolean fOpacity; + + /** + * The indirection version. + */ + private int fIndirectionVersion; + + /** + * Default constructor. Called by Hibernate. + */ + protected LayeredDirectoryNodeImpl() + { + } + + /** + * Make a new one from a specified indirection path. + * + * @param indirection + * The indirection path to set. + * @param store + * The store that owns this node. + */ + public LayeredDirectoryNodeImpl(String indirection, AVMStore store, AVMNode toCopy, Long parentAcl, ACLCopyMode mode) + { + super(store.getAVMRepository().issueID(), store); + fLayerID = -1; + fIndirection = indirection; + fIndirectionVersion = -1; + fPrimaryIndirection = true; + fOpacity = false; + if (toCopy != null) + { + setVersionID(toCopy.getVersionID() + 1); + } + else + { + setVersionID(1); + } + AVMDAOs.Instance().fAVMNodeDAO.save(this); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + if (toCopy != null) + { + copyProperties(toCopy); + copyACLs(toCopy, parentAcl, mode); + copyAspects(toCopy); + } + else + { + if (indirection != null) + { + Lookup lookup = AVMRepository.GetInstance().lookupDirectory(-1, indirection); + if (lookup != null) + { + DirectoryNode dir = (DirectoryNode) lookup.getCurrentNode(); + if (dir.getAcl() != null) + { + setAcl(DbAccessControlListImpl.createLayeredAcl(dir.getAcl().getId())); + } + else + { + // TODO: Will not pick up changes if we start with no permission on teh terget node - may need + // to add + setAcl(DbAccessControlListImpl.createLayeredAcl(null)); + } + } + else + { + setAcl(DbAccessControlListImpl.createLayeredAcl(null)); + } + } + else + { + setAcl(DbAccessControlListImpl.createLayeredAcl(null)); + } + } + } + + /** + * Kind of copy constructor, sort of. + * + * @param other + * The LayeredDirectoryNode we are copied from. + * @param repos + * The AVMStore object we use. + */ + @SuppressWarnings("unchecked") + public LayeredDirectoryNodeImpl(LayeredDirectoryNode other, AVMStore repos, Lookup lookup, boolean copyAll, Long parentAcl, ACLCopyMode mode) + { + super(repos.getAVMRepository().issueID(), repos); + fIndirection = other.getIndirection(); + fPrimaryIndirection = other.getPrimaryIndirection(); + fIndirectionVersion = -1; + fLayerID = -1; + fOpacity = false; + AVMDAOs.Instance().fAVMNodeDAO.save(this); + Map children = null; + if (copyAll) + { + children = other.getListing(lookup, true); + } + else + { + children = other.getListingDirect(lookup, true); + } + for (Map.Entry child : children.entrySet()) + { + ChildKey key = new ChildKey(this, child.getKey()); + ChildEntry entry = new ChildEntryImpl(key, child.getValue()); + AVMDAOs.Instance().fChildEntryDAO.save(entry); + } + setVersionID(other.getVersionID() + 1); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + copyProperties(other); + copyAspects(other); + copyACLs(other, parentAcl, mode); + } + + /** + * Construct one from a PlainDirectoryNode. Called when a COW is performed in a layered context. + * + * @param other + * The PlainDirectoryNode. + * @param store + * The AVMStore we should belong to. + * @param lPath + * The Lookup object. + */ + @SuppressWarnings("unchecked") + public LayeredDirectoryNodeImpl(PlainDirectoryNode other, AVMStore store, Lookup lPath, boolean copyContents, Long parentAcl, ACLCopyMode mode) + { + super(store.getAVMRepository().issueID(), store); + fIndirection = null; + fPrimaryIndirection = false; + fIndirectionVersion = -1; + fLayerID = -1; + fOpacity = false; + AVMDAOs.Instance().fAVMNodeDAO.save(this); + if (copyContents) + { + for (ChildEntry child : AVMDAOs.Instance().fChildEntryDAO.getByParent(other)) + { + ChildKey key = new ChildKey(this, child.getKey().getName()); + ChildEntryImpl newChild = new ChildEntryImpl(key, child.getChild()); + AVMDAOs.Instance().fChildEntryDAO.save(newChild); + } + } + setVersionID(other.getVersionID() + 1); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + copyProperties(other); + copyAspects(other); + copyACLs(other, parentAcl, mode); + } + + /** + * Create a new layered directory based on a directory we are being named from that is in not in the layer of the + * source lookup. + * + * @param dir + * The directory + * @param store + * The store + * @param srcLookup + * The source lookup. + * @param name + * The name of the target. + */ + public LayeredDirectoryNodeImpl(DirectoryNode dir, AVMStore store, Lookup srcLookup, String name, Long inheritedAcl, ACLCopyMode mode) + { + super(store.getAVMRepository().issueID(), store); + fIndirection = srcLookup.getIndirectionPath() + "/" + name; + fPrimaryIndirection = true; + fIndirectionVersion = -1; + fLayerID = -1; + fOpacity = false; + setVersionID(dir.getVersionID() + 1); + AVMDAOs.Instance().fAVMNodeDAO.save(this); + Map children = dir.getListing(srcLookup, true); + for (Map.Entry child : children.entrySet()) + { + ChildKey key = new ChildKey(this, child.getKey()); + ChildEntry entry = new ChildEntryImpl(key, child.getValue()); + AVMDAOs.Instance().fChildEntryDAO.save(entry); + } + AVMDAOs.Instance().fAVMNodeDAO.flush(); + copyProperties(dir); + copyAspects(dir); + copyACLs(dir, inheritedAcl, mode); + } + + /** + * Is this a primary indirection node. + * + * @return Whether this is a primary indirection. + */ + public boolean getPrimaryIndirection() + { + return fPrimaryIndirection; + } + + /** + * Set the primary indirection state of this. + * + * @param has + * Whether this is a primary indirection node. + */ + public void setPrimaryIndirection(boolean has) + { + fPrimaryIndirection = has; + } + + /** + * Get the indirection path. + * + * @return The indirection path. + */ + public String getIndirection() + { + return fIndirection; + } + + /** + * Get the underlying path in the Lookup's context. + * + * @param lPath + * The Lookup. + * @return The underlying path. + */ + public String getUnderlying(Lookup lPath) + { + if (fPrimaryIndirection) + { + return fIndirection; + } + return lPath.getCurrentIndirection(); + } + + /** + * Get the underlying version in the lookup path context. + * + * @param lPath + * The Lookup. + * @return The effective underlying version. + */ + public int getUnderlyingVersion(Lookup lPath) + { + if (lPath.getVersion() == -1) + { + return -1; + } + if (fPrimaryIndirection) + { + return fIndirectionVersion; + } + return lPath.getCurrentIndirectionVersion(); + } + + /** + * Get the layer id. + * + * @return The layer id. + */ + public long getLayerID() + { + return fLayerID; + } + + /** + * Set the layer id. + * + * @param id + * The id to set. + */ + public void setLayerID(long id) + { + fLayerID = id; + } + + /** + * Copy on write logic. + * + * @param lPath + * @return The copy or null. + */ + public AVMNode copy(Lookup lPath) + { + DirectoryNode dir = lPath.getCurrentNodeDirectory(); + Long parentAclId = null; + if ((dir != null) && (dir.getAcl() != null)) + { + parentAclId = dir.getAcl().getId(); + } + // Capture the store. + AVMStore store = lPath.getAVMStore(); + LayeredDirectoryNodeImpl newMe = null; + if (!lPath.isInThisLayer()) + { + // This means that this is being seen indirectly through the topmost + // layer. The following creates a node that will inherit its + // indirection from its parent. + newMe = new LayeredDirectoryNodeImpl((String) null, store, this, parentAclId, ACLCopyMode.COW); + newMe.setPrimaryIndirection(false); + newMe.setLayerID(lPath.getTopLayer().getLayerID()); + } + else + { + // A simple copy is made. + newMe = new LayeredDirectoryNodeImpl(this, store, lPath, false, parentAclId, ACLCopyMode.COW); + newMe.setLayerID(getLayerID()); + } + newMe.setAncestor(this); + return newMe; + } + + /** + * Insert a child node without COW. + * + * @param name + * The name to give the child. + */ + public void putChild(String name, AVMNode node) + { + if (DEBUG) + { + checkReadOnly(); + } + ChildKey key = new ChildKey(this, name); + ChildEntry existing = AVMDAOs.Instance().fChildEntryDAO.get(key); + if (existing != null) + { + AVMDAOs.Instance().fChildEntryDAO.delete(existing); + } + ChildEntry entry = new ChildEntryImpl(key, node); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + AVMDAOs.Instance().fChildEntryDAO.save(entry); + } + + /** + * 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.getByParentChild(this, node) != null; + } + + /** + * Get a listing of the virtual contents of this directory. + * + * @param lPath + * The Lookup. + * @return A Map from names to nodes. This is a sorted Map. + */ + @SuppressWarnings("unchecked") + public Map getListing(Lookup lPath, boolean includeDeleted) + { + // Get the base listing from the thing we indirect to. + Map listing = new HashMap(); + if (!fOpacity) + { + Lookup lookup = AVMRepository.GetInstance().lookupDirectory(getUnderlyingVersion(lPath), getUnderlying(lPath)); + if (lookup != null) + { + DirectoryNode dir = (DirectoryNode) lookup.getCurrentNode(); + Map underListing = dir.getListing(lookup, includeDeleted); + for (Map.Entry entry : underListing.entrySet()) + { + if (entry.getValue().getType() == AVMNodeType.LAYERED_DIRECTORY || + entry.getValue().getType() == AVMNodeType.PLAIN_DIRECTORY) + { + if (!AVMRepository.GetInstance().can(entry.getValue(), PermissionService.READ_CHILDREN)) + { + continue; + } + } + listing.put(entry.getKey(), entry.getValue()); + } + } + } + for (ChildEntry entry : AVMDAOs.Instance().fChildEntryDAO.getByParent(this)) + { + if (entry.getChild().getType() == AVMNodeType.LAYERED_DIRECTORY || + entry.getChild().getType() == AVMNodeType.PLAIN_DIRECTORY) + { + if (!AVMRepository.GetInstance().can(entry.getChild(), PermissionService.READ_CHILDREN)) + { + continue; + } + } + if (!includeDeleted && entry.getChild().getType() == AVMNodeType.DELETED_NODE) + { + listing.remove(entry.getKey().getName()); + } + else + { + listing.put(entry.getKey().getName(), entry.getChild()); + } + } + return listing; + } + + /** + * Get a listing of the nodes directly contained by a directory. + * + * @param lPath + * The Lookup to this directory. + * @return A Map of names to nodes. + */ + public Map getListingDirect(Lookup lPath, boolean includeDeleted) + { + Map listing = new HashMap(); + for (ChildEntry entry : AVMDAOs.Instance().fChildEntryDAO.getByParent(this)) + { + if (entry.getChild().getType() == AVMNodeType.LAYERED_DIRECTORY || + entry.getChild().getType() == AVMNodeType.PLAIN_DIRECTORY) + { + if (!AVMRepository.GetInstance().can(entry.getChild(), PermissionService.READ_CHILDREN)) + { + continue; + } + } + if (includeDeleted || entry.getChild().getType() != AVMNodeType.DELETED_NODE) + { + listing.put(entry.getKey().getName(), entry.getChild()); + } + } + return listing; + } + + /** + * Get the direct contents of this directory. + * + * @param dir + * The descriptor that describes us. + * @param includeDeleted + * Whether to inlude deleted nodes. + * @return A Map of Strings to descriptors. + */ + public SortedMap getListingDirect(AVMNodeDescriptor dir, boolean includeDeleted) + { + List children = AVMDAOs.Instance().fChildEntryDAO.getByParent(this); + SortedMap listing = new TreeMap(); + for (ChildEntry child : children) + { + AVMNode childNode = child.getChild(); + if (childNode.getType() == AVMNodeType.LAYERED_DIRECTORY || + childNode.getType() == AVMNodeType.PLAIN_DIRECTORY) + { + if (!AVMRepository.GetInstance().can(childNode, PermissionService.READ_CHILDREN)) + { + continue; + } + } + if (!includeDeleted && childNode.getType() == AVMNodeType.DELETED_NODE) + { + continue; + } + AVMNodeDescriptor childDesc = childNode.getDescriptor(dir.getPath(), child.getKey().getName(), dir.getIndirection(), dir.getIndirectionVersion()); + listing.put(child.getKey().getName(), childDesc); + } + return listing; + } + + /** + * Get a listing from a directory node descriptor. + * + * @param dir + * The directory node descriptor. + * @param includeDeleted + * Should DeletedNodes be shown. + * @return A Map of names to node descriptors. + */ + public SortedMap getListing(AVMNodeDescriptor dir, boolean includeDeleted) + { + if (dir.getPath() == null || dir.getIndirection() == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + SortedMap baseListing = new TreeMap(); + // If we are not opaque, get the underlying base listing. + if (!fOpacity) + { + Lookup lookup = AVMRepository.GetInstance().lookupDirectory(-1, dir.getIndirection()); + if (lookup != null) + { + DirectoryNode dirNode = (DirectoryNode) lookup.getCurrentNode(); + Map listing = dirNode.getListing(lookup, includeDeleted); + for (Map.Entry entry : listing.entrySet()) + { + if (entry.getValue().getType() == AVMNodeType.LAYERED_DIRECTORY || + entry.getValue().getType() == AVMNodeType.PLAIN_DIRECTORY) + { + if (!AVMRepository.GetInstance().can(entry.getValue(), PermissionService.READ_CHILDREN)) + { + continue; + } + } + baseListing.put(entry.getKey(), + entry.getValue().getDescriptor(dir.getPath(), entry.getKey(), + lookup.getCurrentIndirection(), + lookup.getCurrentIndirectionVersion())); + } + } + } + List children = AVMDAOs.Instance().fChildEntryDAO.getByParent(this); + for (ChildEntry child : children) + { + if (child.getChild().getType() == AVMNodeType.LAYERED_DIRECTORY || + child.getChild().getType() == AVMNodeType.PLAIN_DIRECTORY) + { + if (!AVMRepository.GetInstance().can(child.getChild(), PermissionService.READ_CHILDREN)) + { + continue; + } + } + if (!includeDeleted && child.getChild().getType() == AVMNodeType.DELETED_NODE) + { + baseListing.remove(child.getKey().getName()); + } + else + { + baseListing.put(child.getKey().getName(), child.getChild() + .getDescriptor(dir.getPath(), child.getKey().getName(), dir.getIndirection(), dir.getIndirectionVersion())); + } + } + return baseListing; + } + + /** + * Get the names of nodes deleted in this directory. + * + * @return A List of names. + */ + public List getDeletedNames() + { + List children = AVMDAOs.Instance().fChildEntryDAO.getByParent(this); + List listing = new ArrayList(); + for (ChildEntry entry : children) + { + if (entry.getChild().getType() == AVMNodeType.DELETED_NODE) + { + listing.add(entry.getKey().getName()); + } + } + return listing; + } + + /** + * Lookup a child by name. + * + * @param lPath + * The Lookup. + * @param name + * The name we are looking. + * @param version + * The version in which we are looking. + * @param write + * Whether this lookup is occurring in a write context. + * @return The child or null if not found. + */ + @SuppressWarnings("unchecked") + public Pair lookupChild(Lookup lPath, String name, boolean includeDeleted) + { + ChildKey key = new ChildKey(this, name); + ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); + if (entry != null) + { + if (!includeDeleted && entry.getChild().getType() == AVMNodeType.DELETED_NODE) + { + return null; + } + Pair result = new Pair(AVMNodeUnwrapper.Unwrap(entry.getChild()), true); + return result; + } + // Don't check our underlying directory if we are opaque. + if (fOpacity) + { + return null; + } + // Not here so check our indirection. + Lookup lookup = AVMRepository.GetInstance().lookupDirectory(getUnderlyingVersion(lPath), getUnderlying(lPath)); + if (lookup != null) + { + DirectoryNode dir = (DirectoryNode) lookup.getCurrentNode(); + Pair retVal = dir.lookupChild(lookup, name, includeDeleted); + if (retVal != null) + { + retVal.setSecond(false); + } + lPath.setFinalStore(lookup.getFinalStore()); + return retVal; + } + else + { + return null; + } + } + + /** + * Lookup a child using a node descriptor as context. + * + * @param mine + * The node descriptor for this, + * @param name + * The name to lookup, + * @return The node descriptor. + */ + public AVMNodeDescriptor lookupChild(AVMNodeDescriptor mine, String name, boolean includeDeleted) + { + if (mine.getPath() == null || mine.getIndirection() == null) + { + throw new AVMBadArgumentException("Illegal null argument."); + } + ChildKey key = new ChildKey(this, name); + ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); + if (entry != null) + { + if (!includeDeleted && entry.getChild().getType() == AVMNodeType.DELETED_NODE) + { + return null; + } + AVMNodeDescriptor desc = entry.getChild().getDescriptor(mine.getPath(), name, mine.getIndirection(), mine.getIndirectionVersion()); + return desc; + } + // If we are opaque don't check underneath. + if (fOpacity) + { + return null; + } + Lookup lookup = AVMRepository.GetInstance().lookupDirectory(mine.getIndirectionVersion(), mine.getIndirection()); + if (lookup != null) + { + DirectoryNode dir = (DirectoryNode) lookup.getCurrentNode(); + Pair child = dir.lookupChild(lookup, name, includeDeleted); + if (child == null) + { + return null; + } + AVMNodeDescriptor desc = child.getFirst().getDescriptor(lookup); + return desc; + } + else + { + return null; + } + } + + /** + * Directly remove a child. Do not COW. Do not pass go etc. + * + * @param lPath + * The lookup that arrived at this. + * @param name + * The name of the child to remove. + */ + @SuppressWarnings("unchecked") + public void removeChild(Lookup lPath, String name) + { + if (DEBUG) + { + checkReadOnly(); + } + ChildKey key = new ChildKey(this, name); + ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); + AVMNode child = null; + boolean indirect = false; + if (entry != null) + { + child = entry.getChild(); + if (child.getType() == AVMNodeType.DELETED_NODE) + { + return; + } + AVMDAOs.Instance().fChildEntryDAO.delete(entry); + } + else + { + Pair temp = lookupChild(lPath, name, false); + if (temp == null) + { + child = null; + } + else + { + child = temp.getFirst(); + } + indirect = true; + } + if (child != null && (indirect || child.getStoreNew() == null || child.getAncestor() != null)) + { + DeletedNodeImpl ghost = new DeletedNodeImpl(lPath.getAVMStore().getAVMRepository().issueID(), lPath.getAVMStore(), child.getAcl()); + AVMDAOs.Instance().fAVMNodeDAO.save(ghost); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + ghost.setAncestor(child); + ghost.setDeletedType(child.getType()); + this.putChild(name, ghost); + } + else + { + AVMDAOs.Instance().fAVMNodeDAO.flush(); + } + } + + /** + * Get the type of this node. + * + * @return The type of this node. + */ + public int getType() + { + return AVMNodeType.LAYERED_DIRECTORY; + } + + /** + * For diagnostics. Get a String representation. + * + * @param lPath + * The Lookup. + * @return A String representation. + */ + public String toString(Lookup lPath) + { + return "[LD:" + getId() + ":" + getUnderlying(lPath) + "]"; + } + + /** + * Set the primary indirection. No COW. Cascade resetting of acls also does not COW + * + * @param path + * The indirection path. + */ + public void rawSetPrimary(Lookup lPath, String path) + { + if (DEBUG) + { + checkReadOnly(); + } + + fIndirection = path; + fPrimaryIndirection = true; + // Need to change the permission we point to .... + if (fIndirection != null) + { + if ((getAcl() == null) || (getAcl().getAclType() == ACLType.LAYERED)) + { + DbAccessControlList acl = null; + Lookup lookup = AVMRepository.GetInstance().lookupDirectory(-1, fIndirection); + if (lookup != null) + { + DirectoryNode dir = (DirectoryNode) lookup.getCurrentNode(); + if (dir.getAcl() != null) + { + if (getAcl() == null) + { + acl = DbAccessControlListImpl.createLayeredAcl(dir.getAcl().getId()); + } + else + { + acl = getAcl().getCopy(dir.getAcl().getId(), ACLCopyMode.REDIRECT); + } + } + else + { + if (getAcl() == null) + { + acl = DbAccessControlListImpl.createLayeredAcl(null); + } + else + { + acl = getAcl().getCopy(null, ACLCopyMode.REDIRECT); + } + } + } + setAclAndInherit(this, acl, null); + } + } + else + { + + if (getAcl().getAclType() == ACLType.LAYERED) + { + DbAccessControlList acl = null; + if (getAcl() == null) + { + acl = DbAccessControlListImpl.createLayeredAcl(null); + } + else + { + acl = getAcl().getCopy(null, ACLCopyMode.REDIRECT); + } + setAclAndInherit(this, acl, null); + } + } + } + + protected void setAclAndInherit(LayeredDirectoryNodeImpl layeredDirectory, DbAccessControlList acl, String name) + { + // Note ACLS may COW on next ACL change + layeredDirectory.setAcl(acl); + Map directChildren = layeredDirectory.getListingDirect((Lookup) null, true); + for (String key : directChildren.keySet()) + { + AVMNode node = directChildren.get(key); + + if (node instanceof LayeredDirectoryNodeImpl) + { + LayeredDirectoryNodeImpl childNode = (LayeredDirectoryNodeImpl) node; + DbAccessControlList currentAcl = node.getAcl(); + if (currentAcl == null) + { + if (acl == null) + { + childNode.setAclAndInherit(childNode, null, key); + } + else + { + childNode.setAclAndInherit(childNode, acl.getCopy(acl.getId(), ACLCopyMode.REDIRECT), key); + } + } + else + { + if (acl == null) + { + childNode.setAclAndInherit(childNode, currentAcl, key); + } + else + { + childNode.setAclAndInherit(childNode, currentAcl.getCopy(acl.getId(), ACLCopyMode.REDIRECT), key); + } + } + } + else if (node instanceof PlainFileNodeImpl) + { + PlainFileNodeImpl childNode = (PlainFileNodeImpl) node; + DbAccessControlList currentAcl = node.getAcl(); + if (currentAcl == null) + { + if (acl == null) + { + childNode.setAcl(null); + } + else + { + childNode.setAcl(acl.getCopy(acl.getId(), ACLCopyMode.REDIRECT)); + } + } + else + { + if (acl == null) + { + childNode.setAcl(currentAcl); + } + else + { + childNode.setAcl(currentAcl.getCopy(acl.getId(), ACLCopyMode.REDIRECT)); + } + } + } + } + } + + /** + * Make this node become a primary indirection. COW. + * + * @param lPath + * The Lookup. + */ + public void turnPrimary(Lookup lPath) + { + if (DEBUG) + { + checkReadOnly(); + } + String path = lPath.getCurrentIndirection(); + rawSetPrimary(lPath, path); + } + + /** + * Make this point at a new target. + * + * @param lPath + * The Lookup. + */ + public void retarget(Lookup lPath, String target) + { + if (DEBUG) + { + checkReadOnly(); + } + rawSetPrimary(lPath, target); + } + + /** + * Let anything behind name in this become visible. + * + * @param lPath + * The Lookup. + * @param name + * The name to uncover. + */ + public void uncover(Lookup lPath, String name) + { + if (DEBUG) + { + checkReadOnly(); + } + ChildKey key = new ChildKey(this, name); + ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); + if (entry.getChild().getType() != AVMNodeType.DELETED_NODE) + { + throw new AVMException("One can only uncover deleted nodes."); + } + if (entry != null) + { + AVMDAOs.Instance().fChildEntryDAO.delete(entry); + } + } + + /** + * Get the descriptor for this node. + * + * @param lPath + * The Lookup. + * @return A descriptor. + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath, String name) + { + BasicAttributes attrs = getBasicAttributes(); + String path = lPath.getRepresentedPath(); + path = AVMNodeConverter.ExtendAVMPath(path, name); + String indirect = null; + int indirectionVersion = -1; + if (fPrimaryIndirection) + { + indirect = fIndirection; + indirectionVersion = fIndirectionVersion; + } + else + { + indirect = AVMNodeConverter.ExtendAVMPath(lPath.getCurrentIndirection(), name); + indirectionVersion = lPath.getCurrentIndirectionVersion(); + } + return new AVMNodeDescriptor(path, name, AVMNodeType.LAYERED_DIRECTORY, attrs.getCreator(), attrs.getOwner(), attrs.getLastModifier(), attrs.getCreateDate(), attrs + .getModDate(), attrs.getAccessDate(), getId(), getGuid(), getVersionID(), indirect, indirectionVersion, fPrimaryIndirection, fLayerID, fOpacity, -1, -1); + } + + /** + * Get the descriptor for this node. + * + * @param lPath + * The Lookup. + * @return A descriptor. + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath) + { + BasicAttributes attrs = getBasicAttributes(); + String path = lPath.getRepresentedPath(); + String name = path.substring(path.lastIndexOf("/") + 1); + return new AVMNodeDescriptor(path, name, AVMNodeType.LAYERED_DIRECTORY, attrs.getCreator(), attrs.getOwner(), attrs.getLastModifier(), attrs.getCreateDate(), attrs + .getModDate(), attrs.getAccessDate(), getId(), getGuid(), getVersionID(), getUnderlying(lPath), getUnderlyingVersion(lPath), fPrimaryIndirection, fLayerID, + fOpacity, -1, -1); + } + + /** + * Get a descriptor for this. + * + * @param parentPath + * The parent path. + * @param name + * The name this was looked up with. + * @param parentIndirection + * The indirection of the parent. + * @return The descriptor. + */ + public AVMNodeDescriptor getDescriptor(String parentPath, String name, String parentIndirection, int parentIndirectionVersion) + { + BasicAttributes attrs = getBasicAttributes(); + String path = parentPath.endsWith("/") ? parentPath + name : parentPath + "/" + name; + String indirection = null; + int indirectionVersion = -1; + if (fPrimaryIndirection) + { + indirection = fIndirection; + indirectionVersion = fIndirectionVersion; + } + else + { + indirection = parentIndirection.endsWith("/") ? parentIndirection + name : parentIndirection + "/" + name; + indirectionVersion = parentIndirectionVersion; + } + return new AVMNodeDescriptor(path, name, AVMNodeType.LAYERED_DIRECTORY, attrs.getCreator(), attrs.getOwner(), attrs.getLastModifier(), attrs.getCreateDate(), attrs + .getModDate(), attrs.getAccessDate(), getId(), getGuid(), getVersionID(), indirection, indirectionVersion, fPrimaryIndirection, fLayerID, fOpacity, -1, -1); + } + + /** + * Set the indirection. + * + * @param indirection + */ + public void setIndirection(String indirection) + { + fIndirection = indirection; + } + + /** + * Does nothing because LayeredDirectoryNodes can't be roots. + * + * @param isRoot + */ + public void setIsRoot(boolean isRoot) + { + } + + /** + * Get the opacity of this. + * + * @return The opacity. + */ + public boolean getOpacity() + { + return fOpacity; + } + + /** + * Set the opacity of this, ie, whether it blocks things normally seen through its indirection. + * + * @param opacity + */ + public void setOpacity(boolean opacity) + { + fOpacity = opacity; + } + + /** + * Link a node with the given id into this directory. + * + * @param lPath + * The Lookup for this. + * @param name + * The name to give the node. + * @param toLink + * The node to link in. + */ + public void link(Lookup lPath, String name, AVMNodeDescriptor toLink) + { + if (DEBUG) + { + checkReadOnly(); + } + AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(toLink.getId()); + if (node == null) + { + throw new AVMNotFoundException("Not Found: " + toLink.getId()); + } + if (node.getType() == AVMNodeType.LAYERED_DIRECTORY && !((LayeredDirectoryNode) node).getPrimaryIndirection()) + { + throw new AVMBadArgumentException("Non primary layered directories cannot be linked."); + } + // Look for an existing child of that name. + Pair temp = lookupChild(lPath, name, true); + AVMNode existing = (temp == null) ? null : temp.getFirst(); + ChildKey key = new ChildKey(this, name); + if (existing != null) + { + if (existing.getType() != AVMNodeType.DELETED_NODE) + { + // If the existing child is not a DELETED_NODE it's an error. + throw new AVMExistsException(name + " exists."); + } + // Only if the existing DELETED_NODE child exists directly in this + // directory do we delete it. + if (directlyContains(existing)) + { + ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); + AVMDAOs.Instance().fChildEntryDAO.delete(entry); + } + } + // Make the new ChildEntry and save. + ChildEntry newChild = new ChildEntryImpl(key, node); + AVMDAOs.Instance().fChildEntryDAO.save(newChild); + } + + /** + * Remove name without leaving behind a deleted node. + * + * @param name + * The name of the child to flatten. + */ + public void flatten(String name) + { + if (DEBUG) + { + checkReadOnly(); + } + ChildKey key = new ChildKey(this, name); + ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); + if (entry != null) + { + AVMDAOs.Instance().fChildEntryDAO.delete(entry); + } + } + + /* + * (non-Javadoc) + * + * @see org.alfresco.repo.avm.LayeredDirectoryNode#setIndirectionVersion(int) + */ + public void setIndirectionVersion(Integer version) + { + if (version == null) + { + fIndirectionVersion = -1; + } + else + { + fIndirectionVersion = version; + } + } + + /** + * Get the indirection version. + * + * @return The indirection version. + */ + public Integer getIndirectionVersion() + { + return fIndirectionVersion; + } + +} diff --git a/source/java/org/alfresco/repo/avm/LayeredFileNodeImpl.java b/source/java/org/alfresco/repo/avm/LayeredFileNodeImpl.java index e97498d33d..01e8fe52c5 100644 --- a/source/java/org/alfresco/repo/avm/LayeredFileNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/LayeredFileNodeImpl.java @@ -1,338 +1,363 @@ -/* - * 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.avm; - -import org.alfresco.service.cmr.avm.AVMException; -import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.cmr.repository.ContentData; - -/** - * A LayeredFileNode behaves like a copy on write symlink. - * @author britt - */ -class LayeredFileNodeImpl extends FileNodeImpl implements LayeredFileNode -{ - static final long serialVersionUID = 9208423010479156363L; - - /** - * The indirection. - */ - private String fIndirection; - - /** - * The indirection version. - */ - private int fIndirectionVersion; - - /** - * Anonymous constructor. - */ - protected LayeredFileNodeImpl() - { - } - - /** - * Basically a copy constructor. Used when a branch is created - * from a layered file. - * @param other The file to make a copy of. - * @param store The store that contains us. - */ - public LayeredFileNodeImpl(LayeredFileNode other, AVMStore store) - { - super(store.getAVMRepository().issueID(), store); - fIndirection = other.getIndirection(); - fIndirectionVersion = -1; - setVersionID(other.getVersionID() + 1); - AVMDAOs.Instance().fAVMNodeDAO.save(this); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - copyProperties(other); - copyAspects(other); - copyACLs(other); - } - - /** - * Make a brand new layered file node. - * @param indirection The thing we point to. - * @param store The store we belong to. - */ - public LayeredFileNodeImpl(String indirection, AVMStore store) - { - super(store.getAVMRepository().issueID(), store); - fIndirection = indirection; - fIndirectionVersion = -1; - setVersionID(1); - AVMDAOs.Instance().fAVMNodeDAO.save(this); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - } - - /** - * Copy on write logic. - * @param lPath The path by which this was found. - */ - public AVMNode copy(Lookup lPath) - { - // LayeredFileNodes are always copied. - Lookup lookup = AVMRepository.GetInstance().lookup(-1, fIndirection, false); - if (lookup == null) - { - throw new AVMException("Unbacked layered file node."); - } - AVMNode indirect = lookup.getCurrentNode(); - if (indirect.getType() != AVMNodeType.LAYERED_FILE && - indirect.getType() != AVMNodeType.PLAIN_FILE) - { - throw new AVMException("Unbacked layered file node."); - } - // TODO This doesn't look quite right. - PlainFileNodeImpl newMe = new PlainFileNodeImpl(lPath.getAVMStore(), - getBasicAttributes(), - getContentData(lPath), - indirect.getProperties(), - indirect.getAspects(), - indirect.getAcl(), - getVersionID()); - newMe.setAncestor(this); - return newMe; - } - - /** - * Get the type of this node. - * @return The type. - */ - public int getType() - { - return AVMNodeType.LAYERED_FILE; - } - - /** - * Get the underlying path. - * @param lookup The Lookup. (Unused here.) - * @return The underlying path. - */ - public String getUnderlying(Lookup lookup) - { - return fIndirection; - } - - /** - * Get a diagnostic String representation. - * @param lPath The Lookup. - * @return A diagnostic String representation. - */ - public String toString(Lookup lPath) - { - return "[LF:" + getId() + ":" + fIndirection + "]"; - } - - /** - * Get the descriptor for this node. - * @param lPath The Lookup. - * @return A descriptor. - */ - public AVMNodeDescriptor getDescriptor(Lookup lPath, String name) - { - BasicAttributes attrs = getBasicAttributes(); - String path = lPath.getRepresentedPath(); - if (path.endsWith("/")) - { - path = path + name; - } - else - { - path = path + "/" + name; - } - return new AVMNodeDescriptor(path, - name, - AVMNodeType.LAYERED_FILE, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - getUnderlying(lPath), - getUnderlyingVersion(lPath), - false, - -1, - false, - 0, - -1); - } - - /** - * Get the descriptor for this node. - * @param lPath The Lookup. - * @return A descriptor. - */ - public AVMNodeDescriptor getDescriptor(Lookup lPath) - { - BasicAttributes attrs = getBasicAttributes(); - String path = lPath.getRepresentedPath(); - return new AVMNodeDescriptor(path, - path.substring(path.lastIndexOf("/") + 1), - AVMNodeType.LAYERED_FILE, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - getUnderlying(lPath), - getUnderlyingVersion(lPath), - false, - -1, - false, - 0, - -1); - } - - /** - * Get the descriptor for this node. - * @param parentPath The parent path. - * @param name The name this was looked up with. - * @param parentIndirection The parent indirection. - * @return The descriptor. - */ - public AVMNodeDescriptor getDescriptor(String parentPath, String name, String parentIndirection, int parentIndirectionVersion) - { - 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(), - fIndirection, - fIndirectionVersion, - false, - -1, - false, - 0, - -1); - } - - /** - * Get the indirection. - * @return The indirection. - */ - public String getIndirection() - { - return fIndirection; - } - - /** - * Set the indirection. - * @param indirection - */ - public void setIndirection(String indirection) - { - fIndirection = indirection; - } - - /** - * Set the ContentData for this file. - * @param contentData The value to set. - */ - public void setContentData(ContentData contentData) - { - throw new AVMException("Should not be called."); - } - - // TODO The lPath argument is unnecessary. - /** - * Get the ContentData for this file. - * @return The ContentData object for this file. - */ - public ContentData getContentData(Lookup lPath) - { - Lookup lookup = lPath.getAVMStore().getAVMRepository().lookup(getUnderlyingVersion(lPath), getIndirection(), false); - if (lookup == null) - { - throw new AVMException("Invalid target."); - } - AVMNode node = lookup.getCurrentNode(); - if (!(node instanceof FileNode)) - { - throw new AVMException("Invalid target."); - } - FileNode file = (FileNode)node; - return file.getContentData(lookup); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.Layered#getUnderlyingVersion(org.alfresco.repo.avm.Lookup) - */ - public int getUnderlyingVersion(Lookup lookup) - { - if (lookup.getVersion() == -1) - { - return -1; - } - return fIndirectionVersion; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.LayeredFileNode#getIndirectionVersion() - */ - public Integer getIndirectionVersion() - { - return fIndirectionVersion; - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.LayeredFileNode#setIndirectionVersion(int) - */ - public void setIndirectionVersion(Integer version) - { - if (version == null) - { - fIndirectionVersion = -1; - } - else - { - fIndirectionVersion = version; - } - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.LayeredFileNode#copyLiterally(org.alfresco.repo.avm.Lookup) - */ - public LayeredFileNode copyLiterally(Lookup lookup) - { - return new LayeredFileNodeImpl(this, lookup.getAVMStore()); - } -} +/* + * 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.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; +import org.alfresco.service.cmr.repository.ContentData; + +/** + * A LayeredFileNode behaves like a copy on write symlink. + * + * @author britt + */ +class LayeredFileNodeImpl extends FileNodeImpl implements LayeredFileNode +{ + static final long serialVersionUID = 9208423010479156363L; + + /** + * The indirection. + */ + private String fIndirection; + + /** + * The indirection version. + */ + private int fIndirectionVersion; + + /** + * Anonymous constructor. + */ + protected LayeredFileNodeImpl() + { + } + + /** + * Basically a copy constructor. Used when a branch is created from a layered file. + * + * @param other + * The file to make a copy of. + * @param store + * The store that contains us. + */ + public LayeredFileNodeImpl(LayeredFileNode other, AVMStore store, Long parentAcl, ACLCopyMode mode) + { + super(store.getAVMRepository().issueID(), store); + fIndirection = other.getIndirection(); + fIndirectionVersion = -1; + setVersionID(other.getVersionID() + 1); + AVMDAOs.Instance().fAVMNodeDAO.save(this); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + copyProperties(other); + copyAspects(other); + copyACLs(other, parentAcl, mode); + } + + /** + * Make a brand new layered file node. + * + * @param indirection + * The thing we point to. + * @param store + * The store we belong to. + */ + public LayeredFileNodeImpl(String indirection, AVMStore store, DbAccessControlList acl) + { + super(store.getAVMRepository().issueID(), store); + fIndirection = indirection; + fIndirectionVersion = -1; + setVersionID(1); + AVMDAOs.Instance().fAVMNodeDAO.save(this); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + if (acl != null) + { + this.setAcl(acl); + } + else + { + if (indirection != null) + { + Lookup lookup = AVMRepository.GetInstance().lookup(-1, indirection, false); + if (lookup != null) + { + AVMNode node = lookup.getCurrentNode(); + if (node.getAcl() != null) + { + setAcl(DbAccessControlListImpl.createLayeredAcl(node.getAcl().getId())); + } + else + { + setAcl(DbAccessControlListImpl.createLayeredAcl(null)); + } + } + else + { + setAcl(DbAccessControlListImpl.createLayeredAcl(null)); + } + } + else + { + setAcl(DbAccessControlListImpl.createLayeredAcl(null)); + } + } + } + + /** + * Copy on write logic. + * + * @param lPath + * The path by which this was found. + */ + public AVMNode copy(Lookup lPath) + { + // LayeredFileNodes are always copied. + Lookup lookup = AVMRepository.GetInstance().lookup(-1, fIndirection, false); + if (lookup == null) + { + throw new AVMException("Unbacked layered file node."); + } + AVMNode indirect = lookup.getCurrentNode(); + if (indirect.getType() != AVMNodeType.LAYERED_FILE && indirect.getType() != AVMNodeType.PLAIN_FILE) + { + throw new AVMException("Unbacked layered file node."); + } + DirectoryNode dir = lPath.getCurrentNodeDirectory(); + Long parentAclId = null; + if ((dir != null) && (dir.getAcl() != null)) + { + parentAclId = dir.getAcl().getId(); + } + // 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); + newMe.setAncestor(this); + return newMe; + } + + /** + * Get the type of this node. + * + * @return The type. + */ + public int getType() + { + return AVMNodeType.LAYERED_FILE; + } + + /** + * Get the underlying path. + * + * @param lookup + * The Lookup. (Unused here.) + * @return The underlying path. + */ + public String getUnderlying(Lookup lookup) + { + return fIndirection; + } + + /** + * Get a diagnostic String representation. + * + * @param lPath + * The Lookup. + * @return A diagnostic String representation. + */ + public String toString(Lookup lPath) + { + return "[LF:" + getId() + ":" + fIndirection + "]"; + } + + /** + * Get the descriptor for this node. + * + * @param lPath + * The Lookup. + * @return A descriptor. + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath, String name) + { + BasicAttributes attrs = getBasicAttributes(); + String path = lPath.getRepresentedPath(); + if (path.endsWith("/")) + { + path = path + name; + } + else + { + path = path + "/" + name; + } + return new AVMNodeDescriptor(path, name, AVMNodeType.LAYERED_FILE, attrs.getCreator(), attrs.getOwner(), attrs.getLastModifier(), attrs.getCreateDate(), + attrs.getModDate(), attrs.getAccessDate(), getId(), getGuid(), getVersionID(), getUnderlying(lPath), getUnderlyingVersion(lPath), false, -1, false, 0, -1); + } + + /** + * Get the descriptor for this node. + * + * @param lPath + * The Lookup. + * @return A descriptor. + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath) + { + BasicAttributes attrs = getBasicAttributes(); + String path = lPath.getRepresentedPath(); + return new AVMNodeDescriptor(path, path.substring(path.lastIndexOf("/") + 1), AVMNodeType.LAYERED_FILE, attrs.getCreator(), attrs.getOwner(), attrs.getLastModifier(), + attrs.getCreateDate(), attrs.getModDate(), attrs.getAccessDate(), getId(), getGuid(), getVersionID(), getUnderlying(lPath), getUnderlyingVersion(lPath), false, -1, + false, 0, -1); + } + + /** + * Get the descriptor for this node. + * + * @param parentPath + * The parent path. + * @param name + * The name this was looked up with. + * @param parentIndirection + * The parent indirection. + * @return The descriptor. + */ + public AVMNodeDescriptor getDescriptor(String parentPath, String name, String parentIndirection, int parentIndirectionVersion) + { + 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(), fIndirection, fIndirectionVersion, false, -1, false, 0, -1); + } + + /** + * Get the indirection. + * + * @return The indirection. + */ + public String getIndirection() + { + return fIndirection; + } + + /** + * Set the indirection. + * + * @param indirection + */ + public void setIndirection(String indirection) + { + fIndirection = indirection; + } + + /** + * Set the ContentData for this file. + * + * @param contentData + * The value to set. + */ + public void setContentData(ContentData contentData) + { + throw new AVMException("Should not be called."); + } + + // TODO The lPath argument is unnecessary. + /** + * Get the ContentData for this file. + * + * @return The ContentData object for this file. + */ + public ContentData getContentData(Lookup lPath) + { + Lookup lookup = lPath.getAVMStore().getAVMRepository().lookup(getUnderlyingVersion(lPath), getIndirection(), false); + if (lookup == null) + { + throw new AVMException("Invalid target."); + } + AVMNode node = lookup.getCurrentNode(); + if (!(node instanceof FileNode)) + { + throw new AVMException("Invalid target."); + } + FileNode file = (FileNode) node; + return file.getContentData(lookup); + } + + /* + * (non-Javadoc) + * + * @see org.alfresco.repo.avm.Layered#getUnderlyingVersion(org.alfresco.repo.avm.Lookup) + */ + public int getUnderlyingVersion(Lookup lookup) + { + if (lookup.getVersion() == -1) + { + return -1; + } + return fIndirectionVersion; + } + + /* + * (non-Javadoc) + * + * @see org.alfresco.repo.avm.LayeredFileNode#getIndirectionVersion() + */ + public Integer getIndirectionVersion() + { + return fIndirectionVersion; + } + + /* + * (non-Javadoc) + * + * @see org.alfresco.repo.avm.LayeredFileNode#setIndirectionVersion(int) + */ + public void setIndirectionVersion(Integer version) + { + if (version == null) + { + fIndirectionVersion = -1; + } + else + { + fIndirectionVersion = version; + } + } + + /* + * (non-Javadoc) + * + * @see org.alfresco.repo.avm.LayeredFileNode#copyLiterally(org.alfresco.repo.avm.Lookup) + */ + public LayeredFileNode copyLiterally(Lookup lookup) + { + // As far As I can tell this not used + DirectoryNode dir = lookup.getCurrentNodeDirectory(); + Long parentAclId = null; + if ((dir != null) && (dir.getAcl() != null)) + { + parentAclId = dir.getAcl().getId(); + } + return new LayeredFileNodeImpl(this, lookup.getAVMStore(), parentAclId, ACLCopyMode.COPY); + } +} diff --git a/source/java/org/alfresco/repo/avm/Lookup.java b/source/java/org/alfresco/repo/avm/Lookup.java index 36088d9198..679825cb5b 100644 --- a/source/java/org/alfresco/repo/avm/Lookup.java +++ b/source/java/org/alfresco/repo/avm/Lookup.java @@ -1,522 +1,539 @@ -/* - * 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.avm; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.alfresco.util.Pair; - -/** - * This holds all the information necessary to perform operations - * on AVMNodes, and is structured internally as a list of path components - * from the root directory of a repository. - * @author britt - */ -class Lookup implements Serializable -{ - private static final long serialVersionUID = -2844833688622561L; - - /** - * Is this lookup valid? - */ - private boolean fValid; - - /** - * The AVMStore. - */ - private AVMStore fAVMStore; - - /** - * The name of the AVMStore. - */ - private String fStoreName; - - /** - * The components that make up this path. - */ - private List fComponents; - - /** - * The final store in resolving layers. - */ - private AVMStore fFinalStore; - - /** - * Whether, at this point, a layered node has been hit. - * Used while building a Lookup. - */ - private boolean fLayeredYet; - - /** - * Whether we are directly contained at this point. - */ - private boolean fDirectlyContained; - - /** - * The first LayeredDirectoryNode in the path. - */ - private LayeredDirectoryNode fTopLayer; - - /** - * The path index of the top LayeredDirectoryNode in the path. - */ - private int fTopLayerIndex; - - /** - * The lowest layered directory node's index seen so far. - */ - private int fLowestLayerIndex; - - /** - * The current component being looked at by this lookup. - */ - private int fPosition; - - /** - * Whether a needs-to-be-copied component has been seen. - */ - private boolean fNeedsCopying; - - /** - * The version that is being looked up. - */ - private int fVersion; - - public Lookup(Lookup other, AVMNodeDAO nodeDAO, AVMStoreDAO storeDAO) - { - fValid = true; - fAVMStore = storeDAO.getByID(other.fAVMStore.getId()); - fVersion = other.fVersion; - if (fAVMStore == null) - { - fValid = false; - return; - } - fStoreName = fAVMStore.getName(); - fComponents = new ArrayList(); - fLayeredYet = other.fLayeredYet; - if (other.fTopLayer != null) - { - fTopLayer = (LayeredDirectoryNode)nodeDAO.getByID(other.fTopLayer.getId()); - if (fTopLayer == null) - { - fValid = false; - return; - } - } - fPosition = other.fPosition; - fTopLayerIndex = other.fTopLayerIndex; - fLowestLayerIndex = other.fLowestLayerIndex; - fNeedsCopying = other.fNeedsCopying; - fDirectlyContained = other.fDirectlyContained; - if (fLayeredYet) - { - for (LookupComponent comp : other.fComponents) - { - LookupComponent newComp = new LookupComponent(); - newComp.setName(comp.getName()); - newComp.setIndirection(comp.getIndirection()); - newComp.setIndirectionVersion(comp.getIndirectionVersion()); - newComp.setNode(nodeDAO.getByID(comp.getNode().getId())); - if (newComp.getNode() == null) - { - fValid = false; - return; - } - fComponents.add(newComp); - } - } - else - { - // If this is not a layered lookup then we do not - // need to reload any of the actual nodes except for - // the last. - int i = 0; - for (; i < fPosition; ++i) - { - LookupComponent comp = other.fComponents.get(i); - LookupComponent newComp = new LookupComponent(); - newComp.setName(comp.getName()); - fComponents.add(newComp); - } - LookupComponent comp = other.fComponents.get(i); - LookupComponent newComp = new LookupComponent(); - newComp.setName(comp.getName()); - newComp.setNode(nodeDAO.getByID(comp.getNode().getId())); - if (newComp.getNode() == null) - { - fValid = false; - return; - } - fComponents.add(newComp); - } - fFinalStore = storeDAO.getByID(other.fFinalStore.getId()); - if (fFinalStore == null) - { - fValid = false; - } - } - - /** - * Create a new one. - * @param store The AVMStore that's being looked in. - * @param storeName The name of that AVMStore. - */ - public Lookup(AVMStore store, String storeName, int version) - { - fValid = true; - fAVMStore = store; - fStoreName = storeName; - fVersion = version; - fComponents = new ArrayList(); - fLayeredYet = false; - fTopLayer = null; - fPosition = -1; - fTopLayerIndex = -1; - fLowestLayerIndex = -1; - fNeedsCopying = false; - fDirectlyContained = true; - fFinalStore = store; - } - - /** - * Is this a valid lookup? - */ - public boolean isValid() - { - return fValid; - } - - // TODO This is badly in need of cleanup. - /** - * Add a new node to the lookup. - * @param node The node to add. - * @param name The name of the node in the path. - * @param write Whether this is in the context of - * a write operation. - */ - public void add(AVMNode node, String name, boolean directlyContained, boolean write) - { - LookupComponent comp = new LookupComponent(); - comp.setName(name); - comp.setNode(node); - if (fPosition >= 0 && fDirectlyContained && - fComponents.get(fPosition).getNode().getType() == AVMNodeType.LAYERED_DIRECTORY) - { -// if (directlyContained != ((DirectoryNode)fComponents.get(fPosition).getNode()).directlyContains(node)) -// { -// System.err.println("Bloody Murder!"); -// } - fDirectlyContained = directlyContained; - } - if (!write) - { - if (node.getType() == AVMNodeType.LAYERED_DIRECTORY) - { - LayeredDirectoryNode oNode = (LayeredDirectoryNode)node; - if (oNode.getPrimaryIndirection()) - { - comp.setIndirection(oNode.getIndirection()); - comp.setIndirectionVersion(oNode.getIndirectionVersion()); - } - else - { - Pair ind = computeIndirection(name); - comp.setIndirection(ind.getFirst()); - comp.setIndirectionVersion(ind.getSecond()); - } - fLayeredYet = true; - // Record the first layer seen. - if (fTopLayer == null) - { - fTopLayer = oNode; - fTopLayerIndex = fPosition + 1; - } - fLowestLayerIndex = fPosition + 1; - } - fComponents.add(comp); - fPosition++; - return; - } - if (!node.getIsNew()) - { - fNeedsCopying = true; - } - else - { - if (fPosition >= 0 && !fDirectlyContained) - { - fNeedsCopying = true; - } - } - // Record various things if this is layered. - if (node.getType() == AVMNodeType.LAYERED_DIRECTORY) - { - LayeredDirectoryNode oNode = (LayeredDirectoryNode)node; - // Record the indirection path that should be used. - if (oNode.getPrimaryIndirection()) - { - comp.setIndirection(oNode.getIndirection()); - comp.setIndirectionVersion(-1); - } - else - { - Pair ind = computeIndirection(name); - comp.setIndirection(ind.getFirst()); - comp.setIndirectionVersion(-1); - } - fLayeredYet = true; - // Record the first layer seen. - if (fTopLayer == null) - { - fTopLayer = oNode; - fTopLayerIndex = fPosition + 1; - } - fLowestLayerIndex = fPosition + 1; - } - // In a write context a plain directory contained in a layer will - // be copied so we will need to compute an indirection path. - else if (fLayeredYet) - { - Pair ind = computeIndirection(name); - comp.setIndirection(ind.getFirst()); - comp.setIndirectionVersion(-1); - } - fComponents.add(comp); - fPosition++; - // If we are in a write context do copy on write. - if (fNeedsCopying) - { - node = node.copy(this); - // node.setVersionID(fAVMStore.getNextVersionID()); - fComponents.get(fPosition).setNode(node); - if (fPosition == 0) - { - // Inform the store of a new root. - fAVMStore.setNewRoot((DirectoryNode)node); - AVMDAOs.Instance().fAVMStoreDAO.update(fAVMStore); - return; - } - // Not the root. Check if we are the top layer and insert this into it's parent. - if (fPosition == fTopLayerIndex) - { - fTopLayer = (LayeredDirectoryNode)node; - } - ((DirectoryNode)fComponents.get(fPosition - 1).getNode()).putChild(name, node); - } - } - - /** - * A helper for keeping track of indirection. - * @param name The name of the being added node. - * @return The indirection for the being added node. - */ - private Pair computeIndirection(String name) - { - String parentIndirection = fComponents.get(fPosition).getIndirection(); - int parentIndirectionVersion = fComponents.get(fPosition).getIndirectionVersion(); - if (parentIndirection.endsWith("/")) - { - return new Pair(parentIndirection + name, parentIndirectionVersion); - } - else - { - return new Pair(parentIndirection + "/" + name, parentIndirectionVersion); - } - } - - /** - * Get the current node we're looking at. - * @return The current node. - */ - public AVMNode getCurrentNode() - { - return fComponents.get(fPosition).getNode(); - } - - /** - * Is the current path layered. - * @return Whether the current position in the path is layered. - */ - public boolean isLayered() - { - return fLayeredYet; - } - - /** - * Determine if a node is directly in this layer. - * @return Whether this node is directly in this layer. - */ - public boolean isInThisLayer() - { - return fLayeredYet && fDirectlyContained; - } - - /** - * Get the number of nodes. - * @return The number of nodes. - */ - public int size() - { - return fComponents.size(); - } - - /** - * Calculate the indirection path at this node. - * @return The indirection path all the way down to the current node. - */ - public String getIndirectionPath() - { - // The path is the underlying path of the lowest layer (in the path sense) - // that is directly contained by the top layer and is a primary indirection node. - int pos = fLowestLayerIndex; - AVMNode node = fComponents.get(pos).getNode(); - LayeredDirectoryNode oNode = null; - while (pos >= fTopLayerIndex && (node.getType() != AVMNodeType.LAYERED_DIRECTORY || - (oNode = (LayeredDirectoryNode)node).getLayerID() != fTopLayer.getLayerID() || - !oNode.getPrimaryIndirection())) - { - pos--; - node = fComponents.get(pos).getNode(); - } - oNode = (LayeredDirectoryNode)node; - // We've found it. - StringBuilder builder = new StringBuilder(); - builder.append(oNode.getIndirection()); - for (int i = pos + 1; i <= fPosition; i++) - { - builder.append("/"); - builder.append(fComponents.get(i).getName()); - } - return builder.toString(); - } - - /** - * Get the computed indirection for the current node. - * @return The indirection. - */ - public String getCurrentIndirection() - { - String value = fComponents.get(fPosition).getIndirection(); - return value; - } - - /** - * Get the computed indirection version for the current node. - * @return The indirection version. - */ - public int getCurrentIndirectionVersion() - { - return fComponents.get(fPosition).getIndirectionVersion(); - } - - /** - * Get the topmost Layered directory node. Topmost in the - * path lookup sense. - * @return The topmost layered directory node. - */ - public LayeredDirectoryNode getTopLayer() - { - return fTopLayer; - } - - /** - * Get the store that this path is in. - * @return The store. - */ - public AVMStore getAVMStore() - { - return fAVMStore; - } - - /** - * Get the path represented by this lookup. - * @return The canonical path for this lookup. - */ - public String getRepresentedPath() - { - if (fComponents.size() == 1) - { - return fStoreName + ":/"; - } - StringBuilder builder = new StringBuilder(); - builder.append(fStoreName); - builder.append(':'); - int count = fComponents.size(); - for (int i = 1; i < count; i++) - { - builder.append('/'); - builder.append(fComponents.get(i).getName()); - } - return builder.toString(); - } - - /** - * Gets the final name in the lookup. - * @return The final name in the lookup. - */ - public String getBaseName() - { - return fComponents.get(fPosition).getName(); - } - - /** - * Set the final store the lookup occurred in. - * @param store The store to set. - */ - public void setFinalStore(AVMStore store) - { - fFinalStore = store; - } - - /** - * Get the final store traversed during lookup. - * @return The final store traversed. - */ - public AVMStore getFinalStore() - { - return fFinalStore; - } - - /** - * Get whether the node looked up is directly contained from the - * original root. - * @return Whether the node looked up is directly contained. - */ - public boolean getDirectlyContained() - { - return fDirectlyContained; - } - - /** - * Get the version id that this is a lookup for. - * @return The version id. - */ - public int getVersion() - { - return fVersion; - } -} +/* + * 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.avm; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import org.alfresco.util.Pair; + +/** + * This holds all the information necessary to perform operations + * on AVMNodes, and is structured internally as a list of path components + * from the root directory of a repository. + * @author britt + */ +class Lookup implements Serializable +{ + private static final long serialVersionUID = -2844833688622561L; + + /** + * Is this lookup valid? + */ + private boolean fValid; + + /** + * The AVMStore. + */ + private AVMStore fAVMStore; + + /** + * The name of the AVMStore. + */ + private String fStoreName; + + /** + * The components that make up this path. + */ + private List fComponents; + + /** + * The final store in resolving layers. + */ + private AVMStore fFinalStore; + + /** + * Whether, at this point, a layered node has been hit. + * Used while building a Lookup. + */ + private boolean fLayeredYet; + + /** + * Whether we are directly contained at this point. + */ + private boolean fDirectlyContained; + + /** + * The first LayeredDirectoryNode in the path. + */ + private LayeredDirectoryNode fTopLayer; + + /** + * The path index of the top LayeredDirectoryNode in the path. + */ + private int fTopLayerIndex; + + /** + * The lowest layered directory node's index seen so far. + */ + private int fLowestLayerIndex; + + /** + * The current component being looked at by this lookup. + */ + private int fPosition; + + /** + * Whether a needs-to-be-copied component has been seen. + */ + private boolean fNeedsCopying; + + /** + * The version that is being looked up. + */ + private int fVersion; + + public Lookup(Lookup other, AVMNodeDAO nodeDAO, AVMStoreDAO storeDAO) + { + fValid = true; + fAVMStore = storeDAO.getByID(other.fAVMStore.getId()); + fVersion = other.fVersion; + if (fAVMStore == null) + { + fValid = false; + return; + } + fStoreName = fAVMStore.getName(); + fComponents = new ArrayList(); + fLayeredYet = other.fLayeredYet; + if (other.fTopLayer != null) + { + fTopLayer = (LayeredDirectoryNode)nodeDAO.getByID(other.fTopLayer.getId()); + if (fTopLayer == null) + { + fValid = false; + return; + } + } + fPosition = other.fPosition; + fTopLayerIndex = other.fTopLayerIndex; + fLowestLayerIndex = other.fLowestLayerIndex; + fNeedsCopying = other.fNeedsCopying; + fDirectlyContained = other.fDirectlyContained; + if (fLayeredYet) + { + for (LookupComponent comp : other.fComponents) + { + LookupComponent newComp = new LookupComponent(); + newComp.setName(comp.getName()); + newComp.setIndirection(comp.getIndirection()); + newComp.setIndirectionVersion(comp.getIndirectionVersion()); + newComp.setNode(nodeDAO.getByID(comp.getNode().getId())); + if (newComp.getNode() == null) + { + fValid = false; + return; + } + fComponents.add(newComp); + } + } + else + { + // If this is not a layered lookup then we do not + // need to reload any of the actual nodes except for + // the last. + int i = 0; + for (; i < fPosition; ++i) + { + LookupComponent comp = other.fComponents.get(i); + LookupComponent newComp = new LookupComponent(); + newComp.setName(comp.getName()); + fComponents.add(newComp); + } + LookupComponent comp = other.fComponents.get(i); + LookupComponent newComp = new LookupComponent(); + newComp.setName(comp.getName()); + newComp.setNode(nodeDAO.getByID(comp.getNode().getId())); + if (newComp.getNode() == null) + { + fValid = false; + return; + } + fComponents.add(newComp); + } + fFinalStore = storeDAO.getByID(other.fFinalStore.getId()); + if (fFinalStore == null) + { + fValid = false; + } + } + + /** + * Create a new one. + * @param store The AVMStore that's being looked in. + * @param storeName The name of that AVMStore. + */ + public Lookup(AVMStore store, String storeName, int version) + { + fValid = true; + fAVMStore = store; + fStoreName = storeName; + fVersion = version; + fComponents = new ArrayList(); + fLayeredYet = false; + fTopLayer = null; + fPosition = -1; + fTopLayerIndex = -1; + fLowestLayerIndex = -1; + fNeedsCopying = false; + fDirectlyContained = true; + fFinalStore = store; + } + + /** + * Is this a valid lookup? + */ + public boolean isValid() + { + return fValid; + } + + // TODO This is badly in need of cleanup. + /** + * Add a new node to the lookup. + * @param node The node to add. + * @param name The name of the node in the path. + * @param write Whether this is in the context of + * a write operation. + */ + public void add(AVMNode node, String name, boolean directlyContained, boolean write) + { + LookupComponent comp = new LookupComponent(); + comp.setName(name); + comp.setNode(node); + if (fPosition >= 0 && fDirectlyContained && + fComponents.get(fPosition).getNode().getType() == AVMNodeType.LAYERED_DIRECTORY) + { +// if (directlyContained != ((DirectoryNode)fComponents.get(fPosition).getNode()).directlyContains(node)) +// { +// System.err.println("Bloody Murder!"); +// } + fDirectlyContained = directlyContained; + } + if (!write) + { + if (node.getType() == AVMNodeType.LAYERED_DIRECTORY) + { + LayeredDirectoryNode oNode = (LayeredDirectoryNode)node; + if (oNode.getPrimaryIndirection()) + { + comp.setIndirection(oNode.getIndirection()); + comp.setIndirectionVersion(oNode.getIndirectionVersion()); + } + else + { + Pair ind = computeIndirection(name); + comp.setIndirection(ind.getFirst()); + comp.setIndirectionVersion(ind.getSecond()); + } + fLayeredYet = true; + // Record the first layer seen. + if (fTopLayer == null) + { + fTopLayer = oNode; + fTopLayerIndex = fPosition + 1; + } + fLowestLayerIndex = fPosition + 1; + } + fComponents.add(comp); + fPosition++; + return; + } + if (!node.getIsNew()) + { + fNeedsCopying = true; + } + else + { + if (fPosition >= 0 && !fDirectlyContained) + { + fNeedsCopying = true; + } + } + // Record various things if this is layered. + if (node.getType() == AVMNodeType.LAYERED_DIRECTORY) + { + LayeredDirectoryNode oNode = (LayeredDirectoryNode)node; + // Record the indirection path that should be used. + if (oNode.getPrimaryIndirection()) + { + comp.setIndirection(oNode.getIndirection()); + comp.setIndirectionVersion(-1); + } + else + { + Pair ind = computeIndirection(name); + comp.setIndirection(ind.getFirst()); + comp.setIndirectionVersion(-1); + } + fLayeredYet = true; + // Record the first layer seen. + if (fTopLayer == null) + { + fTopLayer = oNode; + fTopLayerIndex = fPosition + 1; + } + fLowestLayerIndex = fPosition + 1; + } + // In a write context a plain directory contained in a layer will + // be copied so we will need to compute an indirection path. + else if (fLayeredYet) + { + Pair ind = computeIndirection(name); + comp.setIndirection(ind.getFirst()); + comp.setIndirectionVersion(-1); + } + fComponents.add(comp); + fPosition++; + // If we are in a write context do copy on write. + if (fNeedsCopying) + { + node = node.copy(this); + // node.setVersionID(fAVMStore.getNextVersionID()); + fComponents.get(fPosition).setNode(node); + if (fPosition == 0) + { + // Inform the store of a new root. + fAVMStore.setNewRoot((DirectoryNode)node); + AVMDAOs.Instance().fAVMStoreDAO.update(fAVMStore); + return; + } + // Not the root. Check if we are the top layer and insert this into it's parent. + if (fPosition == fTopLayerIndex) + { + fTopLayer = (LayeredDirectoryNode)node; + } + ((DirectoryNode)fComponents.get(fPosition - 1).getNode()).putChild(name, node); + } + } + + /** + * A helper for keeping track of indirection. + * @param name The name of the being added node. + * @return The indirection for the being added node. + */ + private Pair computeIndirection(String name) + { + String parentIndirection = fComponents.get(fPosition).getIndirection(); + int parentIndirectionVersion = fComponents.get(fPosition).getIndirectionVersion(); + if (parentIndirection.endsWith("/")) + { + return new Pair(parentIndirection + name, parentIndirectionVersion); + } + else + { + return new Pair(parentIndirection + "/" + name, parentIndirectionVersion); + } + } + + /** + * Return the parent node of the current node in the look up context or null if there is not one yet + * @return + */ + public DirectoryNode getCurrentNodeDirectory() + { + int position = fPosition -1; + if( (position >= 0) && (position < fComponents.size())) + { + return ((DirectoryNode)fComponents.get(fPosition - 1).getNode()); + } + else + { + return null; + } + } + + /** + * Get the current node we're looking at. + * @return The current node. + */ + public AVMNode getCurrentNode() + { + return fComponents.get(fPosition).getNode(); + } + + /** + * Is the current path layered. + * @return Whether the current position in the path is layered. + */ + public boolean isLayered() + { + return fLayeredYet; + } + + /** + * Determine if a node is directly in this layer. + * @return Whether this node is directly in this layer. + */ + public boolean isInThisLayer() + { + return fLayeredYet && fDirectlyContained; + } + + /** + * Get the number of nodes. + * @return The number of nodes. + */ + public int size() + { + return fComponents.size(); + } + + /** + * Calculate the indirection path at this node. + * @return The indirection path all the way down to the current node. + */ + public String getIndirectionPath() + { + // The path is the underlying path of the lowest layer (in the path sense) + // that is directly contained by the top layer and is a primary indirection node. + int pos = fLowestLayerIndex; + AVMNode node = fComponents.get(pos).getNode(); + LayeredDirectoryNode oNode = null; + while (pos >= fTopLayerIndex && (node.getType() != AVMNodeType.LAYERED_DIRECTORY || + (oNode = (LayeredDirectoryNode)node).getLayerID() != fTopLayer.getLayerID() || + !oNode.getPrimaryIndirection())) + { + pos--; + node = fComponents.get(pos).getNode(); + } + oNode = (LayeredDirectoryNode)node; + // We've found it. + StringBuilder builder = new StringBuilder(); + builder.append(oNode.getIndirection()); + for (int i = pos + 1; i <= fPosition; i++) + { + builder.append("/"); + builder.append(fComponents.get(i).getName()); + } + return builder.toString(); + } + + /** + * Get the computed indirection for the current node. + * @return The indirection. + */ + public String getCurrentIndirection() + { + String value = fComponents.get(fPosition).getIndirection(); + return value; + } + + /** + * Get the computed indirection version for the current node. + * @return The indirection version. + */ + public int getCurrentIndirectionVersion() + { + return fComponents.get(fPosition).getIndirectionVersion(); + } + + /** + * Get the topmost Layered directory node. Topmost in the + * path lookup sense. + * @return The topmost layered directory node. + */ + public LayeredDirectoryNode getTopLayer() + { + return fTopLayer; + } + + /** + * Get the store that this path is in. + * @return The store. + */ + public AVMStore getAVMStore() + { + return fAVMStore; + } + + /** + * Get the path represented by this lookup. + * @return The canonical path for this lookup. + */ + public String getRepresentedPath() + { + if (fComponents.size() == 1) + { + return fStoreName + ":/"; + } + StringBuilder builder = new StringBuilder(); + builder.append(fStoreName); + builder.append(':'); + int count = fComponents.size(); + for (int i = 1; i < count; i++) + { + builder.append('/'); + builder.append(fComponents.get(i).getName()); + } + return builder.toString(); + } + + /** + * Gets the final name in the lookup. + * @return The final name in the lookup. + */ + public String getBaseName() + { + return fComponents.get(fPosition).getName(); + } + + /** + * Set the final store the lookup occurred in. + * @param store The store to set. + */ + public void setFinalStore(AVMStore store) + { + fFinalStore = store; + } + + /** + * Get the final store traversed during lookup. + * @return The final store traversed. + */ + public AVMStore getFinalStore() + { + return fFinalStore; + } + + /** + * Get whether the node looked up is directly contained from the + * original root. + * @return Whether the node looked up is directly contained. + */ + public boolean getDirectlyContained() + { + return fDirectlyContained; + } + + /** + * Get the version id that this is a lookup for. + * @return The version id. + */ + public int getVersion() + { + return fVersion; + } +} diff --git a/source/java/org/alfresco/repo/avm/OrphanReaper.java b/source/java/org/alfresco/repo/avm/OrphanReaper.java index 31efb7d23e..736eb0cb6a 100644 --- a/source/java/org/alfresco/repo/avm/OrphanReaper.java +++ b/source/java/org/alfresco/repo/avm/OrphanReaper.java @@ -1,352 +1,349 @@ -/* - * 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.avm; - -import java.util.LinkedList; -import java.util.List; - -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.transaction.TransactionService; +/* + * 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.avm; + +import java.util.LinkedList; +import java.util.List; + +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.transaction.TransactionService; import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.SessionFactory; -import org.springframework.orm.hibernate3.HibernateTemplate; - -/** - * This is the background thread for reaping no longer referenced nodes - * in the AVM repository. These orphans arise from purge operations. - * @author britt - */ -public class OrphanReaper -{ - public void execute() - { - synchronized (this) - { - if (fRunning) - { - return; - } - fRunning = true; - } - try - { - do - { - doBatch(); - if (fDone) - { - return; - } - try - { - Thread.sleep(fActiveBaseSleep); - } - catch (InterruptedException e) - { - // Do nothing. - } - } while (fActive); - } - finally - { - synchronized (this) - { - fRunning = false; - } - } - } - - private Log fgLogger = LogFactory.getLog(OrphanReaper.class); - - /** - * The Transaction Service - */ - private TransactionService fTransactionService; - - /** - * The Session Factory - */ - private SessionFactory fSessionFactory; - - /** - * Active base sleep interval. - */ - private long fActiveBaseSleep; - - /** - * Batch size. - */ - private int fBatchSize; - - /** - * Whether we are currently active, ie have - * work queued up. - */ - private boolean fActive; - - /** - * The maximum length of the queue. - */ - private int fQueueLength; - - /** - * The linked list containing ids of nodes that are purgable. - */ - private LinkedList fPurgeQueue; - - private boolean fDone = false; - - private boolean fRunning = false; - - /** - * Create one with default parameters. - */ - public OrphanReaper() - { - fActiveBaseSleep = 1000; - fBatchSize = 50; - fQueueLength = 1000; - fActive = false; - } - - // Setters for configuration. - - /** - * Set the active base sleep interval. - * @param interval The interval to set in ms. - */ - public void setActiveBaseSleep(long interval) - { - fActiveBaseSleep = interval; - } - - /** - * Set the batch size. - * @param size The batch size to set. - */ - public void setBatchSize(int size) - { - fBatchSize = size; - } - - /** - * Set the transaction service. - * @param transactionService The service. - */ - public void setTransactionService(TransactionService transactionService) - { - 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. - * @param queueLength The max length. - */ - public void setMaxQueueLength(int queueLength) - { - fQueueLength = queueLength; - } - - /** - * Start things up after configuration is complete. - */ -// public void init() -// { -// fThread = new Thread(this); -// fThread.start(); -// } - - /** - * Shutdown the reaper. This needs to be called when - * the application shuts down. - */ - public void shutDown() - { - fDone = true; - } - - /** - * Sit in a loop, periodically querying for orphans. When orphans - * are found, unhook them in bite sized batches. - */ -// public void run() -// { -// while (!fDone) -// { -// synchronized (this) -// { -// try -// { -// wait(fActive? fActiveBaseSleep : fInactiveBaseSleep); -// } -// catch (InterruptedException ie) -// { -// // Do nothing. -// } -// doBatch(); -// } -// } -// } - - /** - * This is really for debugging and testing. Allows another thread to - * mark the orphan reaper busy so that it can monitor for it's being done. - */ - public void activate() - { - fActive = true; - } - - /** - * See if the reaper is actively reaping. - * @return Whether this is actively reaping. - */ - public boolean isActive() - { - return fActive; - } - - /** - * Do a batch of cleanup work. - */ - public void doBatch() - { - class TxnWork implements RetryingTransactionCallback - { - public Object execute() - throws Exception - { - if (fPurgeQueue == null) - { - List nodes = AVMDAOs.Instance().fAVMNodeDAO.getOrphans(fQueueLength); - if (nodes.size() == 0) - { - fActive = false; - return null; - } - fPurgeQueue = new LinkedList(); - for (AVMNode node : nodes) - { - fPurgeQueue.add(node.getId()); - } - } - fActive = true; - for (int i = 0; i < fBatchSize; i++) - { - if (fPurgeQueue.size() == 0) - { - fPurgeQueue = null; - return null; - } - AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(fPurgeQueue.removeFirst()); - // Save away the ancestor and merged from fields from this node. - HistoryLink hlink = AVMDAOs.Instance().fHistoryLinkDAO.getByDescendent(node); - AVMNode ancestor = null; - if (hlink != null) - { - ancestor = hlink.getAncestor(); - AVMDAOs.Instance().fHistoryLinkDAO.delete(hlink); - } - MergeLink mlink = AVMDAOs.Instance().fMergeLinkDAO.getByTo(node); - AVMNode mergedFrom = null; - if (mlink != null) - { - mergedFrom = mlink.getMfrom(); - AVMDAOs.Instance().fMergeLinkDAO.delete(mlink); - } - AVMDAOs.Instance().fAVMNodeDAO.flush(); - // Get all the nodes that have this node as ancestor. - List links = AVMDAOs.Instance().fHistoryLinkDAO.getByAncestor(node); - for (HistoryLink link : links) - { - AVMNode desc = link.getDescendent(); - desc.setAncestor(ancestor); - if (desc.getMergedFrom() == null) - { - desc.setMergedFrom(mergedFrom); - } - AVMDAOs.Instance().fHistoryLinkDAO.delete(link); - } - // Get all the nodes that have this node as mergedFrom - List mlinks = AVMDAOs.Instance().fMergeLinkDAO.getByFrom(node); - for (MergeLink link : mlinks) - { - link.getMto().setMergedFrom(ancestor); - AVMDAOs.Instance().fMergeLinkDAO.delete(link); - } - // Get rid of all properties belonging to this node. - // AVMDAOs.Instance().fAVMNodePropertyDAO.deleteAll(node); - // Get rid of all aspects belonging to this node. -// AVMDAOs.Instance().fAVMAspectNameDAO.delete(node); - // Get rid of ACL. - DbAccessControlList acl = node.getAcl(); - node.setAcl(null); - if (acl != null) - { - acl.deleteEntries(); - (new HibernateTemplate(fSessionFactory)).delete(acl); - } - // Extra work for directories. - if (node.getType() == AVMNodeType.PLAIN_DIRECTORY || - node.getType() == AVMNodeType.LAYERED_DIRECTORY) - { - // First get rid of all child entries for the node. - AVMDAOs.Instance().fChildEntryDAO.deleteByParent(node); - } - // This is not on, since content urls can be shared. -// else if (node.getType() == AVMNodeType.PLAIN_FILE) -// { -// PlainFileNode file = (PlainFileNode)node; -// String url = file.getContentData(null).getContentUrl(); -// if (url != null) -// { -// RawServices.Instance().getContentStore().delete(url); -// } -// } - AVMDAOs.Instance().fAVMNodeDAO.delete(node); - } - return null; - } - } - try - { - fTransactionService.getRetryingTransactionHelper().doInTransaction(new TxnWork()); - } - catch (Exception e) - { - fgLogger.error("Garbage collector error", e); - } - } -} +import org.apache.commons.logging.LogFactory; +import org.hibernate.SessionFactory; +import org.springframework.orm.hibernate3.HibernateTemplate; + +/** + * This is the background thread for reaping no longer referenced nodes + * in the AVM repository. These orphans arise from purge operations. + * @author britt + */ +public class OrphanReaper +{ + public void execute() + { + synchronized (this) + { + if (fRunning) + { + return; + } + fRunning = true; + } + try + { + do + { + doBatch(); + if (fDone) + { + return; + } + try + { + Thread.sleep(fActiveBaseSleep); + } + catch (InterruptedException e) + { + // Do nothing. + } + } while (fActive); + } + finally + { + synchronized (this) + { + fRunning = false; + } + } + } + + private Log fgLogger = LogFactory.getLog(OrphanReaper.class); + + /** + * The Transaction Service + */ + private TransactionService fTransactionService; + + /** + * The Session Factory + */ + private SessionFactory fSessionFactory; + + /** + * Active base sleep interval. + */ + private long fActiveBaseSleep; + + /** + * Batch size. + */ + private int fBatchSize; + + /** + * Whether we are currently active, ie have + * work queued up. + */ + private boolean fActive; + + /** + * The maximum length of the queue. + */ + private int fQueueLength; + + /** + * The linked list containing ids of nodes that are purgable. + */ + private LinkedList fPurgeQueue; + + private boolean fDone = false; + + private boolean fRunning = false; + + /** + * Create one with default parameters. + */ + public OrphanReaper() + { + fActiveBaseSleep = 1000; + fBatchSize = 50; + fQueueLength = 1000; + fActive = false; + } + + // Setters for configuration. + + /** + * Set the active base sleep interval. + * @param interval The interval to set in ms. + */ + public void setActiveBaseSleep(long interval) + { + fActiveBaseSleep = interval; + } + + /** + * Set the batch size. + * @param size The batch size to set. + */ + public void setBatchSize(int size) + { + fBatchSize = size; + } + + /** + * Set the transaction service. + * @param transactionService The service. + */ + public void setTransactionService(TransactionService transactionService) + { + 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. + * @param queueLength The max length. + */ + public void setMaxQueueLength(int queueLength) + { + fQueueLength = queueLength; + } + + /** + * Start things up after configuration is complete. + */ +// public void init() +// { +// fThread = new Thread(this); +// fThread.start(); +// } + + /** + * Shutdown the reaper. This needs to be called when + * the application shuts down. + */ + public void shutDown() + { + fDone = true; + } + + /** + * Sit in a loop, periodically querying for orphans. When orphans + * are found, unhook them in bite sized batches. + */ +// public void run() +// { +// while (!fDone) +// { +// synchronized (this) +// { +// try +// { +// wait(fActive? fActiveBaseSleep : fInactiveBaseSleep); +// } +// catch (InterruptedException ie) +// { +// // Do nothing. +// } +// doBatch(); +// } +// } +// } + + /** + * This is really for debugging and testing. Allows another thread to + * mark the orphan reaper busy so that it can monitor for it's being done. + */ + public void activate() + { + fActive = true; + } + + /** + * See if the reaper is actively reaping. + * @return Whether this is actively reaping. + */ + public boolean isActive() + { + return fActive; + } + + /** + * Do a batch of cleanup work. + */ + public void doBatch() + { + class TxnWork implements RetryingTransactionCallback + { + public Object execute() + throws Exception + { + if (fPurgeQueue == null) + { + List nodes = AVMDAOs.Instance().fAVMNodeDAO.getOrphans(fQueueLength); + if (nodes.size() == 0) + { + fActive = false; + return null; + } + fPurgeQueue = new LinkedList(); + for (AVMNode node : nodes) + { + fPurgeQueue.add(node.getId()); + } + } + fActive = true; + for (int i = 0; i < fBatchSize; i++) + { + if (fPurgeQueue.size() == 0) + { + fPurgeQueue = null; + return null; + } + AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(fPurgeQueue.removeFirst()); + // Save away the ancestor and merged from fields from this node. + HistoryLink hlink = AVMDAOs.Instance().fHistoryLinkDAO.getByDescendent(node); + AVMNode ancestor = null; + if (hlink != null) + { + ancestor = hlink.getAncestor(); + AVMDAOs.Instance().fHistoryLinkDAO.delete(hlink); + } + MergeLink mlink = AVMDAOs.Instance().fMergeLinkDAO.getByTo(node); + AVMNode mergedFrom = null; + if (mlink != null) + { + mergedFrom = mlink.getMfrom(); + AVMDAOs.Instance().fMergeLinkDAO.delete(mlink); + } + AVMDAOs.Instance().fAVMNodeDAO.flush(); + // Get all the nodes that have this node as ancestor. + List links = AVMDAOs.Instance().fHistoryLinkDAO.getByAncestor(node); + for (HistoryLink link : links) + { + AVMNode desc = link.getDescendent(); + desc.setAncestor(ancestor); + if (desc.getMergedFrom() == null) + { + desc.setMergedFrom(mergedFrom); + } + AVMDAOs.Instance().fHistoryLinkDAO.delete(link); + } + // Get all the nodes that have this node as mergedFrom + List mlinks = AVMDAOs.Instance().fMergeLinkDAO.getByFrom(node); + for (MergeLink link : mlinks) + { + link.getMto().setMergedFrom(ancestor); + AVMDAOs.Instance().fMergeLinkDAO.delete(link); + } + // Get rid of all properties belonging to this node. + // AVMDAOs.Instance().fAVMNodePropertyDAO.deleteAll(node); + // Get rid of all aspects belonging to this node. +// AVMDAOs.Instance().fAVMAspectNameDAO.delete(node); + // Get rid of ACL. + DbAccessControlList acl = node.getAcl(); + node.setAcl(null); + // Unused acls will be garbage collected + // Many acls will be shared + // Extra work for directories. + if (node.getType() == AVMNodeType.PLAIN_DIRECTORY || + node.getType() == AVMNodeType.LAYERED_DIRECTORY) + { + // First get rid of all child entries for the node. + AVMDAOs.Instance().fChildEntryDAO.deleteByParent(node); + } + // This is not on, since content urls can be shared. +// else if (node.getType() == AVMNodeType.PLAIN_FILE) +// { +// PlainFileNode file = (PlainFileNode)node; +// String url = file.getContentData(null).getContentUrl(); +// if (url != null) +// { +// RawServices.Instance().getContentStore().delete(url); +// } +// } + AVMDAOs.Instance().fAVMNodeDAO.delete(node); + } + return null; + } + } + try + { + fTransactionService.getRetryingTransactionHelper().doInTransaction(new TxnWork()); + } + catch (Exception e) + { + fgLogger.error("Garbage collector error", e); + } + } +} diff --git a/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java index 50025827fe..bddf7a4dbd 100644 --- a/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java @@ -1,519 +1,528 @@ -/* - * 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.avm; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.SortedMap; -import java.util.TreeMap; - -import org.alfresco.service.cmr.avm.AVMBadArgumentException; -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.security.PermissionService; -import org.alfresco.util.Pair; - -/** - * A plain directory. No monkey tricks except for possiblyCopy. - * @author britt - */ -class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectoryNode -{ - static final long serialVersionUID = 9423813734583003L; - - /** - * Make up a new directory with nothing in it. - * @param store - */ - public PlainDirectoryNodeImpl(AVMStore store) - { - super(store.getAVMRepository().issueID(), store); - setVersionID(1); - AVMDAOs.Instance().fAVMNodeDAO.save(this); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - } - - /** - * Anonymous constructor. - */ - protected PlainDirectoryNodeImpl() - { - } - - /** - * Copy like constructor. - * @param other The other directory. - * @param repos The AVMStore Object that will own us. - */ - @SuppressWarnings("unchecked") - public PlainDirectoryNodeImpl(PlainDirectoryNode other, - AVMStore store) - { - super(store.getAVMRepository().issueID(), store); - AVMDAOs.Instance().fAVMNodeDAO.save(this); - for (ChildEntry child : AVMDAOs.Instance().fChildEntryDAO.getByParent(other)) - { - ChildKey key = new ChildKey(this, child.getKey().getName()); - ChildEntry newChild = new ChildEntryImpl(key, - child.getChild()); - AVMDAOs.Instance().fChildEntryDAO.save(newChild); - } - setVersionID(other.getVersionID() + 1); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - copyProperties(other); - copyAspects(other); - copyACLs(other); - } - - /** - * Does this directory directly contain the given node. - * @param node The node to check. - * @return Whether it was found. - */ - public boolean directlyContains(AVMNode node) - { - return AVMDAOs.Instance().fChildEntryDAO.getByParentChild(this, node) != null; - } - - /** - * Get a directory listing. - * @param lPath The lookup path. - * @return The listing. - */ - @SuppressWarnings("unchecked") - public Map getListing(Lookup lPath, boolean includeDeleted) - { - Map result = new HashMap(); - List children = AVMDAOs.Instance().fChildEntryDAO.getByParent(this); - for (ChildEntry child : children) - { - if (child.getChild().getType() == AVMNodeType.LAYERED_DIRECTORY || - child.getChild().getType() == AVMNodeType.PLAIN_DIRECTORY) - { - if (!AVMRepository.GetInstance().can(child.getChild(), PermissionService.READ_CHILDREN)) - { - continue; - } - } - if (!includeDeleted && child.getChild().getType() == AVMNodeType.DELETED_NODE) - { - continue; - } - result.put(child.getKey().getName(), AVMNodeUnwrapper.Unwrap(child.getChild())); - } - return result; - } - - /** - * Get a listing of the nodes directly contained by a directory. - * @param lPath The Lookup to this directory. - * @return A Map of names to nodes. - */ - public Map getListingDirect(Lookup lPath, boolean includeDeleted) - { - return getListing(lPath, includeDeleted); - } - - /** - * Get a listing of the nodes directly contained by a directory. - * @param dir The node's descriptor. - * @param includeDeleted Whether to include deleted nodes. - * @return A Map of Strings to descriptors. - */ - public SortedMap getListingDirect(AVMNodeDescriptor dir, - boolean includeDeleted) - { - return getListing(dir, includeDeleted); - } - - /** - * Get a listing of from a directory node descriptor. - * @param dir The directory node descriptor. - * @return A Map of names to node descriptors. - */ - public SortedMap getListing(AVMNodeDescriptor dir, boolean includeDeleted) - { - if (dir.getPath() == null) - { - throw new AVMBadArgumentException("Path is null."); - } - SortedMap result = new TreeMap(); - List children = AVMDAOs.Instance().fChildEntryDAO.getByParent(this); - for (ChildEntry child : children) - { - if (child.getChild().getType() == AVMNodeType.LAYERED_DIRECTORY || - child.getChild().getType() == AVMNodeType.PLAIN_DIRECTORY) - { - if (!AVMRepository.GetInstance().can(child.getChild(), PermissionService.READ_CHILDREN)) - { - continue; - } - } - if (!includeDeleted && child.getChild().getType() == AVMNodeType.DELETED_NODE) - { - continue; - } - result.put(child.getKey().getName(), - child.getChild().getDescriptor(dir.getPath(), - child.getKey().getName(), - dir.getIndirection(), - dir.getIndirectionVersion())); - } - return result; - } - - /** - * Get the names of nodes deleted in this directory. - * @return A List of names. - */ - public List getDeletedNames() - { - return new ArrayList(); - } - - /** - * Lookup a child by name. - * @param lPath The lookup path so far. - * @param name The name to lookup. - * @param includeDeleted Whether to lookup deleted nodes. - * @return The child or null. - */ - @SuppressWarnings("unchecked") - public Pair lookupChild(Lookup lPath, String name, boolean includeDeleted) - { - ChildKey key = new ChildKey(this, name); - ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); - if (entry == null) - { - return null; - } - if (!includeDeleted && entry.getChild().getType() == AVMNodeType.DELETED_NODE) - { - return null; - } - // We're doing the hand unrolling of the proxy because - // Hibernate/CGLIB proxies are broken. - - Pair result = new Pair(AVMNodeUnwrapper.Unwrap(entry.getChild()), true); - return result; - } - - /** - * Lookup a child using a node descriptor as context. - * @param mine The node descriptor for this. - * @param name The name of the child to lookup. - * @return A node descriptor for the child. - */ - public AVMNodeDescriptor lookupChild(AVMNodeDescriptor mine, String name, boolean includeDeleted) - { - if (mine.getPath() == null) - { - throw new AVMBadArgumentException("Path is null."); - } - ChildKey key = new ChildKey(this, name); - ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); - if (entry == null || - (!includeDeleted && entry.getChild().getType() == AVMNodeType.DELETED_NODE)) - { - return null; - } - AVMNodeDescriptor desc = entry.getChild().getDescriptor(mine.getPath(), name, (String)null, -1); - return desc; - } - - /** - * Remove a child, no copying. - * @param lPath The path by which this was found. - * @param name The name of the child to remove. - */ - @SuppressWarnings("unchecked") - public void removeChild(Lookup lPath, String name) - { - if (DEBUG) - { - checkReadOnly(); - } - ChildKey key = new ChildKey(this, name); - ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); - if (entry != null) - { - AVMNode child = entry.getChild(); - if (child.getType() == AVMNodeType.DELETED_NODE) - { - return; - } - AVMDAOs.Instance().fChildEntryDAO.delete(entry); - if (child.getStoreNew() == null || child.getAncestor() != null) - { - DeletedNodeImpl ghost = new DeletedNodeImpl(lPath.getAVMStore().getAVMRepository().issueID(), - lPath.getAVMStore()); - AVMDAOs.Instance().fAVMNodeDAO.save(ghost); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - ghost.setAncestor(child); - ghost.setDeletedType(child.getType()); - putChild(name, ghost); - } - else - { - AVMDAOs.Instance().fAVMNodeDAO.flush(); - } - } - } - - /** - * Put a new child node into this directory. No copy. - * @param name The name of the child. - * @param node The node to add. - */ - public void putChild(String name, AVMNode node) - { - if (DEBUG) - { - checkReadOnly(); - } - ChildKey key = new ChildKey(this, name); - ChildEntry existing = AVMDAOs.Instance().fChildEntryDAO.get(key); - if (existing != null) - { - AVMDAOs.Instance().fChildEntryDAO.delete(existing); - } - ChildEntry entry = new ChildEntryImpl(key, node); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - AVMDAOs.Instance().fChildEntryDAO.save(entry); - } - - /** - * Copy on write logic. - * @param lPath The lookup path. - * @return A brand new copied version. - */ - public AVMNode copy(Lookup lPath) - { - DirectoryNode newMe = null; - // In a layered context a copy on write creates a new - // layered directory. - if (lPath.isLayered()) - { - // Subtlety warning: This distinguishes the case of a - // Directory that was branched into the layer and one - // that is indirectly seen in this layer. - newMe = new LayeredDirectoryNodeImpl(this, lPath.getAVMStore(), lPath, - lPath.isInThisLayer()); - ((LayeredDirectoryNodeImpl)newMe).setLayerID(lPath.getTopLayer().getLayerID()); - } - else - { - newMe = new PlainDirectoryNodeImpl(this, lPath.getAVMStore()); - } - newMe.setAncestor(this); - return newMe; - } - - /** - * Get the type of this node. - * @return The type of this node. - */ - public int getType() - { - return AVMNodeType.PLAIN_DIRECTORY; - } - - /** - * Get a diagnostic String representation. - * @param lPath The Lookup. - * @return A diagnostic String representation. - */ - public String toString(Lookup lPath) - { - return "[PD:" + getId() + "]"; - } - - /** - * Turn this into a primary indirection. This must be in a - * layered context. - * @param lPath The Lookup. - */ - public void turnPrimary(Lookup lPath) - { - assert false : "Should never happen."; - } - - /** - * Retarget this directory. lPath must be in a layered context. - * @param lPath The Lookup. - * @param target The target path. - */ - public void retarget(Lookup lPath, String target) - { - assert false : "Should never happen."; - } - - /** - * Get the descriptor for this node. - * @param lPath The Lookup. - * @param name The name of this node in this context. - * @return A descriptor. - */ - public AVMNodeDescriptor getDescriptor(Lookup lPath, String name) - { - BasicAttributes attrs = getBasicAttributes(); - String path = lPath.getRepresentedPath(); - if (path.endsWith("/")) - { - path = path + name; - } - else - { - path = path + "/" + name; - } - return new AVMNodeDescriptor(path, - name, - AVMNodeType.PLAIN_DIRECTORY, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - null, - -1, - false, - -1, - false, - -1, - -1); - } - - /** - * Get the descriptor for this node. - * @param lPath The Lookup. - * @return A descriptor. - */ - public AVMNodeDescriptor getDescriptor(Lookup lPath) - { - BasicAttributes attrs = getBasicAttributes(); - String path = lPath.getRepresentedPath(); - return new AVMNodeDescriptor(path, - path.substring(path.lastIndexOf("/") + 1), - AVMNodeType.PLAIN_DIRECTORY, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - null, - -1, - false, - -1, - false, - -1, - -1); - } - - /** - * Get this node's descriptor. - * @param parentPath The parent path. - * @param name The name that we were looked up under. - * @param parentIndirection The parent indirection. - * @return This node's node descriptor - */ - public AVMNodeDescriptor getDescriptor(String parentPath, String name, String parentIndirection, int parentIndirectionVersion) - { - BasicAttributes attrs = getBasicAttributes(); - String path = parentPath.endsWith("/") ? parentPath + name : parentPath + "/" + name; - return new AVMNodeDescriptor(path, - name, - AVMNodeType.PLAIN_DIRECTORY, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - null, - -1, - false, - -1, - false, - -1, - -1); - } - - /** - * Link a node with the given id into this directory. - * @param lPath The Lookup for this directory. - * @param name The name to give the node. - * @param toLink The node to link in. - */ - public void link(Lookup lPath, String name, AVMNodeDescriptor toLink) - { - if (DEBUG) - { - checkReadOnly(); - } - // Assure that the incoming node exists. - AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(toLink.getId()); - if (node == null) - { - throw new AVMNotFoundException("Node not found: " + toLink.getId()); - } - if (node.getType() == AVMNodeType.LAYERED_DIRECTORY && - !((LayeredDirectoryNode)node).getPrimaryIndirection()) - { - throw new AVMBadArgumentException("Non primary layered directories cannot be linked."); - } - // Check for an existing child by the given name. - ChildKey key = new ChildKey(this, name); - ChildEntry child = AVMDAOs.Instance().fChildEntryDAO.get(key); - if (child != null) - { - if (child.getChild().getType() != AVMNodeType.DELETED_NODE) - { - // It's an error if there is a non DELETED_NODE child. - throw new AVMExistsException(name + " exists."); - } - // Get rid of the DELETED_NODE child. - AVMDAOs.Instance().fChildEntryDAO.delete(child); - // Another &*#*&#$ flush. - AVMDAOs.Instance().fAVMNodeDAO.flush(); - } - // Make the new entry and save. - ChildEntry newChild = new ChildEntryImpl(key, node); - AVMDAOs.Instance().fChildEntryDAO.save(newChild); - } -} - +/* + * 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.avm; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.security.permissions.ACLCopyMode; +import org.alfresco.service.cmr.avm.AVMBadArgumentException; +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.security.PermissionService; +import org.alfresco.util.Pair; + +/** + * A plain directory. No monkey tricks except for possiblyCopy. + * @author britt + */ +class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectoryNode +{ + static final long serialVersionUID = 9423813734583003L; + + /** + * Make up a new directory with nothing in it. + * @param store + */ + public PlainDirectoryNodeImpl(AVMStore store) + { + super(store.getAVMRepository().issueID(), store); + setVersionID(1); + AVMDAOs.Instance().fAVMNodeDAO.save(this); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + } + + /** + * Anonymous constructor. + */ + protected PlainDirectoryNodeImpl() + { + } + + /** + * Copy like constructor. + * @param other The other directory. + * @param repos The AVMStore Object that will own us. + */ + @SuppressWarnings("unchecked") + public PlainDirectoryNodeImpl(PlainDirectoryNode other, + AVMStore store, Long parentAcl, ACLCopyMode mode) + { + super(store.getAVMRepository().issueID(), store); + AVMDAOs.Instance().fAVMNodeDAO.save(this); + for (ChildEntry child : AVMDAOs.Instance().fChildEntryDAO.getByParent(other)) + { + ChildKey key = new ChildKey(this, child.getKey().getName()); + ChildEntry newChild = new ChildEntryImpl(key, + child.getChild()); + AVMDAOs.Instance().fChildEntryDAO.save(newChild); + } + setVersionID(other.getVersionID() + 1); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + copyProperties(other); + copyAspects(other); + copyACLs(other, parentAcl, mode); + } + + /** + * Does this directory directly contain the given node. + * @param node The node to check. + * @return Whether it was found. + */ + public boolean directlyContains(AVMNode node) + { + return AVMDAOs.Instance().fChildEntryDAO.getByParentChild(this, node) != null; + } + + /** + * Get a directory listing. + * @param lPath The lookup path. + * @return The listing. + */ + @SuppressWarnings("unchecked") + public Map getListing(Lookup lPath, boolean includeDeleted) + { + Map result = new HashMap(); + List children = AVMDAOs.Instance().fChildEntryDAO.getByParent(this); + for (ChildEntry child : children) + { + if (child.getChild().getType() == AVMNodeType.LAYERED_DIRECTORY || + child.getChild().getType() == AVMNodeType.PLAIN_DIRECTORY) + { + if (!AVMRepository.GetInstance().can(child.getChild(), PermissionService.READ_CHILDREN)) + { + continue; + } + } + if (!includeDeleted && child.getChild().getType() == AVMNodeType.DELETED_NODE) + { + continue; + } + result.put(child.getKey().getName(), AVMNodeUnwrapper.Unwrap(child.getChild())); + } + return result; + } + + /** + * Get a listing of the nodes directly contained by a directory. + * @param lPath The Lookup to this directory. + * @return A Map of names to nodes. + */ + public Map getListingDirect(Lookup lPath, boolean includeDeleted) + { + return getListing(lPath, includeDeleted); + } + + /** + * Get a listing of the nodes directly contained by a directory. + * @param dir The node's descriptor. + * @param includeDeleted Whether to include deleted nodes. + * @return A Map of Strings to descriptors. + */ + public SortedMap getListingDirect(AVMNodeDescriptor dir, + boolean includeDeleted) + { + return getListing(dir, includeDeleted); + } + + /** + * Get a listing of from a directory node descriptor. + * @param dir The directory node descriptor. + * @return A Map of names to node descriptors. + */ + public SortedMap getListing(AVMNodeDescriptor dir, boolean includeDeleted) + { + if (dir.getPath() == null) + { + throw new AVMBadArgumentException("Path is null."); + } + SortedMap result = new TreeMap(); + List children = AVMDAOs.Instance().fChildEntryDAO.getByParent(this); + for (ChildEntry child : children) + { + if (child.getChild().getType() == AVMNodeType.LAYERED_DIRECTORY || + child.getChild().getType() == AVMNodeType.PLAIN_DIRECTORY) + { + if (!AVMRepository.GetInstance().can(child.getChild(), PermissionService.READ_CHILDREN)) + { + continue; + } + } + if (!includeDeleted && child.getChild().getType() == AVMNodeType.DELETED_NODE) + { + continue; + } + result.put(child.getKey().getName(), + child.getChild().getDescriptor(dir.getPath(), + child.getKey().getName(), + dir.getIndirection(), + dir.getIndirectionVersion())); + } + return result; + } + + /** + * Get the names of nodes deleted in this directory. + * @return A List of names. + */ + public List getDeletedNames() + { + return new ArrayList(); + } + + /** + * Lookup a child by name. + * @param lPath The lookup path so far. + * @param name The name to lookup. + * @param includeDeleted Whether to lookup deleted nodes. + * @return The child or null. + */ + @SuppressWarnings("unchecked") + public Pair lookupChild(Lookup lPath, String name, boolean includeDeleted) + { + ChildKey key = new ChildKey(this, name); + ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); + if (entry == null) + { + return null; + } + if (!includeDeleted && entry.getChild().getType() == AVMNodeType.DELETED_NODE) + { + return null; + } + // We're doing the hand unrolling of the proxy because + // Hibernate/CGLIB proxies are broken. + + Pair result = new Pair(AVMNodeUnwrapper.Unwrap(entry.getChild()), true); + return result; + } + + /** + * Lookup a child using a node descriptor as context. + * @param mine The node descriptor for this. + * @param name The name of the child to lookup. + * @return A node descriptor for the child. + */ + public AVMNodeDescriptor lookupChild(AVMNodeDescriptor mine, String name, boolean includeDeleted) + { + if (mine.getPath() == null) + { + throw new AVMBadArgumentException("Path is null."); + } + ChildKey key = new ChildKey(this, name); + ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); + if (entry == null || + (!includeDeleted && entry.getChild().getType() == AVMNodeType.DELETED_NODE)) + { + return null; + } + AVMNodeDescriptor desc = entry.getChild().getDescriptor(mine.getPath(), name, (String)null, -1); + return desc; + } + + /** + * Remove a child, no copying. + * @param lPath The path by which this was found. + * @param name The name of the child to remove. + */ + @SuppressWarnings("unchecked") + public void removeChild(Lookup lPath, String name) + { + if (DEBUG) + { + checkReadOnly(); + } + ChildKey key = new ChildKey(this, name); + ChildEntry entry = AVMDAOs.Instance().fChildEntryDAO.get(key); + if (entry != null) + { + AVMNode child = entry.getChild(); + if (child.getType() == AVMNodeType.DELETED_NODE) + { + return; + } + AVMDAOs.Instance().fChildEntryDAO.delete(entry); + if (child.getStoreNew() == null || child.getAncestor() != null) + { + DeletedNodeImpl ghost = new DeletedNodeImpl(lPath.getAVMStore().getAVMRepository().issueID(), + lPath.getAVMStore(), child.getAcl()); + AVMDAOs.Instance().fAVMNodeDAO.save(ghost); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + ghost.setAncestor(child); + ghost.setDeletedType(child.getType()); + putChild(name, ghost); + } + else + { + AVMDAOs.Instance().fAVMNodeDAO.flush(); + } + } + } + + /** + * Put a new child node into this directory. No copy. + * @param name The name of the child. + * @param node The node to add. + */ + public void putChild(String name, AVMNode node) + { + if (DEBUG) + { + checkReadOnly(); + } + ChildKey key = new ChildKey(this, name); + ChildEntry existing = AVMDAOs.Instance().fChildEntryDAO.get(key); + if (existing != null) + { + AVMDAOs.Instance().fChildEntryDAO.delete(existing); + } + ChildEntry entry = new ChildEntryImpl(key, node); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + AVMDAOs.Instance().fChildEntryDAO.save(entry); + } + + /** + * Copy on write logic. + * @param lPath The lookup path. + * @return A brand new copied version. + */ + public AVMNode copy(Lookup lPath) + { + DirectoryNode newMe = null; + + DirectoryNode dir = lPath.getCurrentNodeDirectory(); + Long parentAclId = null; + if((dir != null) && (dir.getAcl() != null)) + { + parentAclId = dir.getAcl().getId(); + } + // In a layered context a copy on write creates a new + // layered directory. + if (lPath.isLayered()) + { + // Subtlety warning: This distinguishes the case of a + // Directory that was branched into the layer and one + // that is indirectly seen in this layer. + newMe = new LayeredDirectoryNodeImpl(this, lPath.getAVMStore(), lPath, + lPath.isInThisLayer(), parentAclId, ACLCopyMode.COPY); + ((LayeredDirectoryNodeImpl)newMe).setLayerID(lPath.getTopLayer().getLayerID()); + } + else + { + newMe = new PlainDirectoryNodeImpl(this, lPath.getAVMStore(), parentAclId, ACLCopyMode.COW); + } + newMe.setAncestor(this); + return newMe; + } + + /** + * Get the type of this node. + * @return The type of this node. + */ + public int getType() + { + return AVMNodeType.PLAIN_DIRECTORY; + } + + /** + * Get a diagnostic String representation. + * @param lPath The Lookup. + * @return A diagnostic String representation. + */ + public String toString(Lookup lPath) + { + return "[PD:" + getId() + "]"; + } + + /** + * Turn this into a primary indirection. This must be in a + * layered context. + * @param lPath The Lookup. + */ + public void turnPrimary(Lookup lPath) + { + assert false : "Should never happen."; + } + + /** + * Retarget this directory. lPath must be in a layered context. + * @param lPath The Lookup. + * @param target The target path. + */ + public void retarget(Lookup lPath, String target) + { + assert false : "Should never happen."; + } + + /** + * Get the descriptor for this node. + * @param lPath The Lookup. + * @param name The name of this node in this context. + * @return A descriptor. + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath, String name) + { + BasicAttributes attrs = getBasicAttributes(); + String path = lPath.getRepresentedPath(); + if (path.endsWith("/")) + { + path = path + name; + } + else + { + path = path + "/" + name; + } + return new AVMNodeDescriptor(path, + name, + AVMNodeType.PLAIN_DIRECTORY, + attrs.getCreator(), + attrs.getOwner(), + attrs.getLastModifier(), + attrs.getCreateDate(), + attrs.getModDate(), + attrs.getAccessDate(), + getId(), + getGuid(), + getVersionID(), + null, + -1, + false, + -1, + false, + -1, + -1); + } + + /** + * Get the descriptor for this node. + * @param lPath The Lookup. + * @return A descriptor. + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath) + { + BasicAttributes attrs = getBasicAttributes(); + String path = lPath.getRepresentedPath(); + return new AVMNodeDescriptor(path, + path.substring(path.lastIndexOf("/") + 1), + AVMNodeType.PLAIN_DIRECTORY, + attrs.getCreator(), + attrs.getOwner(), + attrs.getLastModifier(), + attrs.getCreateDate(), + attrs.getModDate(), + attrs.getAccessDate(), + getId(), + getGuid(), + getVersionID(), + null, + -1, + false, + -1, + false, + -1, + -1); + } + + /** + * Get this node's descriptor. + * @param parentPath The parent path. + * @param name The name that we were looked up under. + * @param parentIndirection The parent indirection. + * @return This node's node descriptor + */ + public AVMNodeDescriptor getDescriptor(String parentPath, String name, String parentIndirection, int parentIndirectionVersion) + { + BasicAttributes attrs = getBasicAttributes(); + String path = parentPath.endsWith("/") ? parentPath + name : parentPath + "/" + name; + return new AVMNodeDescriptor(path, + name, + AVMNodeType.PLAIN_DIRECTORY, + attrs.getCreator(), + attrs.getOwner(), + attrs.getLastModifier(), + attrs.getCreateDate(), + attrs.getModDate(), + attrs.getAccessDate(), + getId(), + getGuid(), + getVersionID(), + null, + -1, + false, + -1, + false, + -1, + -1); + } + + /** + * Link a node with the given id into this directory. + * @param lPath The Lookup for this directory. + * @param name The name to give the node. + * @param toLink The node to link in. + */ + public void link(Lookup lPath, String name, AVMNodeDescriptor toLink) + { + if (DEBUG) + { + checkReadOnly(); + } + // Assure that the incoming node exists. + AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(toLink.getId()); + if (node == null) + { + throw new AVMNotFoundException("Node not found: " + toLink.getId()); + } + if (node.getType() == AVMNodeType.LAYERED_DIRECTORY && + !((LayeredDirectoryNode)node).getPrimaryIndirection()) + { + throw new AVMBadArgumentException("Non primary layered directories cannot be linked."); + } + // Check for an existing child by the given name. + ChildKey key = new ChildKey(this, name); + ChildEntry child = AVMDAOs.Instance().fChildEntryDAO.get(key); + if (child != null) + { + if (child.getChild().getType() != AVMNodeType.DELETED_NODE) + { + // It's an error if there is a non DELETED_NODE child. + throw new AVMExistsException(name + " exists."); + } + // Get rid of the DELETED_NODE child. + AVMDAOs.Instance().fChildEntryDAO.delete(child); + // Another &*#*&#$ flush. + AVMDAOs.Instance().fAVMNodeDAO.flush(); + } + // Make the new entry and save. + ChildEntry newChild = new ChildEntryImpl(key, node); + AVMDAOs.Instance().fChildEntryDAO.save(newChild); + } +} + diff --git a/source/java/org/alfresco/repo/avm/PlainFileNodeImpl.java b/source/java/org/alfresco/repo/avm/PlainFileNodeImpl.java index ca505f6535..59f327c42b 100644 --- a/source/java/org/alfresco/repo/avm/PlainFileNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/PlainFileNodeImpl.java @@ -1,391 +1,398 @@ -/* - * 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.avm; - -import java.util.HashSet; -import java.util.List; -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.service.cmr.avm.AVMException; -import org.alfresco.service.cmr.avm.AVMNodeDescriptor; -import org.alfresco.service.cmr.repository.ContentData; -import org.alfresco.service.cmr.repository.ContentReader; -import org.alfresco.service.namespace.QName; - - -/** - * A plain old file. Contains a Content object. - * @author britt - */ -class PlainFileNodeImpl extends FileNodeImpl implements PlainFileNode -{ - static final long serialVersionUID = 8720376837929735294L; - - /** - * The Content URL. - */ - private String fContentURL; - - /** - * The Mime type. - */ - private String fMimeType; - - /** - * The character encoding. - */ - private String fEncoding; - - /** - * The length of the file. - */ - private long fLength; - - /** - * Default constructor. - */ - protected PlainFileNodeImpl() - { - } - - /** - * Make one from just an AVMStore. - * This is the constructor used when a brand new plain file is being made. - * @param store An AVMStore. - */ - public PlainFileNodeImpl(AVMStore store) - { - super(store.getAVMRepository().issueID(), store); - setVersionID(1); - AVMDAOs.Instance().fAVMNodeDAO.save(this); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - } - - /** - * Copy on write constructor. - * @param other The node we are being copied from. - * @param store The AVMStore. - */ - public PlainFileNodeImpl(PlainFileNode other, - AVMStore store) - { - super(store.getAVMRepository().issueID(), store); - // The null is OK because the Lookup argument is only use by - // layered files. - setContentData(other.getContentData(null)); - setVersionID(other.getVersionID() + 1); - AVMDAOs.Instance().fAVMNodeDAO.save(this); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - copyProperties(other); - copyAspects(other); - copyACLs(other); - } - - // TODO Is there a reason for passing all these parameters instead - // of just the LayeredFileNode? - /** - * Construct a new one. This is called when a LayeredFileNode - * is copied. - * @param store - * @param attrs - * @param content - */ - public PlainFileNodeImpl(AVMStore store, - BasicAttributes attrs, - ContentData content, - Map props, - Set aspects, - DbAccessControlList acl, - int versionID) - { - super(store.getAVMRepository().issueID(), store); - setContentData(content); - setBasicAttributes(attrs); - setVersionID(versionID + 1); - AVMDAOs.Instance().fAVMNodeDAO.save(this); - AVMDAOs.Instance().fAVMNodeDAO.flush(); - addProperties(props); - setAspects(new HashSet(aspects)); - if (acl != null) - { - setAcl(acl.getCopy()); - } - } - - /** - * Copy on write logic. - * @param lPath The lookup path. - */ - public AVMNode copy(Lookup lPath) - { - PlainFileNodeImpl newMe = new PlainFileNodeImpl(this, lPath.getAVMStore()); - newMe.setAncestor(this); - return newMe; - } - - /** - * Get the type of this node. - * @return The type. - */ - public int getType() - { - return AVMNodeType.PLAIN_FILE; - } - - /** - * Get a diagnostic string representation. - * @param lPath The Lookup. - * @return A diagnostic String representation. - */ -// @Override - public String toString(Lookup lPath) - { - return "[PF:" + getId() + "]"; - } - - /** - * Get the descriptor for this node. - * @param lPath The Lookup. - * @return A descriptor. - */ - public AVMNodeDescriptor getDescriptor(Lookup lPath, String name) - { - BasicAttributes attrs = getBasicAttributes(); - String path = lPath.getRepresentedPath(); - if (path.endsWith("/")) - { - path = path + name; - } - else - { - path = path + "/" + name; - } - return new AVMNodeDescriptor(path, - name, - AVMNodeType.PLAIN_FILE, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - null, - -1, - false, - -1, - false, - getLength(), - -1); - } - - /** - * Get the descriptor for this node. - * @param lPath The Lookup. - * @return A descriptor. - */ - public AVMNodeDescriptor getDescriptor(Lookup lPath) - { - BasicAttributes attrs = getBasicAttributes(); - String path = lPath.getRepresentedPath(); - return new AVMNodeDescriptor(path, - path.substring(path.lastIndexOf("/") + 1), - AVMNodeType.PLAIN_FILE, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - null, - -1, - false, - -1, - false, - getFileLength(), - -1); - } - - /** - * Get the descriptor for this. - * @param parentPath The parent path. - * @param name The name this was looked up with. - * @param parentIndirection The parent indirection. - * @return The descriptor for this. - */ - public AVMNodeDescriptor getDescriptor(String parentPath, String name, String parentIndirection, int parentIndirectionVersion) - { - BasicAttributes attrs = getBasicAttributes(); - String path = parentPath.endsWith("/") ? parentPath + name : parentPath + "/" + name; - return new AVMNodeDescriptor(path, - name, - AVMNodeType.PLAIN_FILE, - attrs.getCreator(), - attrs.getOwner(), - attrs.getLastModifier(), - attrs.getCreateDate(), - attrs.getModDate(), - attrs.getAccessDate(), - getId(), - getGuid(), - getVersionID(), - null, - -1, - false, - -1, - false, - getFileLength(), - -1); - } - - /** - * Get the Content URL. - * @return The content URL. - */ - public String getContentURL() - { - return fContentURL; - } - - /** - * Set the Content URL. - * @param contentURL - */ - protected void setContentURL(String contentURL) - { - fContentURL = contentURL; - } - - /** - * Get the character encoding. - * @return The encoding. - */ - public String getEncoding() - { - return fEncoding; - } - - /** - * Set the character encoding. - * @param encoding The encoding to set. - */ - public void setEncoding(String encoding) - { - fEncoding = encoding; - } - - /** - * Get the file length. - * @return The file length or null if unknown. - */ - public long getLength() - { - return fLength; - } - - /** - * Get the actual file length. - * @return The actual file length; - */ - private long getFileLength() - { - if (fContentURL == null) - { - return 0L; - } - ContentReader reader = RawServices.Instance().getContentStore().getReader(fContentURL); - return reader.getSize(); - } - - /** - * Set the file length. - * @param length The length of the file. - */ - protected void setLength(long length) - { - fLength = length; - } - - /** - * Get the mime type of the content. - * @return The Mime Type of the content. - */ - public String getMimeType() - { - return fMimeType; - } - - /** - * Set the Mime Type of the content. - * @param mimeType The Mime Type to set. - */ - public void setMimeType(String mimeType) - { - fMimeType = mimeType; - } - - /** - * Set the ContentData for this file. - * @param contentData The value to set. - */ - public void setContentData(ContentData contentData) - { - fContentURL = contentData.getContentUrl(); - fMimeType = contentData.getMimetype(); - if (fMimeType == null) - { - throw new AVMException("Null mime type."); - } - fEncoding = contentData.getEncoding(); - fLength = contentData.getSize(); - } - - /** - * Get the ContentData for this file. - * @param lPath The lookup path used to get here. Unused here. - * @return The ContentData object for this file. - */ - public ContentData getContentData(Lookup lPath) - { - return getContentData(); - } - - /* (non-Javadoc) - * @see org.alfresco.repo.avm.PlainFileNode#getContentData() - */ - public ContentData getContentData() - { - return new ContentData(fContentURL, fMimeType, fLength, fEncoding); - } -} - +/* + * 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.avm; + +import java.util.HashSet; +import java.util.List; +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.AVMException; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.ContentReader; +import org.alfresco.service.namespace.QName; + + +/** + * A plain old file. Contains a Content object. + * @author britt + */ +class PlainFileNodeImpl extends FileNodeImpl implements PlainFileNode +{ + static final long serialVersionUID = 8720376837929735294L; + + /** + * The Content URL. + */ + private String fContentURL; + + /** + * The Mime type. + */ + private String fMimeType; + + /** + * The character encoding. + */ + private String fEncoding; + + /** + * The length of the file. + */ + private long fLength; + + /** + * Default constructor. + */ + protected PlainFileNodeImpl() + { + } + + /** + * Make one from just an AVMStore. + * This is the constructor used when a brand new plain file is being made. + * @param store An AVMStore. + */ + public PlainFileNodeImpl(AVMStore store) + { + super(store.getAVMRepository().issueID(), store); + setVersionID(1); + AVMDAOs.Instance().fAVMNodeDAO.save(this); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + } + + /** + * Copy on write constructor. + * @param other The node we are being copied from. + * @param store The AVMStore. + */ + public PlainFileNodeImpl(PlainFileNode other, + AVMStore store, Long parentAcl, ACLCopyMode mode) + { + super(store.getAVMRepository().issueID(), store); + // The null is OK because the Lookup argument is only use by + // layered files. + setContentData(other.getContentData(null)); + setVersionID(other.getVersionID() + 1); + AVMDAOs.Instance().fAVMNodeDAO.save(this); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + copyProperties(other); + copyAspects(other); + copyACLs(other, parentAcl, mode); + } + + // TODO Is there a reason for passing all these parameters instead + // of just the LayeredFileNode? + /** + * Construct a new one. This is called when a LayeredFileNode + * is copied. + * @param store + * @param attrs + * @param content + */ + public PlainFileNodeImpl(AVMStore store, + BasicAttributes attrs, + ContentData content, + Map props, + Set aspects, + DbAccessControlList acl, + int versionID, Long parentAcl, ACLCopyMode mode) + { + super(store.getAVMRepository().issueID(), store); + setContentData(content); + setBasicAttributes(attrs); + setVersionID(versionID + 1); + AVMDAOs.Instance().fAVMNodeDAO.save(this); + AVMDAOs.Instance().fAVMNodeDAO.flush(); + addProperties(props); + setAspects(new HashSet(aspects)); + if (acl != null) + { + setAcl(acl.getCopy(parentAcl, mode)); + } + } + + /** + * Copy on write logic. + * @param lPath The lookup path. + */ + public AVMNode copy(Lookup lPath) + { + DirectoryNode dir = lPath.getCurrentNodeDirectory(); + Long parentAclId = null; + if((dir != null) && (dir.getAcl() != null)) + { + parentAclId = dir.getAcl().getId(); + } + PlainFileNodeImpl newMe = new PlainFileNodeImpl(this, lPath.getAVMStore(), parentAclId, ACLCopyMode.COW); + newMe.setAncestor(this); + return newMe; + } + + /** + * Get the type of this node. + * @return The type. + */ + public int getType() + { + return AVMNodeType.PLAIN_FILE; + } + + /** + * Get a diagnostic string representation. + * @param lPath The Lookup. + * @return A diagnostic String representation. + */ +// @Override + public String toString(Lookup lPath) + { + return "[PF:" + getId() + "]"; + } + + /** + * Get the descriptor for this node. + * @param lPath The Lookup. + * @return A descriptor. + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath, String name) + { + BasicAttributes attrs = getBasicAttributes(); + String path = lPath.getRepresentedPath(); + if (path.endsWith("/")) + { + path = path + name; + } + else + { + path = path + "/" + name; + } + return new AVMNodeDescriptor(path, + name, + AVMNodeType.PLAIN_FILE, + attrs.getCreator(), + attrs.getOwner(), + attrs.getLastModifier(), + attrs.getCreateDate(), + attrs.getModDate(), + attrs.getAccessDate(), + getId(), + getGuid(), + getVersionID(), + null, + -1, + false, + -1, + false, + getLength(), + -1); + } + + /** + * Get the descriptor for this node. + * @param lPath The Lookup. + * @return A descriptor. + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath) + { + BasicAttributes attrs = getBasicAttributes(); + String path = lPath.getRepresentedPath(); + return new AVMNodeDescriptor(path, + path.substring(path.lastIndexOf("/") + 1), + AVMNodeType.PLAIN_FILE, + attrs.getCreator(), + attrs.getOwner(), + attrs.getLastModifier(), + attrs.getCreateDate(), + attrs.getModDate(), + attrs.getAccessDate(), + getId(), + getGuid(), + getVersionID(), + null, + -1, + false, + -1, + false, + getFileLength(), + -1); + } + + /** + * Get the descriptor for this. + * @param parentPath The parent path. + * @param name The name this was looked up with. + * @param parentIndirection The parent indirection. + * @return The descriptor for this. + */ + public AVMNodeDescriptor getDescriptor(String parentPath, String name, String parentIndirection, int parentIndirectionVersion) + { + BasicAttributes attrs = getBasicAttributes(); + String path = parentPath.endsWith("/") ? parentPath + name : parentPath + "/" + name; + return new AVMNodeDescriptor(path, + name, + AVMNodeType.PLAIN_FILE, + attrs.getCreator(), + attrs.getOwner(), + attrs.getLastModifier(), + attrs.getCreateDate(), + attrs.getModDate(), + attrs.getAccessDate(), + getId(), + getGuid(), + getVersionID(), + null, + -1, + false, + -1, + false, + getFileLength(), + -1); + } + + /** + * Get the Content URL. + * @return The content URL. + */ + public String getContentURL() + { + return fContentURL; + } + + /** + * Set the Content URL. + * @param contentURL + */ + protected void setContentURL(String contentURL) + { + fContentURL = contentURL; + } + + /** + * Get the character encoding. + * @return The encoding. + */ + public String getEncoding() + { + return fEncoding; + } + + /** + * Set the character encoding. + * @param encoding The encoding to set. + */ + public void setEncoding(String encoding) + { + fEncoding = encoding; + } + + /** + * Get the file length. + * @return The file length or null if unknown. + */ + public long getLength() + { + return fLength; + } + + /** + * Get the actual file length. + * @return The actual file length; + */ + private long getFileLength() + { + if (fContentURL == null) + { + return 0L; + } + ContentReader reader = RawServices.Instance().getContentStore().getReader(fContentURL); + return reader.getSize(); + } + + /** + * Set the file length. + * @param length The length of the file. + */ + protected void setLength(long length) + { + fLength = length; + } + + /** + * Get the mime type of the content. + * @return The Mime Type of the content. + */ + public String getMimeType() + { + return fMimeType; + } + + /** + * Set the Mime Type of the content. + * @param mimeType The Mime Type to set. + */ + public void setMimeType(String mimeType) + { + fMimeType = mimeType; + } + + /** + * Set the ContentData for this file. + * @param contentData The value to set. + */ + public void setContentData(ContentData contentData) + { + fContentURL = contentData.getContentUrl(); + fMimeType = contentData.getMimetype(); + if (fMimeType == null) + { + throw new AVMException("Null mime type."); + } + fEncoding = contentData.getEncoding(); + fLength = contentData.getSize(); + } + + /** + * Get the ContentData for this file. + * @param lPath The lookup path used to get here. Unused here. + * @return The ContentData object for this file. + */ + public ContentData getContentData(Lookup lPath) + { + return getContentData(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.avm.PlainFileNode#getContentData() + */ + public ContentData getContentData() + { + return new ContentData(fContentURL, fMimeType, fLength, fEncoding); + } +} + diff --git a/source/java/org/alfresco/repo/avm/hibernate/AVM.hbm.xml b/source/java/org/alfresco/repo/avm/hibernate/AVM.hbm.xml index 28263c7c0c..ed9109a46f 100644 --- a/source/java/org/alfresco/repo/avm/hibernate/AVM.hbm.xml +++ b/source/java/org/alfresco/repo/avm/hibernate/AVM.hbm.xml @@ -44,7 +44,7 @@ - diff --git a/source/java/org/alfresco/repo/domain/AccessControlListDAO.java b/source/java/org/alfresco/repo/domain/AccessControlListDAO.java index 2371935cae..c703f70b40 100644 --- a/source/java/org/alfresco/repo/domain/AccessControlListDAO.java +++ b/source/java/org/alfresco/repo/domain/AccessControlListDAO.java @@ -1,50 +1,87 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" */ - -package org.alfresco.repo.domain; - -import org.alfresco.service.cmr.repository.NodeRef; - -/** - * This abstracts the reading and writing of ACLs on nodes - * from particular node implementations. - * @author britt - */ -public interface AccessControlListDAO -{ - /** - * Get the ACL from a node. - * @param nodeRef The reference to the node. - * @return The ACL. - * @throws InvalidNodeRefException - */ - public DbAccessControlList getAccessControlList(NodeRef nodeRef); - - /** - * Set the ACL on a node. - * @param nodeRef The reference to the node. - * @param acl The ACL. - * @throws InvalidNodeRefException - */ - public void setAccessControlList(NodeRef nodeRef, DbAccessControlList acl); -} +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" */ + +package org.alfresco.repo.domain; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.security.permissions.ACLType; +import org.alfresco.repo.security.permissions.impl.AclChange; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * This abstracts the reading and writing of ACLs on nodes from particular node implementations. + * + * @author britt + */ +public interface AccessControlListDAO +{ + /** + * Get the ACL from a node. + * + * @param nodeRef + * The reference to the node. + * @return The ACL. + * @throws InvalidNodeRefException + */ + public DbAccessControlList getAccessControlList(NodeRef nodeRef); + + /** + * Set the ACL on a node. + * + * @param nodeRef + * The reference to the node. + * @param acl + * The ACL. + * @throws InvalidNodeRefException + */ + public void setAccessControlList(NodeRef nodeRef, DbAccessControlList acl); + + /** + * Update any associated ACLs + * + * @param startingPoint + * @param chnages + */ + public void updateChangedAcls(NodeRef startingPoint, List changes); + + /** + * Update inheritance + * + * @param parent + * @param mergeFrom + * @param previousId + * @return + */ + public List setInheritanceForChildren(NodeRef parent, Long mergeFrom); + + public Long getIndirectAcl(NodeRef nodeRef); + + public Long getInheritedAcl(NodeRef nodeRef); + + public void forceCopy(NodeRef nodeRef); + + public Map patchAcls(); +} diff --git a/source/java/org/alfresco/repo/domain/DbAccessControlEntry.java b/source/java/org/alfresco/repo/domain/DbAccessControlEntry.java index 9b362542e6..c6585c088b 100644 --- a/source/java/org/alfresco/repo/domain/DbAccessControlEntry.java +++ b/source/java/org/alfresco/repo/domain/DbAccessControlEntry.java @@ -24,6 +24,9 @@ */ package org.alfresco.repo.domain; +import org.alfresco.repo.security.permissions.ACEType; +import org.alfresco.repo.security.permissions.AccessControlEntry; + /** @@ -44,16 +47,6 @@ public interface DbAccessControlEntry */ public Long getVersion(); - /** - * @return Returns the containing access control list - */ - public DbAccessControlList getAccessControlList(); - - /** - * @param acl the accession control list to which entry belongs - */ - public void setAccessControlList(DbAccessControlList acl); - /** * @return Returns the permission to which this entry applies */ @@ -86,6 +79,30 @@ public interface DbAccessControlEntry */ 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. diff --git a/source/java/org/alfresco/repo/domain/DbAccessControlEntryContext.java b/source/java/org/alfresco/repo/domain/DbAccessControlEntryContext.java new file mode 100644 index 0000000000..b6fd591633 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/DbAccessControlEntryContext.java @@ -0,0 +1,105 @@ +/* + * 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; + +/** + * 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 ae25a1b476..294436a946 100644 --- a/source/java/org/alfresco/repo/domain/DbAccessControlList.java +++ b/source/java/org/alfresco/repo/domain/DbAccessControlList.java @@ -24,9 +24,8 @@ */ package org.alfresco.repo.domain; -import java.util.Set; - -import org.alfresco.repo.domain.hibernate.DbAccessControlEntryImpl; +import org.alfresco.repo.security.permissions.ACLCopyMode; +import org.alfresco.repo.security.permissions.ACLType; /** @@ -36,61 +35,141 @@ import org.alfresco.repo.domain.hibernate.DbAccessControlEntryImpl; */ public interface DbAccessControlList { + /** + * 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(); - /** - * - * @return Returns the access control entries for this access control list - */ - public Set getEntries(); - /** * Get inheritance behaviour * @return Returns the inheritance status of this list */ public boolean getInherits(); + /** + * 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); - public int deleteEntriesForAuthority(String authorityKey); - - public int deleteEntriesForPermission(DbPermissionKey permissionKey); - - public int deleteEntry(String authorityKey, DbPermissionKey permissionKey); + /** + * Set the ACL from which this one inherits + * @param id + */ + public void setInheritsFrom(Long id); /** - * Delete the entries related to this access control list - * - * @return Returns the number of entries deleted + * Set the ACL Type + * @param type */ - public int deleteEntries(); - - public DbAccessControlEntry getEntry(String authorityKey, DbPermissionKey permissionKey); + public void setAclType(ACLType type); /** - * Factory method to create an entry and wire it up. - * Note that the returned value may still be transient. Saving it should be fine, but - * is not required. - * - * @param permission the mandatory permission association with this entry - * @param authority the mandatory authority. Must not be transient. - * @param allowed allowed or disallowed. Must not be transient. - * @return Returns the new entry + * Set the ACL that should be set when inheriting from this one. + * This ACL does not contain any object specific settings. + * @param acl */ - public DbAccessControlEntryImpl newEntry(DbPermission permission, DbAuthority authority, boolean allowed); + public void setInheritedAclId(Long acl); /** - * Make a copy of this ACL (persistently) - * @return The copy. + * Set if this ACL is versioned on write + * @param isVersioned */ - public DbAccessControlList getCopy(); + 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 new file mode 100644 index 0000000000..c482ca0041 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/DbAccessControlListChangeSet.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; + +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 new file mode 100644 index 0000000000..2f15a3fa91 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/DbAccessControlListMember.java @@ -0,0 +1,88 @@ +/* + * 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; + +/** + * 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 index fb56aac80d..59b889098e 100644 --- a/source/java/org/alfresco/repo/domain/DbAuthority.java +++ b/source/java/org/alfresco/repo/domain/DbAuthority.java @@ -25,7 +25,6 @@ package org.alfresco.repo.domain; import java.io.Serializable; -import java.util.Set; /** * The interface against which recipients of permission are persisted @@ -33,30 +32,25 @@ import java.util.Set; */ 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 recipient + * @return Returns the authority */ - public String getRecipient(); + public String getAuthority(); /** - * @param recipient the authority recipient + * @param the authority */ - public void setRecipient(String recipient); - - /** - * @return Returns the external keys associated with this authority - */ - public Set getExternalKeys(); - - /** - * Delete the access control entries related to this authority - * - * @return Returns the number of entries deleted - */ - public int deleteEntries(); + public void setAuthority(String authority); + } diff --git a/source/java/org/alfresco/repo/domain/DbAuthorityAlias.java b/source/java/org/alfresco/repo/domain/DbAuthorityAlias.java new file mode 100644 index 0000000000..4bfb99e843 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/DbAuthorityAlias.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain; + +/** + * Hibernate 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/hibernate/AVMAccessControlListDAO.java b/source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java index cad2c1844f..f3ad2d8d6a 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java +++ b/source/java/org/alfresco/repo/domain/hibernate/AVMAccessControlListDAO.java @@ -1,103 +1,839 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" */ - -package org.alfresco.repo.domain.hibernate; - -import org.alfresco.repo.avm.AVMNodeConverter; -import org.alfresco.repo.avm.AVMRepository; -import org.alfresco.repo.domain.AccessControlListDAO; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.service.cmr.avm.AVMException; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.util.Pair; - -/** - * The AVM implementation for getting and setting ACLs. - * @author britt - */ -public class AVMAccessControlListDAO implements AccessControlListDAO -{ - /** - * Reference to the AVM Repository instance. - */ - private AVMRepository fAVMRepository; - - /** - * Default constructory. - */ - public AVMAccessControlListDAO() - { - } - - public void setAvmRepository(AVMRepository repository) - { - fAVMRepository = repository; - } - - /** - * Get the ACL from a node. - * @param nodeRef The reference to the node. - * @return The ACL. - * @throws InvalidNodeRefException - */ - public DbAccessControlList getAccessControlList(NodeRef nodeRef) - { - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - int version = avmVersionPath.getFirst(); - String path = avmVersionPath.getSecond(); - try - { - return fAVMRepository.getACL(version, path); - } - catch (AVMException e) - { - throw new InvalidNodeRefException(nodeRef); - } - } - - /** - * Set the ACL on a node. - * @param nodeRef The reference to the node. - * @param acl The ACL. - * @throws InvalidNodeRefException - */ - public void setAccessControlList(NodeRef nodeRef, DbAccessControlList acl) - { - Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); - int version = avmVersionPath.getFirst(); - if (version >= 0) - { - throw new InvalidNodeRefException("Read Only Node.", nodeRef); - } - String path = avmVersionPath.getSecond(); - try - { - fAVMRepository.setACL(path, acl); - } - catch (AVMException e) - { - throw new InvalidNodeRefException(nodeRef); - } - } -} +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" */ + +package org.alfresco.repo.domain.hibernate; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.avm.AVMNodeConverter; +import org.alfresco.repo.avm.AVMRepository; +import org.alfresco.repo.domain.AccessControlListDAO; +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +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.avm.AVMException; +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.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.util.Pair; + +/** + * The AVM implementation for getting and setting ACLs. + * + * @author britt + */ +public class AVMAccessControlListDAO implements AccessControlListDAO +{ + /** + * Reference to the AVM Repository instance. + */ + private AVMRepository fAVMRepository; + + private AVMService fAVMService; + + private AclDaoComponent aclDaoComponent; + + /** + * Default constructory. + */ + public AVMAccessControlListDAO() + { + } + + public void setAvmRepository(AVMRepository repository) + { + fAVMRepository = repository; + } + + public void setAvmService(AVMService avmService) + { + fAVMService = avmService; + } + + public void setAclDaoComponent(AclDaoComponent aclDaoComponent) + { + this.aclDaoComponent = aclDaoComponent; + } + + public Long getIndirectAcl(NodeRef nodeRef) + { + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + int version = avmVersionPath.getFirst(); + if (version >= 0) + { + throw new InvalidNodeRefException("Read Only Node.", nodeRef); + } + String path = avmVersionPath.getSecond(); + try + { + AVMNodeDescriptor descriptor = fAVMService.lookup(version, path); + if (descriptor == null) + { + return null; + } + if (descriptor.isPrimary()) + { + DbAccessControlList acl = getAclAsSystem(descriptor.getIndirectionVersion(), descriptor.getIndirection()); + if (acl == null) + { + return null; + } + else + { + return acl.getId(); + } + } + else + { + DbAccessControlList acl = getAclAsSystem(version, path); + if (acl == null) + { + return null; + } + else + { + return acl.getId(); + } + } + } + catch (AVMException e) + { + throw new InvalidNodeRefException(nodeRef); + } + } + + public Long getInheritedAcl(NodeRef nodeRef) + { + // 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 null; + } + + DbAccessControlList acl = getAclAsSystem(avmVersionPath.getFirst(), splitPath[0]); + if (acl == null) + { + return null; + } + else + { + return acl.getId(); + } + + } + + /** + * Get the ACL from a node. + * + * @param nodeRef + * The reference to the node. + * @return The ACL. + * @throws InvalidNodeRefException + */ + public DbAccessControlList getAccessControlList(NodeRef nodeRef) + { + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + int version = avmVersionPath.getFirst(); + String path = avmVersionPath.getSecond(); + try + { + return getAclAsSystem(version, path); + } + catch (AVMException e) + { + throw new InvalidNodeRefException(nodeRef); + } + } + + /** + * Set the ACL on a node. + * + * @param nodeRef + * The reference to the node. + * @param acl + * The ACL. + * @throws InvalidNodeRefException + */ + public void setAccessControlList(NodeRef nodeRef, DbAccessControlList acl) + { + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + int version = avmVersionPath.getFirst(); + if (version >= 0) + { + throw new InvalidNodeRefException("Read Only Node.", nodeRef); + } + String path = avmVersionPath.getSecond(); + try + { + setAclAsSystem(path, acl); + } + catch (AVMException e) + { + throw new InvalidNodeRefException(nodeRef); + } + } + + public void updateChangedAcls(NodeRef startingPoint, List changes) + { + Long after = null; + for (AclChange change : changes) + { + if (change.getBefore() == null) + { + after = change.getAfter(); + } + else if (change.getTypeBefore() != change.getTypeAfter()) + { + after = change.getAfter(); + } + } + Long inherited = null; + if (after != null) + { + inherited = aclDaoComponent.getInheritedAccessControlList(after); + } + updateChangedAclsImpl(startingPoint, changes, SetMode.ALL, inherited, after); + } + + private void updateChangedAclsImpl(NodeRef startingPoint, List changes, SetMode mode, Long inherited, Long setAcl) + { + HashMap changeMap = new HashMap(); + HashSet unchangedSet = new HashSet(); + for (AclChange change : changes) + { + 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()); + } + } + unchangedSet.add(inherited); + unchangedSet.add(setAcl); + + if (inherited != null) + { + updateReferencingLayeredAcls(startingPoint, inherited); + } + updateInheritedChangedAcls(startingPoint, changeMap, unchangedSet, inherited, mode); + updateLayeredAclsChangedByInheritance(changes, changeMap, unchangedSet); + } + + public void forceCopy(NodeRef nodeRef) + { + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef); + int version = avmVersionPath.getFirst(); + if (version >= 0) + { + throw new InvalidNodeRefException("Read Only Node.", nodeRef); + } + String path = avmVersionPath.getSecond(); + try + { + fAVMRepository.forceCopy(path); + } + catch (AVMException e) + { + throw new InvalidNodeRefException(nodeRef); + } + + } + + private void updateReferencingLayeredAcls(NodeRef node, Long inherited) + { + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(node); + int version = avmVersionPath.getFirst(); + if (version >= 0) + { + throw new InvalidNodeRefException("Read Only Node.", node); + } + String path = avmVersionPath.getSecond(); + try + { + AVMNodeDescriptor descriptor = fAVMService.lookup(version, path); + if (descriptor == null) + { + return; + } + else + { + List> paths = fAVMService.getHeadPaths(descriptor); + for (Pair current : paths) + { + List avmNodeIds = aclDaoComponent.getAvmNodesByIndirection(current.getSecond()); + for (Long id : avmNodeIds) + { + // need to fix up inheritance as is has changed + AVMNodeDescriptor layerDesc = new AVMNodeDescriptor(null, null, 0, null, null, null, 0, 0, 0, id, null, 0, null, 0, false, 0, false, 0, 0); + List> layerPaths = fAVMRepository.getHeadPaths(layerDesc); + // Update all locations with the updated ACL + for (Pair layerPath : layerPaths) + { + AVMNodeDescriptor test = fAVMService.lookup(-1, layerPath.getSecond()); + if (test.isPrimary()) + { + DbAccessControlList target = getAclAsSystem(-1, layerPath.getSecond()); + if (target != null) + { + if (target.getAclType() == ACLType.LAYERED) + { + fAVMService.forceCopy(layerPath.getSecond()); + + List layeredChanges = aclDaoComponent.mergeInheritedAccessControlList(inherited, target.getId()); + NodeRef layeredNode = AVMNodeConverter.ToNodeRef(-1, layerPath.getSecond()); + for (AclChange change : layeredChanges) + { + if (change.getBefore().equals(target.getId())) + { + Long newInherited = null; + if (change.getAfter() != null) + { + newInherited = aclDaoComponent.getInheritedAccessControlList(change.getAfter()); + } + updateChangedAclsImpl(layeredNode, layeredChanges, SetMode.DIRECT_ONLY, newInherited, change.getAfter()); + break; + } + } + } + } + } + } + } + } + } + } + catch (AVMException e) + { + throw new InvalidNodeRefException(node); + } + } + + private void updateLayeredAclsChangedByInheritance(List changes, HashMap changeMap, Set unchanged) + { + for (AclChange change : changes) + { + if ((change.getTypeBefore() == ACLType.LAYERED) && (change.getTypeAfter() == ACLType.LAYERED)) + { + // Query for affected nodes + List avmNodeIds = aclDaoComponent.getAvmNodesByACL(change.getBefore()); + + for (Long id : avmNodeIds) + { + // Find all paths to the nodes + AVMNodeDescriptor desc = new AVMNodeDescriptor(null, null, 0, null, null, null, 0, 0, 0, id, null, 0, null, 0, false, 0, false, 0, 0); + List> paths = fAVMRepository.getHeadPaths(desc); + // Update all locations with the updated ACL + for (Pair path : paths) + { + // No need to force COW - any inherited ACL will have COWED if the top ACL required it + setAclAsSystem(path.getSecond(), aclDaoComponent.getDbAccessControlList(change.getAfter())); + NodeRef layeredNode = AVMNodeConverter.ToNodeRef(-1, path.getSecond()); + updateInheritedChangedAcls(layeredNode, changeMap, unchanged, aclDaoComponent.getInheritedAccessControlList(change.getAfter()), SetMode.DIRECT_ONLY); + } + } + } + } + } + + private void updateInheritedChangedAcls(NodeRef startingPoint, HashMap changeMap, Set unchanged, Long unsetAcl, SetMode mode) + { + // Walk children and fix up any that reference the given list .. + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(startingPoint); + int version = avmVersionPath.getFirst(); + if (version >= 0) + { + throw new InvalidNodeRefException("Read Only Node.", startingPoint); + } + String path = avmVersionPath.getSecond(); + try + { + AVMNodeDescriptor descriptor = fAVMService.lookup(version, path); + if (descriptor == null) + { + return; + } + else + { + + if (descriptor.isLayeredDirectory()) + { + setInheritanceForDirectChildren(descriptor, changeMap, aclDaoComponent.getInheritedAccessControlList(getAclAsSystem(-1, descriptor.getPath()).getId())); + } + fixUpAcls(descriptor, changeMap, unchanged, unsetAcl, mode); + } + } + catch (AVMException e) + { + throw new InvalidNodeRefException(startingPoint); + } + } + + private void fixUpAcls(AVMNodeDescriptor descriptor, Map changes, Set unchanged, Long unsetAcl, SetMode mode) + { + DbAccessControlList acl = getAclAsSystem(-1, descriptor.getPath()); + Long id = null; + if (acl != null) + { + id = acl.getId(); + } + + if (id == null) + { + // No need to force COW - ACL should have COWed if required + setAclAsSystem(descriptor.getPath(), aclDaoComponent.getDbAccessControlList(unsetAcl)); + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, descriptor.getPath()); + updateReferencingLayeredAcls(nodeRef, unsetAcl); + } + else if (changes.containsKey(id)) + { + Long updateId = changes.get(id); + if (updateId != id) + { + DbAccessControlList newAcl = aclDaoComponent.getDbAccessControlList(updateId); + // No need to force COW - ACL should have COWed if required + setAclAsSystem(descriptor.getPath(), newAcl); + } + } + else if (unchanged.contains(id)) + { + // carry on + } + else + { + // Not in the list + return; + } + if (descriptor.isDirectory()) + { + Map children; + switch (mode) + { + case ALL: + children = fAVMService.getDirectoryListing(descriptor, false); + break; + case DIRECT_ONLY: + children = fAVMService.getDirectoryListingDirect(descriptor, false); + break; + default: + throw new IllegalStateException(); + } + for (AVMNodeDescriptor child : children.values()) + { + fixUpAcls(child, changes, unchanged, unsetAcl, mode); + } + } + + } + + private void setInheritanceForDirectChildren(AVMNodeDescriptor descriptor, Map changeMap, Long mergeFrom) + { + List changes = new ArrayList(); + setFixedAcls(descriptor, mergeFrom, changes, SetMode.DIRECT_ONLY, false); + for (AclChange change : changes) + { + if (!change.getBefore().equals(change.getAfter())) + { + changeMap.put(change.getBefore(), change.getAfter()); + } + } + } + + public List setInheritanceForChildren(NodeRef parent, Long mergeFrom) + { + // 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 + Pair avmVersionPath = AVMNodeConverter.ToAVMVersionPath(parent); + int version = avmVersionPath.getFirst(); + if (version >= 0) + { + throw new InvalidNodeRefException("Read Only Node.", parent); + } + String path = avmVersionPath.getSecond(); + try + { + List changes = new ArrayList(); + AVMNodeDescriptor descriptor = fAVMService.lookup(version, path); + setFixedAcls(descriptor, mergeFrom, changes, SetMode.ALL, false); + return changes; + + } + catch (AVMException e) + { + throw new InvalidNodeRefException(parent); + } + } + + public void setFixedAcls(AVMNodeDescriptor descriptor, Long mergeFrom, List changes, SetMode mode, boolean set) + { + if (descriptor == null) + { + return; + } + else + { + if (set) + { + // Simple set does not require any special COW wire up + // The AVM node will COW as required + DbAccessControlList previous = getAclAsSystem(-1, descriptor.getPath()); + setAclAsSystem(descriptor.getPath(), aclDaoComponent.getDbAccessControlList(mergeFrom)); + if (previous == null) + { + NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, descriptor.getPath()); + updateReferencingLayeredAcls(nodeRef, mergeFrom); + } + } + + if (descriptor.isDirectory()) + { + Map children; + switch (mode) + { + case ALL: + children = fAVMService.getDirectoryListing(descriptor, false); + break; + case DIRECT_ONLY: + children = fAVMService.getDirectoryListingDirect(descriptor, false); + break; + default: + throw new IllegalStateException(); + } + + for (String key : children.keySet()) + { + AVMNodeDescriptor child = children.get(key); + + DbAccessControlList acl = getAclAsSystem(-1, child.getPath()); + + if (acl == null) + { + setFixedAcls(child, mergeFrom, changes, mode, true); + + } + else if (acl.getAclType() == ACLType.LAYERED) + { + // nothing to do + } + else if (acl.getAclType() == ACLType.DEFINING) + { + // Can require copy on right to be triggered for ACLS + // So we force a copy on write (which marks ACLS and below to copy if required) + fAVMService.forceCopy(child.getPath()); + + List newChanges = aclDaoComponent.mergeInheritedAccessControlList(mergeFrom, acl.getId()); + + for (AclChange change : newChanges) + { + if (change.getBefore().equals(acl.getId())) + { + setAclAsSystem(child.getPath(), aclDaoComponent.getDbAccessControlList(change.getAfter())); + setFixedAcls(child, aclDaoComponent.getInheritedAccessControlList(change.getAfter()), newChanges, SetMode.DIRECT_ONLY, false); + changes.addAll(newChanges); + break; + } + } + } + else + { + setFixedAcls(child, mergeFrom, changes, mode, true); + } + + } + } + } + } + + private enum SetMode + { + ALL, DIRECT_ONLY; + } + + public Map patchAcls() + { + CounterSet result = new CounterSet(); + List stores = fAVMService.getStores(); + for (AVMStoreDescriptor store : stores) + { + AVMNodeDescriptor root = fAVMService.getStoreRoot(-1, store.getName()); + CounterSet update = fixOldAvmAcls(root); + 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 fixOldAvmAcls(AVMNodeDescriptor node) + { + CounterSet result = new CounterSet(); + // Do the children first + + if (node.isDirectory()) + { + Map children = fAVMRepository.getListingDirect(node, true); + for (AVMNodeDescriptor child : children.values()) + { + CounterSet update = fixOldAvmAcls(child); + result.add(update); + } + } + + DbAccessControlList existingAcl = getAclAsSystem(-1, node.getPath()); + + if (existingAcl != null) + { + if (existingAcl.getAclType() == ACLType.OLD) + { + result.increment(ACLType.DEFINING); + // + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + // Accept default versioning + Long id = aclDaoComponent.createAccessControlList(properties); + DbAccessControlList newAcl = aclDaoComponent.getDbAccessControlList(id); + + AccessControlList existing = aclDaoComponent.getAccessControlList(existingAcl.getId()); + for (AccessControlEntry entry : existing.getEntries()) + { + if (entry.getPosition() == 0) + { + aclDaoComponent.setAccessControlEntry(id, entry); + } + } + setAclAsSystem(node.getPath(), newAcl); + + // Cascade to children - changes should all be 1-1 so we do not have to post fix + + List changes = new ArrayList(); + + setFixedAcls(node, aclDaoComponent.getInheritedAccessControlList(id), changes, SetMode.DIRECT_ONLY, false); + + for (AclChange change : changes) + { + if (!change.getBefore().equals(change.getAfter())) + { + throw new IllegalStateException("ACL fix should not change the acl ids - unexpected COW!"); + } + + } + } + else + { + throw new IllegalStateException(); + } + } + else if (node.isLayeredDirectory()) + { + result.increment(ACLType.LAYERED); + // create layered permission entry + if (node.getIndirection() != null) + { + AVMNodeDescriptor referencedNode = fAVMService.lookup(-1, node.getIndirection(), false); + if ((referencedNode != null) && (referencedNode.isDirectory())) + { + DbAccessControlList acl = getAclAsSystem(-1, referencedNode.getPath()); + if (acl != null) + { + setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(acl.getId())); + } + else + { + setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(null)); + } + } + else + { + setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(null)); + } + } + else + { + setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(null)); + } + List changes = new ArrayList(); + + setFixedAcls(node, aclDaoComponent.getInheritedAccessControlList(getAclAsSystem(-1, node.getPath()).getId()), changes, SetMode.DIRECT_ONLY, false); + + for (AclChange change : changes) + { + if (!change.getBefore().equals(change.getAfter())) + { + throw new IllegalStateException("ACL fix should not change the acl ids - unexpected COW!"); + } + + } + } + else if (node.isLayeredFile()) + { + result.increment(ACLType.LAYERED); + if (node.getIndirection() != null) + { + AVMNodeDescriptor referencedNode = fAVMService.lookup(-1, node.getIndirection(), false); + if (referencedNode != null) + { + DbAccessControlList acl = getAclAsSystem(-1, referencedNode.getPath()); + if (acl != null) + { + setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(acl.getId())); + } + else + { + setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(null)); + } + } + else + { + setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(null)); + } + } + else + { + setAclAsSystem(node.getPath(), DbAccessControlListImpl.createLayeredAcl(null)); + } + List changes = new ArrayList(); + + setFixedAcls(node, aclDaoComponent.getInheritedAccessControlList(getAclAsSystem(-1, node.getPath()).getId()), changes, SetMode.DIRECT_ONLY, false); + + for (AclChange change : changes) + { + if (!change.getBefore().equals(change.getAfter())) + { + throw new IllegalStateException("ACL fix should not change the acl ids - unexpected COW!"); + } + + } + } + return result; + } + + private class CounterSet extends HashMap + { + CounterSet() + { + super(); + this.put(ACLType.DEFINING, new Counter()); + this.put(ACLType.FIXED, new Counter()); + this.put(ACLType.GLOBAL, new Counter()); + this.put(ACLType.LAYERED, new Counter()); + this.put(ACLType.OLD, new Counter()); + this.put(ACLType.SHARED, new Counter()); + } + + void add(ACLType type, Counter c) + { + Counter counter = get(type); + counter.add(c.getCounter()); + } + + void increment(ACLType type) + { + Counter counter = get(type); + counter.increment(); + } + + void add(CounterSet other) + { + add(ACLType.DEFINING, other.get(ACLType.DEFINING)); + add(ACLType.FIXED, other.get(ACLType.FIXED)); + add(ACLType.GLOBAL, other.get(ACLType.GLOBAL)); + add(ACLType.LAYERED, other.get(ACLType.LAYERED)); + add(ACLType.OLD, other.get(ACLType.OLD)); + add(ACLType.SHARED, other.get(ACLType.SHARED)); + } + } + + private class Counter + { + int counter; + + void increment() + { + counter++; + } + + int getCounter() + { + return counter; + } + + void add(int i) + { + counter += i; + } + } + + + + private DbAccessControlList getAclAsSystem(final int version, final String path) + { + return AuthenticationUtil.runAs(new RunAsWork(){ + + public DbAccessControlList doWork() throws Exception + { + return fAVMRepository.getACL(version, path); + }}, AuthenticationUtil.getSystemUserName()); + } + + private void setAclAsSystem(final String path, final DbAccessControlList acl) + { + AuthenticationUtil.runAs(new RunAsWork(){ + + public Object doWork() throws Exception + { + fAVMRepository.setACL(path, acl); + return null; + }}, AuthenticationUtil.getSystemUserName()); + } +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java new file mode 100644 index 0000000000..206a245a5f --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/AbstractPermissionsDaoComponentImpl.java @@ -0,0 +1,494 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.hibernate; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.alfresco.repo.domain.AccessControlListDAO; +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.security.permissions.ACEType; +import org.alfresco.repo.security.permissions.AccessControlEntry; +import org.alfresco.repo.security.permissions.AccessControlList; +import org.alfresco.repo.security.permissions.NodePermissionEntry; +import org.alfresco.repo.security.permissions.PermissionEntry; +import org.alfresco.repo.security.permissions.PermissionReference; +import org.alfresco.repo.security.permissions.SimpleAccessControlEntry; +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.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; + +public abstract class AbstractPermissionsDaoComponentImpl implements PermissionsDaoComponent, TransactionalDao +{ + private static Log logger = LogFactory.getLog(AbstractPermissionsDaoComponentImpl.class); + + protected static final boolean INHERIT_PERMISSIONS_DEFAULT = true; + + protected AclDaoComponent aclDaoComponent; + + private Map fProtocolToACLDAO; + + private AccessControlListDAO fDefaultACLDAO; + + /** a uuid identifying this unique instance */ + private String uuid; + + AbstractPermissionsDaoComponentImpl() + { + this.uuid = GUID.generate(); + } + + public AclDaoComponent getAclDaoComponent() + { + return aclDaoComponent; + } + + public void setAclDaoComponent(AclDaoComponent aclDaoComponent) + { + this.aclDaoComponent = aclDaoComponent; + } + + /** + * Checks equality by type and uuid + */ + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + else if (!(obj instanceof AbstractPermissionsDaoComponentImpl)) + { + return false; + } + AbstractPermissionsDaoComponentImpl that = (AbstractPermissionsDaoComponentImpl) obj; + return this.uuid.equals(that.uuid); + } + + /** + * @see #uuid + */ + public int hashCode() + { + return uuid.hashCode(); + } + + /** + * Does this Session contain any changes which must be synchronized with the store? + * + * @return true => changes are pending + */ + public boolean isDirty() + { + return aclDaoComponent.isDirty(); + } + + /** + * Just flushes the session + */ + public void flush() + { + aclDaoComponent.flush(); + } + + /** + * NO-OP + */ + public void beforeCommit() + { + aclDaoComponent.beforeCommit(); + } + + public void setProtocolToACLDAO(Map map) + { + fProtocolToACLDAO = map; + } + + public void setDefaultACLDAO(AccessControlListDAO defaultACLDAO) + { + fDefaultACLDAO = defaultACLDAO; + } + + /** + * Helper to choose appropriate NodeService for the given NodeRef + * + * @param nodeRef + * The NodeRef to dispatch from. + * @return The appropriate NodeService. + */ + protected AccessControlListDAO getACLDAO(NodeRef nodeRef) + { + AccessControlListDAO ret = fProtocolToACLDAO.get(nodeRef.getStoreRef().getProtocol()); + if (ret == null) + { + return fDefaultACLDAO; + } + return ret; + } + + protected DbAccessControlList getAccessControlList(NodeRef nodeRef) + { + DbAccessControlList acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); + return acl; + } + + protected CreationReport getMutableAccessControlList(NodeRef nodeRef) + { + DbAccessControlList acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); + if (acl == null) + { + return createAccessControlList(nodeRef, INHERIT_PERMISSIONS_DEFAULT, null); + } + else + { + switch (acl.getAclType()) + { + case FIXED: + case GLOBAL: + case SHARED: + case LAYERED: + // We can not set an ACL on node that has one of these types so we need to make a new one .... + return createAccessControlList(nodeRef, INHERIT_PERMISSIONS_DEFAULT, acl); + case DEFINING: + case OLD: + default: + // Force a copy on write if one is required + getACLDAO(nodeRef).forceCopy(nodeRef); + return new CreationReport(acl, Collections. emptyList()); + } + } + } + + public NodePermissionEntry getPermissions(NodeRef nodeRef) + { + // Create the object if it is not found. + // Null objects are not cached in hibernate + // If the object does not exist it will repeatedly query to check its + // non existence. + NodePermissionEntry npe = null; + DbAccessControlList acl = null; + try + { + acl = getAccessControlList(nodeRef); + } + catch (InvalidNodeRefException e) + { + // Do nothing. + } + + if (acl == null) + { + // there isn't an access control list for the node - spoof a null one + SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry(nodeRef, true, Collections. emptySet()); + npe = snpe; + } + else + { + npe = createSimpleNodePermissionEntry(nodeRef); + } + // done + if (logger.isDebugEnabled()) + { + logger.debug("Got NodePermissionEntry for node: \n" + " node: " + nodeRef + "\n" + " acl: " + npe); + } + return npe; + } + + @SuppressWarnings("unchecked") + 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 + + private SimpleNodePermissionEntry createSimpleNodePermissionEntry(NodeRef nodeRef) + { + DbAccessControlList acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); + if (acl == null) + { + // there isn't an access control list for the node - spoof a null one + SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry(nodeRef, true, Collections. emptySet()); + return snpe; + } + else + { + AccessControlList info = aclDaoComponent.getAccessControlList(acl.getId()); + + HashSet spes = new HashSet(info.getEntries().size(), 1.0f); + for (AccessControlEntry entry : info.getEntries()) + { + SimplePermissionEntry spe = new SimplePermissionEntry(nodeRef, entry.getPermission(), entry.getAuthority(), entry.getAccessStatus()); + spes.add(spe); + } + SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry(nodeRef, acl.getInherits(), spes); + return snpe; + } + } + + public boolean getInheritParentPermissions(NodeRef nodeRef) + { + DbAccessControlList acl = null; + try + { + acl = getAccessControlList(nodeRef); + } + catch (InvalidNodeRefException e) + { + return INHERIT_PERMISSIONS_DEFAULT; + } + if (acl == null) + { + return INHERIT_PERMISSIONS_DEFAULT; + } + else + { + return aclDaoComponent.getAccessControlListProperties(acl.getId()).getInherits(); + } + } + + @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 + + } + + public void deletePermissions(NodeRef nodeRef, final String authority) + { + DbAccessControlList acl = null; + try + { + acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); + } + catch (InvalidNodeRefException e) + { + return; + } + switch (acl.getAclType()) + { + case FIXED: + case GLOBAL: + case SHARED: + throw new IllegalStateException("Can not delete from this acl in a node context " + acl.getAclType()); + case DEFINING: + case LAYERED: + case OLD: + default: + CreationReport report = getMutableAccessControlList(nodeRef); + SimpleAccessControlEntry pattern = new SimpleAccessControlEntry(); + pattern.setAuthority(authority); + List changes = aclDaoComponent.deleteAccessControlEntries(report.getCreated().getId(), pattern); + getACLDAO(nodeRef).updateChangedAcls(nodeRef, changes); + break; + } + } + + /** + * Deletes all permission entries (access control list entries) that match the given criteria. Note that the access + * control list for the node is not deleted. + */ + public void deletePermission(NodeRef nodeRef, String authority, PermissionReference permission) + { + DbAccessControlList acl = null; + try + { + acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); + } + catch (InvalidNodeRefException e) + { + return; + } + + switch (acl.getAclType()) + { + case FIXED: + case GLOBAL: + case SHARED: + throw new IllegalStateException("Can not delete from this acl in a node context " + acl.getAclType()); + case DEFINING: + case LAYERED: + case OLD: + default: + CreationReport report = getMutableAccessControlList(nodeRef); + SimpleAccessControlEntry pattern = new SimpleAccessControlEntry(); + pattern.setAuthority(authority); + pattern.setPermission(permission); + List changes = aclDaoComponent.deleteAccessControlEntries(report.getCreated().getId(), pattern); + getACLDAO(nodeRef).updateChangedAcls(nodeRef, changes); + break; + } + + } + + public void setPermission(NodeRef nodeRef, String authority, PermissionReference permission, boolean allow) + { + CreationReport report = null; + try + { + report = getMutableAccessControlList(nodeRef); + } + catch (InvalidNodeRefException e) + { + return; + } + if (report.getCreated() != null) + { + SimpleAccessControlEntry entry = new SimpleAccessControlEntry(); + entry.setAuthority(authority); + entry.setPermission(permission); + entry.setAccessStatus(allow ? AccessStatus.ALLOWED : AccessStatus.DENIED); + entry.setAceType(ACEType.ALL); + List changes = aclDaoComponent.setAccessControlEntry(report.getCreated().getId(), entry); + List all = new ArrayList(changes.size() + report.getChanges().size()); + all.addAll(report.getChanges()); + all.addAll(changes); + getACLDAO(nodeRef).updateChangedAcls(nodeRef, all); + } + } + + public void setPermission(PermissionEntry permissionEntry) + { + setPermission(permissionEntry.getNodeRef(), permissionEntry.getAuthority(), permissionEntry.getPermissionReference(), permissionEntry.isAllowed()); + } + + public void setPermission(NodePermissionEntry nodePermissionEntry) + { + NodeRef nodeRef = nodePermissionEntry.getNodeRef(); + + // Get the access control list + // Note the logic here requires to know whether it was created or not + DbAccessControlList existing = getAccessControlList(nodeRef); + if (existing != null) + { + deletePermissions(nodeRef); + } + // create the access control list + CreationReport report = createAccessControlList(nodeRef, nodePermissionEntry.inheritPermissions(), existing); + + // add all entries + for (PermissionEntry pe : nodePermissionEntry.getPermissionEntries()) + { + SimpleAccessControlEntry entry = new SimpleAccessControlEntry(); + entry.setAuthority(pe.getAuthority()); + entry.setPermission(pe.getPermissionReference()); + entry.setAccessStatus(pe.isAllowed() ? AccessStatus.ALLOWED : AccessStatus.DENIED); + entry.setAceType(ACEType.ALL); + List changes = aclDaoComponent.setAccessControlEntry(report.getCreated().getId(), entry); + List all = new ArrayList(changes.size() + report.getChanges().size()); + all.addAll(report.getChanges()); + all.addAll(changes); + getACLDAO(nodeRef).updateChangedAcls(nodeRef, all); + } + } + + public void setInheritParentPermissions(NodeRef nodeRef, boolean inheritParentPermissions) + { + DbAccessControlList acl = getAccessControlList(nodeRef); + if ((acl == null) && (inheritParentPermissions == INHERIT_PERMISSIONS_DEFAULT)) + { + return; + } + if ((acl != null) && (acl.getInherits() == inheritParentPermissions)) + { + return; + } + + CreationReport report = getMutableAccessControlList(nodeRef); + + List changes; + if (!inheritParentPermissions) + { + changes = aclDaoComponent.disableInheritance(report.getCreated().getId(), false); + } + else + { + // TODO: Find inheritance + changes = aclDaoComponent.enableInheritance(report.getCreated().getId(), null); + } + List all = new ArrayList(changes.size() + report.getChanges().size()); + all.addAll(report.getChanges()); + all.addAll(changes); + getACLDAO(nodeRef).updateChangedAcls(nodeRef, all); + } + + protected abstract CreationReport createAccessControlList(NodeRef nodeRef, boolean inherit, DbAccessControlList existing); + + static class CreationReport + { + DbAccessControlList created; + + List changes; + + CreationReport(DbAccessControlList created, List changes) + { + this.created = created; + this.changes = changes; + } + + public void setChanges(List changes) + { + this.changes = changes; + } + + public void setCreated(DbAccessControlList created) + { + this.created = created; + } + + public List getChanges() + { + return changes; + } + + public DbAccessControlList getCreated() + { + return created; + } + + } +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java new file mode 100644 index 0000000000..9e99a72f5a --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/AclDaoComponentImpl.java @@ -0,0 +1,1736 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.hibernate; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.alfresco.repo.domain.DbAccessControlEntry; +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.domain.DbAccessControlListChangeSet; +import org.alfresco.repo.domain.DbAccessControlListMember; +import org.alfresco.repo.domain.DbAuthority; +import org.alfresco.repo.domain.DbPermission; +import org.alfresco.repo.node.db.hibernate.HibernateNodeDaoServiceImpl; +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.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.SimplePermissionReference; +import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.util.GUID; +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 DAO to manage ACL persistence + * + * @author andyh + */ +public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoComponent +{ + private static Log logger = LogFactory.getLog(HibernateNodeDaoServiceImpl.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_FOR_ACL = "permission.GetAcesForAcl"; + + 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_AVM_NODES_BY_INDIRECTION = "permission.FindAvmNodesIndirection"; + + static String QUERY_GET_LATEST_ACL_BY_ACLID = "permission.FindLatestAclByGuid"; + + private enum WriteMode + { + TRUNCATE_INHERITED, ADD_INHERITED, CHANGE_INHERITED, REMOVE_INHERITED, INSERT_INHERITED, COPY_UPDATE_AND_INHERIT, COPY_ONLY; + } + + public AclDaoComponentImpl() + { + super(); + DbAccessControlListImpl.setAclDaoComponent(this); + } + + 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); + } + + private Long createAccessControlListImpl(AccessControlListProperties properties) + { + 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); + return created; + } + + @SuppressWarnings("unchecked") + private void getWritable(final Long id, final Long parent, AccessControlEntry 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); + 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, AccessControlEntry 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); + 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 + */ + @SuppressWarnings("unchecked") + private AclChange getWritable(final Long id, final Long parent, AccessControlEntry 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()) + { + 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 COPY_ONLY: + default: + break; + } + if (inheritsFrom != null) + { + acl.setInheritsFrom(inheritsFrom); + } + 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 COPY_ONLY: + default: + break; + } + if (inheritsFrom != null) + { + acl.setInheritsFrom(inheritsFrom); + } + 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); + + // 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); + 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); + + } + + // 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 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); + 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, AccessControlEntry exclude, int depth) + { + 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); + return query.list(); + } + }; + List members = (List) getHibernateTemplate().execute(callback); + + boolean removed = false; + for (DbAccessControlListMember member : members) + { + if ((exclude != null) && excluder.matches(member.getAccessControlEntry(), depth, member.getPosition())) + { + getHibernateTemplate().delete(member); + removed = true; + } + } + if (removed) + { + getHibernateTemplate().flush(); + } + + } + + /** + * 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); + } + } + } + + 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); + 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) + { + getHibernateTemplate().flush(); + } + } + + @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); + 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) + { + getHibernateTemplate().flush(); + } + } + + private void addInherited(DbAccessControlList acl, List inherited, List positions, int depth) + { + 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); + + } + + } + + @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); + 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) + { + getHibernateTemplate().flush(); + } + + 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); + + } + + } + + /** + * 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); + return query.list(); + } + }; + List results = (List) getHibernateTemplate().execute(callback); + + // fix up members and extract acls and aces + + for (Object[] ids : results) + { + // Delete acl entry + DbAccessControlListMember member = (DbAccessControlListMember) getHibernateTemplate().get(DbAccessControlListMemberImpl.class, (Long) ids[0]); + Long aclId = ((Long) ids[1]); + 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); + } + + // remove authority + + callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_AUTHORITY); + query.setParameter("authority", authority); + return query.uniqueResult(); + } + }; + DbAuthority dbAuthority = (DbAuthority) getHibernateTemplate().execute(callback); + if (dbAuthority != null) + { + getHibernateTemplate().delete(dbAuthority); + } + + 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); + return query.list(); + } + }; + List members = (List) getHibernateTemplate().execute(callback); + + for (DbAccessControlListMember member : members) + { + getHibernateTemplate().delete(member); + } + + } + + @SuppressWarnings("unchecked") + public List deleteAccessControlList(final Long id) + { + List acls = new ArrayList(); + + 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 teh defining acl"); + } + + if ((acl.getAclType() == ACLType.DEFINING) || (acl.getAclType() == ACLType.LAYERED)) + { + if (acl.getInheritedAclId() != -1) + { + final DbAccessControlList inherited = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, acl.getInheritedAclId()); + 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); + return query.list(); + } + }; + List inheritors = (List) getHibernateTemplate().execute(callback); + for (Long nextId : inheritors) + { + 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); + 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); + return query.list(); + } + }; + List inheritors = (List) getHibernateTemplate().execute(callback); + for (Long nextId : inheritors) + { + 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); + return query.list(); + } + }; + List members = (List) getHibernateTemplate().execute(callback); + + for (DbAccessControlListMember member : members) + { + getHibernateTemplate().delete(member); + } + + getHibernateTemplate().delete(acl); + } + + 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)); + getWritable(id, null, 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)); + getWritable(id, null, pattern, null, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT); + return changes; + } + + public List deleteAccessControlEntries(Long id, AccessControlEntry pattern) + { + List changes = new ArrayList(); + getWritable(id, null, pattern, null, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT); + return changes; + } + + public Long[] findAccessControlList(AccessControlEntry pattern) + { + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + public AccessControlList getAccessControlList(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_GET_ACES_FOR_ACL); + query.setParameter("id", id); + return query.list(); + } + }; + List members = (List) getHibernateTemplate().execute(callback); + + List entries = new ArrayList(); + 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); + } + SimplePermissionReference permissionRefernce = new SimplePermissionReference(member.getAccessControlEntry().getPermission().getTypeQname(), member + .getAccessControlEntry().getPermission().getName()); + entry.setPermission(permissionRefernce); + entry.setPosition(member.getPosition()); + + entries.add(entry); + + } + + 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()); + 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); + @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(); + } + + @SuppressWarnings("unchecked") + 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 + { + // Assuem 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); + 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); + } + getWritable(target, actualInheritedId, null, null, actualInheritedId, true, changes, WriteMode.CHANGE_INHERITED); + + return changes; + + } + + public List setAccessControlEntry(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 auth + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_AUTHORITY); + query.setParameter("authority", ace.getAuthority()); + return query.uniqueResult(); + } + }; + DbAuthority authority = (DbAuthority) getHibernateTemplate().execute(callback); + if (authority == null) + { + DbAuthorityImpl newAuthority = new DbAuthorityImpl(); + newAuthority.setAuthority(ace.getAuthority()); + authority = newAuthority; + getHibernateTemplate().save(newAuthority); + } + + // Find permission + + callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_PERMISSION); + query.setParameter("permissionTypeQName", ace.getPermission().getQName()); + query.setParameter("permissionName", ace.getPermission().getName()); + return query.uniqueResult(); + } + }; + DbPermission permission = (DbPermission) getHibernateTemplate().execute(callback); + if (permission == null) + { + DbPermissionImpl newPermission = new DbPermissionImpl(); + newPermission.setTypeQname(ace.getPermission().getQName()); + newPermission.setName(ace.getPermission().getName()); + permission = newPermission; + getHibernateTemplate().save(newPermission); + } + + // Find context + + if (ace.getContext() != null) + { + throw new UnsupportedOperationException(); + } + + // Find ACE + + final DbAuthority finalAuthority = authority; + final DbPermission finalPermission = permission; + callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_ACE_WITH_NO_CONTEXT); + query.setParameter("permissionId", finalPermission.getId()); + query.setParameter("authorityId", finalAuthority.getId()); + query.setParameter("allowed", (ace.getAccessStatus() == AccessStatus.ALLOWED) ? true : false); + query.setParameter("applies", ace.getAceType().getId()); + return query.uniqueResult(); + } + }; + DbAccessControlEntry entry = (DbAccessControlEntry) getHibernateTemplate().execute(callback); + if (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); + } + + // 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); + getWritable(id, null, exclude, toAdd, null, true, changes, WriteMode.COPY_UPDATE_AND_INHERIT); + + return changes; + } + + 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); + 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()) + { + 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); + } + else + { + getWritable(id, null, null, null, null, false, changes, WriteMode.COPY_ONLY); + } + + return mergeInheritedAccessControlList(parent, changes.get(0).getAfter()); + } + } + + 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); + 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); + } + } + + 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); + inheritedId = getInheritedAccessControlList(toCopy); + if ((inheritedId != null) && (!inheritedId.equals(toCopy))) + { + DbAccessControlList inheritedAcl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, inheritedId); + inheritedAcl.setRequiresVersion(true); + } + return toCopy; + case REDIRECT: + 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; + } + 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); + } + 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; + } + + @SuppressWarnings("unchecked") + public List getAvmNodesByACL(final Long id) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_AVM_NODES_BY_ACL); + query.setParameter("acl", id); + return query.list(); + } + }; + List avmNodeIds = (List) getHibernateTemplate().execute(callback); + return avmNodeIds; + } + + @SuppressWarnings("unchecked") + public List getAvmNodesByIndirection(final String indirection) + { + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session.getNamedQuery(QUERY_GET_AVM_NODES_BY_INDIRECTION); + query.setParameter("indirection", indirection); + return query.list(); + } + }; + List avmNodeIds = (List) getHibernateTemplate().execute(callback); + return avmNodeIds; + } + + private List disableInheritanceImpl(Long id, boolean setInheritedOnAcl, DbAccessControlList acl) + { + List changes = new ArrayList(); + + if (!acl.getInherits()) + { + return Collections. emptyList(); + } + 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); + getWritable(acl.getId(), null, null, null, null, true, changes, WriteMode.TRUNCATE_INHERITED); + + // set Inherited + + 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); + 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); + } + SimplePermissionReference permissionRefernce = new SimplePermissionReference(member.getAccessControlEntry().getPermission().getTypeQname(), member + .getAccessControlEntry().getPermission().getName()); + entry.setPermission(permissionRefernce); + entry.setPosition(Integer.valueOf(0)); + + setAccessControlEntry(id, entry); + } + } + + 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); + 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 AccessControlEntry pattern; + + AcePatternMatcher(AccessControlEntry pattern) + { + this.pattern = pattern; + } + + boolean matches(DbAccessControlEntry entry, int position, int memberPosition) + { + if (pattern == null) + { + return true; + } + + 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) + { + if (!pattern.getAuthority().equals(entry.getAuthority().getAuthority())) + { + return false; + } + } + + if (pattern.getContext() != null) + { + throw new IllegalArgumentException("Context not yet supported"); + } + + if (pattern.getPermission() != null) + { + if ((pattern.getPermission().getQName() != null) && (!pattern.getPermission().getQName().equals(entry.getPermission().getTypeQname()))) + { + return false; + } + if ((pattern.getPermission().getName() != null) && (!pattern.getPermission().getName().equals(entry.getPermission().getName()))) + { + return false; + } + } + + if (pattern.getPosition() != null) + { + if (pattern.getPosition().intValue() >= 0) + { + if (memberPosition != position) + { + return false; + } + } + else if (pattern.getPosition().intValue() == -1) + { + if (memberPosition <= 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(); + } + + /** + * Just flushes the session + */ + public void flush() + { + getSession().flush(); + } + + /** + * 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; + } + + public void setAfter(Long after) + { + this.after = after; + } + + public void setBefore(Long before) + { + this.before = before; + } + + public ACLType getTypeAfter() + { + return typeAfter; + } + + public void setTypeAfter(ACLType typeAfter) + { + this.typeAfter = typeAfter; + } + + public ACLType getTypeBefore() + { + return 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(); + } + + } +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlEntryContextImpl.java b/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlEntryContextImpl.java new file mode 100644 index 0000000000..baa9db6e17 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlEntryContextImpl.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.hibernate; + +import java.io.Serializable; + +import 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 index 22df86c9d9..57aee8b0bf 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlEntryImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlEntryImpl.java @@ -27,32 +27,41 @@ 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.DbAccessControlEntryContext; import org.alfresco.repo.domain.DbAuthority; import org.alfresco.repo.domain.DbPermission; -import org.alfresco.util.EqualsHelper; +import org.alfresco.repo.domain.DbPermissionKey; +import org.alfresco.repo.security.permissions.ACEType; +import org.alfresco.service.namespace.QName; +import org.hibernate.CallbackException; +import org.hibernate.Session; /** * Persisted permission entries * * @author andyh */ -public class DbAccessControlEntryImpl extends LifecycleAdapter - implements DbAccessControlEntry, Serializable +public class DbAccessControlEntryImpl implements DbAccessControlEntry, Serializable { private static final long serialVersionUID = -418837862334064582L; private Long id; + private Long version; - /** The container of these entries */ - private DbAccessControlList accessControlList; + /** 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(); @@ -62,58 +71,69 @@ public class DbAccessControlEntryImpl extends LifecycleAdapter public String toString() { StringBuilder sb = new StringBuilder(128); - sb.append("DbAccessControlEntryImpl") - .append("[ id=").append(id) - .append(", acl=").append(accessControlList.getId()) - .append(", permission=").append(permission.getKey()) - .append(", authority=").append(authority.getRecipient()) - .append("]"); + 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(", authorityDeleted=").append(", aceType=") + .append(ACEType.getACETypeFromId(aceType)).append(", context=").append(context).append("]"); return sb.toString(); } - @Override - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (!(o instanceof DbAccessControlEntry)) - { - return false; - } - DbAccessControlEntry other = (DbAccessControlEntry) o; - if (EqualsHelper.nullSafeEquals(id, other.getId())) - { - return true; - } - else - { - return (EqualsHelper.nullSafeEquals(this.permission, other.getPermission()) - && EqualsHelper.nullSafeEquals(this.authority, other.getAuthority())); - } - } - @Override public int hashCode() { - int hashCode = 0; - if (permission != null) + 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) { - hashCode = hashCode * 37 + permission.hashCode(); + if (other.authority != null) + return false; } - if (authority != null) + else if (!authority.equals(other.authority)) + return false; + if (context == null) { - hashCode = hashCode * 37 + authority.hashCode(); + if (other.context != null) + return false; } - return hashCode; + 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 */ @@ -137,16 +157,6 @@ public class DbAccessControlEntryImpl extends LifecycleAdapter this.version = version; } - public DbAccessControlList getAccessControlList() - { - return accessControlList; - } - - public void setAccessControlList(DbAccessControlList nodePermissionEntry) - { - this.accessControlList = nodePermissionEntry; - } - public DbPermission getPermission() { return permission; @@ -177,12 +187,54 @@ public class DbAccessControlEntryImpl extends LifecycleAdapter 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() { - // remove the instance from the access control list - @SuppressWarnings("unused") - boolean removed = getAccessControlList().getEntries().remove(this); - // delete the instance - getSession().delete(this); + 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 new file mode 100644 index 0000000000..5754c732dc --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListChangeSetImpl.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.hibernate; + +import java.io.Serializable; + +import 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 index f220544ab2..4cb6bcd7df 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListImpl.java @@ -26,80 +26,102 @@ package org.alfresco.repo.domain.hibernate; import java.io.Serializable; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; +import 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 +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 Set entries; + + 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() { - entries = new HashSet(5); } - + @Override public String toString() { StringBuilder sb = new StringBuilder(128); - sb.append("DbAccessControlListImpl") - .append("[ id=").append(id) - .append(", entries=").append(entries.size()) - .append(", inherits=").append(inherits) - .append("]"); + 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 equals(Object o) + public boolean onDelete(Session session) throws CallbackException { - if (this == o) - { - return true; - } - if (!(o instanceof DbAccessControlList)) - { - return false; - } - DbAccessControlList other = (DbAccessControlList) o; - - return (this.inherits == other.getInherits()); - } - - @Override - public int hashCode() - { - return (inherits == false ? 0 : 17); + s_aclDaoComponent.onDeleteAccessControlList(id); + return super.onDelete(session); } public Long getId() { return id; } - + /** * Hibernate use */ @@ -123,20 +145,6 @@ public class DbAccessControlListImpl extends LifecycleAdapter this.version = version; } - public Set getEntries() - { - return entries; - } - - /** - * For Hibernate use - */ - @SuppressWarnings("unused") - private void setEntries(Set entries) - { - this.entries = entries; - } - public boolean getInherits() { return inherits; @@ -147,130 +155,131 @@ public class DbAccessControlListImpl extends LifecycleAdapter this.inherits = inherits; } - /** - * @see #deleteEntry(String, DbPermissionKey) - */ - public int deleteEntriesForAuthority(String authority) + public String getAclId() { - return deleteEntry(authority, null); + 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(); } /** - * @see #deleteEntry(String, DbPermissionKey) + * Hibernate */ - public int deleteEntriesForPermission(DbPermissionKey permissionKey) + + private int getType() { - return deleteEntry(null, permissionKey); + return aclType; } - public int deleteEntry(String authority, DbPermissionKey permissionKey) + private void setType(int aclType) { - List toDelete = new ArrayList(2); - for (DbAccessControlEntry entry : entries) - { - if (authority != null && !authority.equals(entry.getAuthority().getRecipient())) - { - // authority is not a match - continue; - } - else if (permissionKey != null && !permissionKey.equals(entry.getPermission().getKey())) - { - // permission is not a match - continue; - } - toDelete.add(entry); - } - // delete them - for (DbAccessControlEntry entry : toDelete) - { - // remove from the entry list - entry.delete(); - } - // Fix issues with deleting and adding permissions - // See AR-918 - this.getSession().flush(); - // done - if (logger.isDebugEnabled()) - { - logger.debug("Deleted " + toDelete.size() + " access entries: \n" + - " access control list: " + id + "\n" + - " authority: " + authority + "\n" + - " permission: " + permissionKey); - } - return toDelete.size(); + this.aclType = aclType; } - public int deleteEntries() + public long getAclVersion() { - /* - * We don't do the full delete-remove-from-set thing here. Just delete each child entity - * and then clear the entry set. - */ - - Session session = getSession(); - List toDelete = new ArrayList(entries); - // delete each entry - for (DbAccessControlEntry entry : toDelete) - { - session.delete(entry); - } - // clear the list - int count = entries.size(); - entries.clear(); - // done - if (logger.isDebugEnabled()) - { - logger.debug("Deleted " + count + " access entries for access control list " + this.id); - } - return count; + return aclVersion; } - public DbAccessControlEntry getEntry(String authority, DbPermissionKey permissionKey) + public void setAclVersion(long aclVersion) { - for (DbAccessControlEntry entry : entries) - { - DbAuthority authorityEntity = entry.getAuthority(); - DbPermission permissionEntity = entry.getPermission(); - // check for a match - if (authorityEntity.getRecipient().equals(authority) - && permissionEntity.getKey().equals(permissionKey)) - { - // found it - return entry; - } - } - return null; + this.aclVersion = aclVersion; } - public DbAccessControlEntryImpl newEntry(DbPermission permission, DbAuthority authority, boolean allowed) + public Long getInheritedAclId() { - DbAccessControlEntryImpl accessControlEntry = new DbAccessControlEntryImpl(); - // fill - accessControlEntry.setAccessControlList(this); - accessControlEntry.setPermission(permission); - accessControlEntry.setAuthority(authority); - accessControlEntry.setAllowed(allowed); - // save it - getSession().save(accessControlEntry); - // maintain inverse set on the acl - getEntries().add(accessControlEntry); - // done - return accessControlEntry; + return inheritedAclId; } - - /** - * Make a copy of this ACL. - * @return The copy. - */ - public DbAccessControlList getCopy() + + public void setInheritedAclId(Long inheritedAclId) { - DbAccessControlList newAcl = - new DbAccessControlListImpl(); - getSession().save(newAcl); - for (DbAccessControlEntry entry : entries) + 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) { - newAcl.newEntry(entry.getPermission(), entry.getAuthority(), entry.isAllowed()); + s_aclDaoComponent.mergeInheritedAccessControlList(indirectedAcl, id); } - return newAcl; + 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 new file mode 100644 index 0000000000..cb2fb365a7 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/DbAccessControlListMemberImpl.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.hibernate; + +import java.io.Serializable; + +import 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 new file mode 100644 index 0000000000..8915778487 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/DbAuthorityAliasImpl.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.hibernate; + +import java.io.Serializable; + +import 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 index 2ee1e627c9..8e26c653cb 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/DbAuthorityImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/DbAuthorityImpl.java @@ -25,14 +25,11 @@ package org.alfresco.repo.domain.hibernate; import java.io.Serializable; -import java.util.HashSet; -import java.util.Set; import org.alfresco.repo.domain.DbAuthority; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.CallbackException; -import org.hibernate.Query; import org.hibernate.Session; /** @@ -40,20 +37,31 @@ import org.hibernate.Session; * * @author andyh */ -public class DbAuthorityImpl extends LifecycleAdapter +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 recipient; - private Set externalKeys; + private String authority; public DbAuthorityImpl() { - externalKeys = new HashSet(); + } + + @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 @@ -68,44 +76,27 @@ public class DbAuthorityImpl extends LifecycleAdapter return false; } DbAuthority other = (DbAuthority)o; - return this.getRecipient().equals(other.getRecipient()); + return this.getAuthority().equals(other.getAuthority()); } @Override public int hashCode() { - return getRecipient().hashCode(); + return getAuthority().hashCode(); } - public int deleteEntries() + public Long getId() { - /* - * This can use a delete direct to the database as well, but then care must be taken - * to evict the instances from the session. - */ - - // bypass L2 cache and get all entries for this list - Query query = getSession() - .getNamedQuery(PermissionsDaoComponentImpl.QUERY_GET_AC_ENTRIES_FOR_AUTHORITY) - .setString("authorityRecipient", this.recipient); - int count = HibernateHelper.deleteDbAccessControlEntries(getSession(), query); - // done - if (logger.isDebugEnabled()) - { - logger.debug("Deleted " + count + " access entries for access control list " + this.recipient); - } - return count; + return id; } - - /** - * Ensures that all this access control list's entries have been deleted. - */ - public boolean onDelete(Session session) throws CallbackException + + @SuppressWarnings("unused") + private void setId(Long id) { - deleteEntries(); - return super.onDelete(session); + this.id = id; } - + + public Long getVersion() { return version; @@ -120,25 +111,14 @@ public class DbAuthorityImpl extends LifecycleAdapter this.version = version; } - public String getRecipient() + public String getAuthority() { - return recipient; + return authority; } - public void setRecipient(String recipient) + public void setAuthority(String authority) { - this.recipient = recipient; - } - - public Set getExternalKeys() - { - return externalKeys; - } - - // Hibernate - /* package */ void setExternalKeys(Set externalKeys) - { - this.externalKeys = externalKeys; + this.authority = authority; } /** @@ -150,6 +130,7 @@ public class DbAuthorityImpl extends LifecycleAdapter */ public static DbAuthority find(Session session, String authority) { - return (DbAuthority) session.get(DbAuthorityImpl.class, 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 index 7abbfb859b..02cfa74367 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/DbPermissionImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/DbPermissionImpl.java @@ -41,49 +41,47 @@ import org.hibernate.Session; * * @author andyh */ -public class DbPermissionImpl extends LifecycleAdapter - implements DbPermission, Serializable -{ +public class DbPermissionImpl implements DbPermission, Serializable +{ private static final long serialVersionUID = -6352566900815035461L; - + private static Log logger = LogFactory.getLog(DbPermissionImpl.class); private Long id; + private Long version; + private QName typeQname; + private String name; public DbPermissionImpl() { super(); } - + @Override public String toString() { StringBuilder sb = new StringBuilder(128); - sb.append("PermissionImpl") - .append("[ id=").append(id) - .append(", typeQname=").append(typeQname) - .append(", name=").append(getName()) - .append("]"); + sb.append("DbPermissionImpl").append("[ id=").append(id).append(", version=").append(version).append(", typeQname=").append(typeQname).append(", name=").append(getName()) + .append("]"); return sb.toString(); } @Override public boolean equals(Object o) { - if(this == o) + if (this == o) { return true; } - if(!(o instanceof DbPermission)) + if (!(o instanceof DbPermission)) { return false; } - DbPermission other = (DbPermission)o; - return (EqualsHelper.nullSafeEquals(typeQname, other.getTypeQname())) - && (EqualsHelper.nullSafeEquals(name, other.getName())); + DbPermission other = (DbPermission) o; + return (EqualsHelper.nullSafeEquals(typeQname, other.getTypeQname())) && (EqualsHelper.nullSafeEquals(name, other.getName())); } @Override @@ -91,35 +89,6 @@ public class DbPermissionImpl extends LifecycleAdapter { return typeQname.hashCode() + (37 * name.hashCode()); } - - public int deleteEntries() - { - /* - * This can use a delete direct to the database as well, but then care must be taken - * to evict the instances from the session. - */ - - // bypass L2 cache and get all entries for this list - Query query = getSession() - .getNamedQuery(PermissionsDaoComponentImpl.QUERY_GET_AC_ENTRIES_FOR_PERMISSION) - .setSerializable("permissionId", this.id); - int count = HibernateHelper.deleteDbAccessControlEntries(getSession(), query); - // done - if (logger.isDebugEnabled()) - { - logger.debug("Deleted " + count + " access entries for permission " + this.id); - } - return count; - } - - /** - * Ensures that all this access control list's entries have been deleted. - */ - public boolean onDelete(Session session) throws CallbackException - { - deleteEntries(); - return super.onDelete(session); - } public Long getId() { @@ -168,7 +137,7 @@ public class DbPermissionImpl extends LifecycleAdapter { this.name = name; } - + public DbPermissionKey getKey() { return new DbPermissionKey(typeQname, name); @@ -177,17 +146,21 @@ public class DbPermissionImpl extends LifecycleAdapter /** * 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 + * @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(); + // 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/NodeAccessControlListDAO.java b/source/java/org/alfresco/repo/domain/hibernate/NodeAccessControlListDAO.java index 0bbd84ed3f..a79ead44fa 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/NodeAccessControlListDAO.java +++ b/source/java/org/alfresco/repo/domain/hibernate/NodeAccessControlListDAO.java @@ -1,88 +1,149 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" */ - -package org.alfresco.repo.domain.hibernate; - -import org.alfresco.repo.domain.AccessControlListDAO; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.Node; -import org.alfresco.repo.node.db.NodeDaoService; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; -import org.alfresco.service.cmr.repository.NodeRef; -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; - } - - /** - * Get the ACL from a node. - * @param nodeRef The reference to the node. - * @return The ACL. - * @throws InvalidNodeRefException - */ - public DbAccessControlList getAccessControlList(NodeRef nodeRef) - { - Node node = fNodeDAOService.getNode(nodeRef); - if (node == null) - { - throw new InvalidNodeRefException(nodeRef); - } - return node.getAccessControlList(); - } - - /** - * Set the ACL on a node. - * @param nodeRef The reference to the node. - * @param acl The ACL. - * @throws InvalidNodeRefException - */ - public void setAccessControlList(NodeRef nodeRef, DbAccessControlList acl) - { - Node node = fNodeDAOService.getNode(nodeRef); - if (node == null) - { - throw new InvalidNodeRefException(nodeRef); - } - node.setAccessControlList(acl); - } -} +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" */ + +package org.alfresco.repo.domain.hibernate; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.alfresco.repo.domain.AccessControlListDAO; +import org.alfresco.repo.domain.ChildAssoc; +import org.alfresco.repo.domain.DbAccessControlList; +import org.alfresco.repo.domain.Node; +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.InvalidNodeRefException; +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * The Node implementation for getting and setting ACLs. + * + * @author britt + */ +public class NodeAccessControlListDAO implements AccessControlListDAO +{ + /** + * The DAO for Nodes. + */ + private NodeDaoService fNodeDAOService; + + /** + * Default constructor. + */ + public NodeAccessControlListDAO() + { + } + + public void setNodeDaoService(NodeDaoService nodeDAOService) + { + fNodeDAOService = nodeDAOService; + } + + /** + * Get the ACL from a node. + * + * @param nodeRef + * The reference to the node. + * @return The ACL. + * @throws InvalidNodeRefException + */ + public DbAccessControlList getAccessControlList(NodeRef nodeRef) + { + Node node = fNodeDAOService.getNode(nodeRef); + if (node == null) + { + throw new InvalidNodeRefException(nodeRef); + } + return node.getAccessControlList(); + } + + /** + * Set the ACL on a node. + * + * @param nodeRef + * The reference to the node. + * @param acl + * The ACL. + * @throws InvalidNodeRefException + */ + public void setAccessControlList(NodeRef nodeRef, DbAccessControlList acl) + { + Node node = fNodeDAOService.getNode(nodeRef); + if (node == null) + { + throw new InvalidNodeRefException(nodeRef); + } + node.setAccessControlList(acl); + } + + public void updateChangedAcls(NodeRef startingPoint, List changes) + { + // Nothing to do here + } + + public List setInheritanceForChildren(NodeRef parent, Long mergeFrom) + { + // Nothing to do here + return Collections. emptyList(); + } + + public Long getIndirectAcl(NodeRef nodeRef) + { + return getAccessControlList(nodeRef).getId(); + } + + public Long getInheritedAcl(NodeRef nodeRef) + { + Node node = fNodeDAOService.getNode(nodeRef); + ChildAssoc ca = fNodeDAOService.getPrimaryParentAssoc(node); + if ((ca != null) && (ca.getParent() != null)) + { + DbAccessControlList acl = getAccessControlList(ca.getParent().getNodeRef()); + if (acl != null) + { + return acl.getId(); + } + else + { + return null; + } + } + else + { + return null; + } + } + + public void forceCopy(NodeRef nodeRef) + { + // nothing to do; + } + + public Map patchAcls() + { + throw new UnsupportedOperationException(); + } + +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/OldADMPermissionsDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/hibernate/OldADMPermissionsDaoComponentImpl.java new file mode 100644 index 0000000000..d7b279eba4 --- /dev/null +++ b/source/java/org/alfresco/repo/domain/hibernate/OldADMPermissionsDaoComponentImpl.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.domain.hibernate; + +import java.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, null); + aclDaoComponent.deleteAccessControlList(acl.getId()); + } + } + + + +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml index c14007696a..9d738ef5e2 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/Permission.hbm.xml @@ -5,6 +5,23 @@ 'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd'> + + + + + + + + + - - - - - + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - select distinct + select permission from org.alfresco.repo.domain.hibernate.DbPermissionImpl as permission @@ -142,7 +238,108 @@ permission.typeQname = :permissionTypeQName 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 + 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 + aclmem + from + org.alfresco.repo.domain.hibernate.DbAccessControlListMemberImpl as aclmem + where + aclmem.accessControlList.id = :id + + + + select + acl.id + from + org.alfresco.repo.domain.hibernate.DbAccessControlListImpl as acl + where acl.inheritsFrom = :id and acl.inherits = true + + + + select + node.id + from + org.alfresco.repo.avm.AVMNodeImpl node + where node.acl.id = :acl + + + + select + node.id + from + org.alfresco.repo.avm.LayeredDirectoryNodeImpl node + where node.primaryIndirection = true and node.indirection = :indirection + + + + select + acl.id + from + org.alfresco.repo.domain.hibernate.DbAccessControlListImpl as acl + where acl.aclId = :aclId and latest = true + + + \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/hibernate/PermissionsDaoComponentImpl.java b/source/java/org/alfresco/repo/domain/hibernate/PermissionsDaoComponentImpl.java index aa97ad444a..6142717515 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/PermissionsDaoComponentImpl.java +++ b/source/java/org/alfresco/repo/domain/hibernate/PermissionsDaoComponentImpl.java @@ -24,226 +24,107 @@ */ package org.alfresco.repo.domain.hibernate; -import java.util.Collection; +import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.List; -import org.alfresco.repo.domain.AccessControlListDAO; -import org.alfresco.repo.domain.DbAccessControlEntry; import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.DbAuthority; -import org.alfresco.repo.domain.DbPermission; -import org.alfresco.repo.domain.DbPermissionKey; -import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.NodeStatus; -import org.alfresco.repo.security.permissions.NodePermissionEntry; -import org.alfresco.repo.security.permissions.PermissionEntry; -import org.alfresco.repo.security.permissions.PermissionReference; -import org.alfresco.repo.security.permissions.impl.AccessPermissionImpl; -import org.alfresco.repo.security.permissions.impl.PermissionReferenceImpl; -import org.alfresco.repo.security.permissions.impl.PermissionsDaoComponent; -import org.alfresco.repo.security.permissions.impl.SimpleNodePermissionEntry; -import org.alfresco.repo.security.permissions.impl.SimplePermissionEntry; -import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; -import org.alfresco.repo.transaction.TransactionalDao; +import org.alfresco.repo.domain.hibernate.AbstractPermissionsDaoComponentImpl.CreationReport; +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.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.security.AccessPermission; -import org.alfresco.service.cmr.security.AccessStatus; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.GUID; -import org.hibernate.Query; -import org.hibernate.ScrollMode; -import org.hibernate.ScrollableResults; -import org.hibernate.Session; -import org.springframework.orm.hibernate3.HibernateCallback; -import org.springframework.orm.hibernate3.support.HibernateDaoSupport; -/** - * Support for accessing persisted permission information. This class maps between persisted objects and the external - * API defined in the PermissionsDAO interface. - * - * @author andyh - */ -public class PermissionsDaoComponentImpl extends HibernateDaoSupport implements PermissionsDaoComponent, - TransactionalDao +public class PermissionsDaoComponentImpl extends AbstractPermissionsDaoComponentImpl { - private static final boolean INHERIT_PERMISSIONS_DEFAULT = true; - public static final String QUERY_GET_PERMISSION = "permission.GetPermission"; - - public static final String QUERY_GET_AC_ENTRIES_FOR_AUTHORITY = "permission.GetAccessControlEntriesForAuthority"; - - public static final String QUERY_GET_ALL_AC_ENTRIES_FOR_AUTHORITY = "permission.GetAllAccessControlEntriesForAuthority"; - - public static final String QUERY_GET_AC_ENTRIES_FOR_PERMISSION = "permission.GetAccessControlEntriesForPermission"; - - public static final String QUERY_FIND_NODES_BY_PERMISSION = "permission.FindNodesByPermission"; - - private Map fProtocolToACLDAO; - - private AccessControlListDAO fDefaultACLDAO; - - /** a uuid identifying this unique instance */ - private String uuid; - - /** - * - */ - public PermissionsDaoComponentImpl() + @Override + protected CreationReport createAccessControlList(NodeRef nodeRef, boolean inherit, DbAccessControlList existing) { - this.uuid = GUID.generate(); - } - - /** - * Checks equality by type and uuid - */ - public boolean equals(Object obj) - { - if (obj == null) + if (existing == null) { - return false; + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + // Accept default versioning + Long id = aclDaoComponent.createAccessControlList(properties); + 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, aclDaoComponent.getInheritedAccessControlList(id))); + getACLDAO(nodeRef).setAccessControlList(nodeRef, acl); + return new CreationReport(acl, changes); } - else if (!(obj instanceof PermissionsDaoComponentImpl)) + SimpleAccessControlListProperties properties; + Long id; + List changes; + DbAccessControlList acl; + switch (existing.getAclType()) { - return false; - } - PermissionsDaoComponentImpl that = (PermissionsDaoComponentImpl) obj; - return this.uuid.equals(that.uuid); - } + case OLD: + throw new IllegalStateException("Can not mix old and new style permissions"); + case DEFINING: + return new CreationReport(existing, Collections. emptyList()); + case FIXED: + case GLOBAL: + case SHARED: + // create new defining, wire up and report changes to acl required. + properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + properties.setInherits(existing.getInherits()); + // Accept default versioning + id = aclDaoComponent.createAccessControlList(properties); + changes = new ArrayList(); + acl = aclDaoComponent.getDbAccessControlList(id); + changes.add(new AclDaoComponentImpl.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, aclDaoComponent.getInheritedAccessControlList(id))); - /** - * @see #uuid - */ - public int hashCode() - { - return uuid.hashCode(); - } + 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); - /** - * 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) + // create new defining, wire up and report changes to acl required. + properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + if (indirectAclId != null) { - return session.isDirty(); + properties.setInherits(aclDaoComponent.getAccessControlListProperties(indirectAclId).getInherits()); } - }; - // execute the callback - return ((Boolean) getHibernateTemplate().execute(callback)).booleanValue(); - } + // Accept default versioning + id = aclDaoComponent.createAccessControlList(properties); + changes = new ArrayList(); + acl = aclDaoComponent.getDbAccessControlList(id); + changes.add(new AclDaoComponentImpl.AclChangeImpl(existing.getId(), id, existing.getAclType(), acl.getAclType())); + if (indirectAclId != null) + { + AccessControlList indirectAcl = aclDaoComponent.getAccessControlList(indirectAclId); + for (AccessControlEntry entry : indirectAcl.getEntries()) + { + if (entry.getPosition() == 0) + { + aclDaoComponent.setAccessControlEntry(id, entry); + } + } + } + if (inheritedAclId != null) + { + changes.addAll(aclDaoComponent.mergeInheritedAccessControlList(inheritedAclId, id)); + } + // set this to inherit to children + changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, aclDaoComponent.getInheritedAccessControlList(id))); - /** - * Just flushes the session - */ - public void flush() - { - getSession().flush(); - } - - /** - * NO-OP - */ - public void beforeCommit() - { - } - - public void setProtocolToACLDAO(Map map) - { - fProtocolToACLDAO = map; - } - - public void setDefaultACLDAO(AccessControlListDAO defaultACLDAO) - { - fDefaultACLDAO = defaultACLDAO; - } - - public NodePermissionEntry getPermissions(NodeRef nodeRef) - { - // Create the object if it is not found. - // Null objects are not cached in hibernate - // If the object does not exist it will repeatedly query to check its - // non existence. - NodePermissionEntry npe = null; - DbAccessControlList acl = null; - try - { - acl = getAccessControlList(nodeRef, false); + getACLDAO(nodeRef).setAccessControlList(nodeRef, acl); + return new CreationReport(acl, changes); + default: + throw new IllegalStateException("Unknown type " + existing.getAclType()); } - catch (InvalidNodeRefException e) - { - // Do nothing. - } - if (acl == null) - { - // there isn't an access control list for the node - spoof a null one - SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry(nodeRef, true, Collections - . emptySet()); - npe = snpe; - } - else - { - npe = createSimpleNodePermissionEntry(nodeRef); - } - // done - if (logger.isDebugEnabled()) - { - logger.debug("Created access control list for node: \n" + " node: " + nodeRef + "\n" + " acl: " + npe); - } - return npe; - } - - /** - * Get the persisted access control list or create it if required. - * - * @param nodeRef - - * the node for which to create the list - * @param create - - * create the object if it is missing - * @return Returns the current access control list or null if not found - */ - private DbAccessControlList getAccessControlList(NodeRef nodeRef, boolean create) - { - DbAccessControlList acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); - if (acl == null && create) - { - acl = createAccessControlList(nodeRef); - } - // done - if (logger.isDebugEnabled()) - { - logger.debug("Retrieved access control list: \n" + " node: " + nodeRef + "\n" + " list: " + acl); - } - return acl; - } - - /** - * Creates an access control list for the node and removes the entry from the nullPermsionCache. - */ - private DbAccessControlList createAccessControlList(NodeRef nodeRef) - { - DbAccessControlList acl = new DbAccessControlListImpl(); - acl.setInherits(INHERIT_PERMISSIONS_DEFAULT); - getHibernateTemplate().save(acl); - - // maintain inverse - getACLDAO(nodeRef).setAccessControlList(nodeRef, acl); - - // done - if (logger.isDebugEnabled()) - { - logger.debug("Created Access Control List: \n" + " node: " + nodeRef + "\n" + " list: " + acl); - } - return acl; } public void deletePermissions(NodeRef nodeRef) @@ -251,7 +132,7 @@ public class PermissionsDaoComponentImpl extends HibernateDaoSupport implements DbAccessControlList acl = null; try { - acl = getAccessControlList(nodeRef, false); + acl = getAccessControlList(nodeRef); } catch (InvalidNodeRefException e) { @@ -259,422 +140,32 @@ public class PermissionsDaoComponentImpl extends HibernateDaoSupport implements } if (acl != null) { - // maintain referencial integrity - getACLDAO(nodeRef).setAccessControlList(nodeRef, null); - // delete the access control list - it will cascade to the entries - getHibernateTemplate().delete(acl); - } - } - - @SuppressWarnings("unchecked") - public void deletePermissions(final String authority) - { - // get the authority - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) + if (acl.getInheritsFrom() != null) { - Query query = session.getNamedQuery(QUERY_GET_AC_ENTRIES_FOR_AUTHORITY).setString("authorityRecipient", - authority); - return (Integer) HibernateHelper.deleteDbAccessControlEntries(session, query); + Long deleted = acl.getId(); + Long inheritsFrom = acl.getInheritsFrom(); + getACLDAO(nodeRef).setAccessControlList(nodeRef, aclDaoComponent.getDbAccessControlList(inheritsFrom)); + aclDaoComponent.deleteAccessControlList(acl.getId()); + List changes = new ArrayList(); + changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, inheritsFrom)); + getACLDAO(nodeRef).updateChangedAcls(nodeRef, changes); } - }; - Integer deletedCount = (Integer) getHibernateTemplate().execute(callback); - // done - if (logger.isDebugEnabled()) - { - logger.debug("Deleted " + deletedCount + " entries for authority " + authority); - } - } - - public void deletePermissions(final NodeRef nodeRef, final String authority) - { - DbAccessControlList acl = null; - try - { - acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); - } - catch (InvalidNodeRefException e) - { - return; - } - int deletedCount = 0; - if (acl != null) - { - deletedCount = acl.deleteEntriesForAuthority(authority); - } - // done - if (logger.isDebugEnabled()) - { - logger.debug("Deleted " - + deletedCount + "entries for criteria: \n" + " node: " + nodeRef + "\n" + " authority: " - + authority); - } - } - - /** - * Deletes all permission entries (access control list entries) that match the given criteria. Note that the access - * control list for the node is not deleted. - */ - public void deletePermission(NodeRef nodeRef, String authority, PermissionReference permission) - { - DbAccessControlList acl = null; - try - { - acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); - } - catch (InvalidNodeRefException e) - { - return; - } - int deletedCount = 0; - if (acl != null) - { - DbPermissionKey permissionKey = new DbPermissionKey(permission.getQName(), permission.getName()); - deletedCount = acl.deleteEntry(authority, permissionKey); - } - // done - if (logger.isDebugEnabled()) - { - logger.debug("Deleted " - + deletedCount + "entries for criteria: \n" + " node: " + nodeRef + "\n" + " permission: " - + permission + "\n" + " authority: " + authority); - } - } - - public void setPermission(NodeRef nodeRef, String authority, PermissionReference permission, boolean allow) - { - // get the entry - DbAccessControlEntry entry = getAccessControlEntry(nodeRef, authority, permission); - if (entry == null) - { - // need to create it - DbAccessControlList dbAccessControlList = getAccessControlList(nodeRef, true); - DbPermission dbPermission = getPermission(permission, true); - DbAuthority dbAuthority = getAuthority(authority, true); - // set persistent objects - entry = dbAccessControlList.newEntry(dbPermission, dbAuthority, allow); - // done - if (logger.isDebugEnabled()) + else { - logger.debug("Created new access control entry: " + entry); - } - } - else - { - entry.setAllowed(allow); - // done - if (logger.isDebugEnabled()) - { - logger.debug("Updated access control entry: " + entry); + // TODO: could just cear out existing + 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)); + aclDaoComponent.deleteAccessControlList(acl.getId()); + List changes = new ArrayList(); + changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id)); + getACLDAO(nodeRef).updateChangedAcls(nodeRef, changes); } } } - /** - * @param nodeRef - * the node against which to join - * @param authority - * the authority against which to join - * @param perm - * the permission against which to join - * @return Returns all access control entries that match the criteria - */ - private DbAccessControlEntry getAccessControlEntry(NodeRef nodeRef, String authority, PermissionReference permission) - { - DbAccessControlList acl = getAccessControlList(nodeRef, false); - DbAccessControlEntry entry = null; - if (acl != null) - { - DbPermissionKey permissionKey = new DbPermissionKey(permission.getQName(), permission.getName()); - entry = acl.getEntry(authority, permissionKey); - } - // done - if (logger.isDebugEnabled()) - { - logger.debug("" - + (entry == null ? "Did not find" : "Found") + " entry for criteria: \n" + " node: " + nodeRef - + "\n" + " authority: " + authority + "\n" + " permission: " + permission); - } - return entry; - } - - /** - * Utility method to find or create a persisted authority - */ - private DbAuthority getAuthority(String authority, boolean create) - { - DbAuthority entity = (DbAuthority) getHibernateTemplate().get(DbAuthorityImpl.class, authority); - if ((entity == null) && create) - { - entity = new DbAuthorityImpl(); - entity.setRecipient(authority); - getHibernateTemplate().save(entity); - return entity; - } - else - { - return entity; - } - } - - /** - * Utility method to find and optionally create a persisted permission. - */ - private DbPermission getPermission(PermissionReference permissionRef, final boolean create) - { - final QName qname = permissionRef.getQName(); - final String name = permissionRef.getName(); - Session session = getSession(); - - DbPermission dbPermission = DbPermissionImpl.find(session, qname, name); - - // create if necessary - if ((dbPermission == null) && create) - { - dbPermission = new DbPermissionImpl(); - dbPermission.setTypeQname(qname); - dbPermission.setName(name); - getHibernateTemplate().save(dbPermission); - } - return dbPermission; - } - - public void setPermission(PermissionEntry permissionEntry) - { - setPermission(permissionEntry.getNodeRef(), permissionEntry.getAuthority(), permissionEntry - .getPermissionReference(), permissionEntry.isAllowed()); - } - - public void setPermission(NodePermissionEntry nodePermissionEntry) - { - NodeRef nodeRef = nodePermissionEntry.getNodeRef(); - - // Get the access control list - // Note the logic here requires to know whether it was created or not - DbAccessControlList acl = getAccessControlList(nodeRef, false); - if (acl != null) - { - // maintain referencial integrity - getACLDAO(nodeRef).setAccessControlList(nodeRef, null); - // drop the list - getHibernateTemplate().delete(acl); - } - // create the access control list - acl = createAccessControlList(nodeRef); - - // set attributes - acl.setInherits(nodePermissionEntry.inheritPermissions()); - - // add all entries - for (PermissionEntry pe : nodePermissionEntry.getPermissionEntries()) - { - PermissionReference permission = pe.getPermissionReference(); - String authority = pe.getAuthority(); - boolean isAllowed = pe.isAllowed(); - - DbPermission permissionEntity = getPermission(permission, true); - DbAuthority authorityEntity = getAuthority(authority, true); - - @SuppressWarnings("unused") - DbAccessControlEntryImpl entry = acl.newEntry(permissionEntity, authorityEntity, isAllowed); - } - } - - public void setInheritParentPermissions(NodeRef nodeRef, boolean inheritParentPermissions) - { - DbAccessControlList acl = null; - if (!inheritParentPermissions) - { - // Inheritance == true is the default, so only force a create of the ACL if the value false - acl = getAccessControlList(nodeRef, true); - acl.setInherits(false); - } - else - { - acl = getAccessControlList(nodeRef, false); - if (acl != null) - { - acl.setInherits(true); - } - } - } - - public boolean getInheritParentPermissions(NodeRef nodeRef) - { - DbAccessControlList acl = null; - try - { - acl = getAccessControlList(nodeRef, false); - } - catch (InvalidNodeRefException e) - { - return INHERIT_PERMISSIONS_DEFAULT; - } - if (acl == null) - { - return true; - } - else - { - return acl.getInherits(); - } - } - - // Utility methods to create simple detached objects for the outside world - // We do not pass out the hibernate objects - - private SimpleNodePermissionEntry createSimpleNodePermissionEntry(NodeRef nodeRef) - { - DbAccessControlList acl = getACLDAO(nodeRef).getAccessControlList(nodeRef); - if (acl == null) - { - // there isn't an access control list for the node - spoof a null one - SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry(nodeRef, true, Collections - . emptySet()); - return snpe; - } - else - { - Set entries = acl.getEntries(); - SimpleNodePermissionEntry snpe = new SimpleNodePermissionEntry(nodeRef, acl.getInherits(), - createSimplePermissionEntries(nodeRef, entries)); - return snpe; - } - } - - /** - * @param entries - * access control entries - * @return Returns a unique set of entries that can be given back to the outside world - */ - private Set createSimplePermissionEntries(NodeRef nodeRef, - Collection entries) - { - if (entries == null) - { - return null; - } - HashSet spes = new HashSet(entries.size(), 1.0f); - if (entries.size() != 0) - { - for (DbAccessControlEntry entry : entries) - { - spes.add(createSimplePermissionEntry(nodeRef, entry)); - } - } - return spes; - } - - private static SimplePermissionEntry createSimplePermissionEntry(NodeRef nodeRef, DbAccessControlEntry ace) - { - if (ace == null) - { - return null; - } - return new SimplePermissionEntry(nodeRef, createSimplePermissionReference(ace.getPermission()), ace - .getAuthority().getRecipient(), ace.isAllowed() ? AccessStatus.ALLOWED : AccessStatus.DENIED); - } - - private static SimplePermissionReference createSimplePermissionReference(DbPermission perm) - { - if (perm == null) - { - return null; - } - return new SimplePermissionReference(perm.getTypeQname(), perm.getName()); - } - - /** - * Helper to choose appropriate NodeService for the given NodeRef - * - * @param nodeRef - * The NodeRef to dispatch from. - * @return The appropriate NodeService. - */ - private AccessControlListDAO getACLDAO(NodeRef nodeRef) - { - AccessControlListDAO ret = fProtocolToACLDAO.get(nodeRef.getStoreRef().getProtocol()); - if (ret == null) - { - return fDefaultACLDAO; - } - return ret; - } - - @SuppressWarnings("unchecked") - public Map> getAllSetPermissions(final String authority) - { - // get the authority - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_GET_ALL_AC_ENTRIES_FOR_AUTHORITY).setString( - "authorityRecipient", authority); - - Map> result = new HashMap>(); - - ScrollableResults entities = query.scroll(ScrollMode.FORWARD_ONLY); - while (entities.next()) - { - DbAccessControlEntry entry = (DbAccessControlEntry) entities.get(0); - // DbAccessControlList acl = (DbAccessControlList) entities.get(1); - Node node = (Node) entities.get(2); - DbPermission dbPermission = entry.getPermission(); - PermissionReferenceImpl pr = new PermissionReferenceImpl(dbPermission.getTypeQname(), dbPermission - .getName()); - AccessStatus accessStatus = entry.isAllowed() ? AccessStatus.ALLOWED : AccessStatus.DENIED; - AccessPermission ap = new AccessPermissionImpl(pr.toString(), accessStatus, entry.getAuthority() - .getRecipient()); - NodeRef nodeRef = node.getNodeRef(); - Set nodeSet = result.get(nodeRef); - if (nodeSet == null) - { - nodeSet = new HashSet(); - result.put(nodeRef, nodeSet); - } - nodeSet.add(ap); - } - - return result; - } - }; - return (Map>) getHibernateTemplate().execute(callback); - - } - - public Set findNodeByPermission(final String authority, final PermissionReference permission, final boolean allow) - { - // get the authority - HibernateCallback callback = new HibernateCallback() - { - public Object doInHibernate(Session session) - { - Query query = session.getNamedQuery(QUERY_FIND_NODES_BY_PERMISSION).setString( - "authorityRecipient", authority).setBoolean("allow", allow).setString("permissionName", permission.getName()).setString("permissionTypeQname", permission.getQName().toString()); - - Set result = new HashSet(); - - ScrollableResults entities = query.scroll(ScrollMode.FORWARD_ONLY); - while (entities.next()) - { - DbAccessControlEntry entry = (DbAccessControlEntry) entities.get(0); - // DbAccessControlList acl = (DbAccessControlList) entities.get(1); - Node node = (Node) entities.get(2); - DbPermission dbPermission = entry.getPermission(); - PermissionReferenceImpl pr = new PermissionReferenceImpl(dbPermission.getTypeQname(), dbPermission - .getName()); - AccessStatus accessStatus = entry.isAllowed() ? AccessStatus.ALLOWED : AccessStatus.DENIED; - AccessPermission ap = new AccessPermissionImpl(pr.toString(), accessStatus, entry.getAuthority() - .getRecipient()); - NodeRef nodeRef = node.getNodeRef(); - result.add(nodeRef); - } - - return result; - } - }; - return (Set) getHibernateTemplate().execute(callback); - } } diff --git a/source/java/org/alfresco/repo/lock/LockServiceImpl.java b/source/java/org/alfresco/repo/lock/LockServiceImpl.java index fef72e6ea3..759a3fb065 100644 --- a/source/java/org/alfresco/repo/lock/LockServiceImpl.java +++ b/source/java/org/alfresco/repo/lock/LockServiceImpl.java @@ -390,7 +390,7 @@ public class LockServiceImpl implements LockService, * @param userName the user name * @return the lock status */ - private LockStatus getLockStatus(NodeRef nodeRef, String userName) + public LockStatus getLockStatus(NodeRef nodeRef, String userName) { LockStatus result = LockStatus.NO_LOCK; diff --git a/source/java/org/alfresco/repo/search/impl/lucene/analysis/FrenchSnowballAnalyserThatRemovesAccents.java b/source/java/org/alfresco/repo/search/impl/lucene/analysis/FrenchSnowballAnalyserThatRemovesAccents.java new file mode 100644 index 0000000000..2b522ccfdc --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/lucene/analysis/FrenchSnowballAnalyserThatRemovesAccents.java @@ -0,0 +1,25 @@ +package org.alfresco.repo.search.impl.lucene.analysis; + +import java.io.Reader; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.ISOLatin1AccentFilter; +import org.apache.lucene.analysis.TokenStream; + +public class FrenchSnowballAnalyserThatRemovesAccents extends Analyzer +{ + Analyzer analyzer = new FrenchSnowballAnalyser(); + + public FrenchSnowballAnalyserThatRemovesAccents() + { + + } + + public TokenStream tokenStream(String fieldName, Reader reader) + { + TokenStream result = analyzer.tokenStream(fieldName, reader); + result = new ISOLatin1AccentFilter(result); + return result; + } + +} diff --git a/source/java/org/alfresco/repo/security/permissions/ACEType.java b/source/java/org/alfresco/repo/security/permissions/ACEType.java new file mode 100644 index 0000000000..9cba631648 --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/ACEType.java @@ -0,0 +1,91 @@ +/* + * 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.security.permissions; + +/** + * The ACE Type + * @author andyh + * + */ +public enum ACEType +{ + /** + * ACE applies to the object and its children + */ + ALL + { + public int getId() + { + return 0; + } + }, + /** + * ACE applies to the object only + */ + OBJECT + { + public int getId() + { + return 1; + } + }, + /** + * ACE only applies to children + */ + CHILDREN + { + public int getId() + { + return 2; + } + }; + + /** + * Get the id for the ACEType stored in the DB. + * @return + */ + public abstract int getId(); + + + /** + * Get the ACEType from the value stored in the DB. + * @param id + * @return + */ + public static ACEType getACETypeFromId(int id) + { + switch(id) + { + case 0: + return ACEType.ALL; + case 1: + return ACEType.OBJECT; + case 2: + return ACEType.CHILDREN; + default: + throw new IllegalArgumentException("Unknown ace type "+id); + } + } +} diff --git a/source/java/org/alfresco/repo/security/permissions/ACLCopyMode.java b/source/java/org/alfresco/repo/security/permissions/ACLCopyMode.java new file mode 100644 index 0000000000..3e60f8bbc0 --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/ACLCopyMode.java @@ -0,0 +1,6 @@ +package org.alfresco.repo.security.permissions; + +public enum ACLCopyMode +{ + COPY, COW, INHERIT, REDIRECT; +} diff --git a/source/java/org/alfresco/repo/security/permissions/ACLType.java b/source/java/org/alfresco/repo/security/permissions/ACLType.java new file mode 100644 index 0000000000..c9dcf256fd --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/ACLType.java @@ -0,0 +1,135 @@ +/* + * 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.security.permissions; + +/** + * The ACL Type + * + * @author andyh + * + */ +public enum ACLType +{ + /** + * Old style permissions that require a parent wlak to resolve + */ + OLD + { + public int getId() + { + return 0; + } + }, + + /** + * Defining permission - not reused anywhere + */ + DEFINING + { + public int getId() + { + return 1; + } + }, + + /** + * Shared permission, reused for inhertiance from defining permission + */ + SHARED + { + public int getId() + { + return 2; + } + }, + + /** + * An ACL defined in its own right - there is no inheriance context + * + */ + FIXED + { + public int getId() + { + return 3; + } + }, + + /** + * A single instance for global permissions + */ + GLOBAL + { + public int getId() + { + return 4; + } + }, + + /** + * Layered types + */ + LAYERED + { + public int getId() + { + return 5; + } + }; + + + /** + * Get the id for the ACLType stored in the DB + * + * @return + */ + public abstract int getId(); + + /** + * Get the ACLType from the value stored in the DB + * @param id + * @return + */ + public static ACLType getACLTypeFromId(int id) + { + switch(id) + { + case 0: + return ACLType.OLD; + case 1: + return ACLType.DEFINING; + case 2: + return ACLType.SHARED; + case 3: + return ACLType.FIXED; + case 4: + return ACLType.GLOBAL; + case 5: + return ACLType.LAYERED; + default: + throw new IllegalArgumentException("Unknown acl type "+id); + } + } +} diff --git a/source/java/org/alfresco/repo/security/permissions/AccessControlEntry.java b/source/java/org/alfresco/repo/security/permissions/AccessControlEntry.java new file mode 100644 index 0000000000..ab7fbf8570 --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/AccessControlEntry.java @@ -0,0 +1,42 @@ +/* + * 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.security.permissions; + +import org.alfresco.service.cmr.security.AccessStatus; + +public interface AccessControlEntry extends Comparable +{ + public Integer getPosition(); + + public PermissionReference getPermission(); + + public String getAuthority(); + + public AccessStatus getAccessStatus(); + + public ACEType getAceType(); + + public AccessControlEntryContext getContext(); +} diff --git a/source/java/org/alfresco/repo/security/permissions/AccessControlEntryContext.java b/source/java/org/alfresco/repo/security/permissions/AccessControlEntryContext.java new file mode 100644 index 0000000000..01026ae07f --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/AccessControlEntryContext.java @@ -0,0 +1,65 @@ +/* + * 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.security.permissions; + +public interface AccessControlEntryContext +{ + /** + * 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(); + + /** + * Get the property context + * + * QName QName Qname => property types to which it applies + * + * @return + */ + public String getPropertyContext(); + + /** + * Get the key value pair context + * + * Serialized Map + * + * @return + */ + public String getKVPContext();} diff --git a/source/java/org/alfresco/repo/security/permissions/AccessControlList.java b/source/java/org/alfresco/repo/security/permissions/AccessControlList.java new file mode 100644 index 0000000000..87361768e3 --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/AccessControlList.java @@ -0,0 +1,50 @@ +/* + * 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.security.permissions; + +import java.util.List; + +public interface AccessControlList +{ + /** + * Get the properties + * @return + */ + public AccessControlListProperties getProperties(); + + /** + * Get the members of the ACL in order + * Ordered by: + * position, + * then deny followed by allow, + * then by authority type + * then .... + * + * To make permission evaluation faster for the common cases + * + * @return + */ + public List getEntries(); +} diff --git a/source/java/org/alfresco/repo/security/permissions/AccessControlListProperties.java b/source/java/org/alfresco/repo/security/permissions/AccessControlListProperties.java new file mode 100644 index 0000000000..a8612b1aa4 --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/AccessControlListProperties.java @@ -0,0 +1,71 @@ +/* + * 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.security.permissions; + + +public interface AccessControlListProperties +{ + /** + * 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 type for this ACL + * + * @return + */ + public ACLType getAclType(); + + /** + * 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(); +} diff --git a/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlEntry.java b/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlEntry.java new file mode 100644 index 0000000000..37ed6edc31 --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlEntry.java @@ -0,0 +1,126 @@ +/* + * 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.security.permissions; + +import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.AuthorityType; + +public class SimpleAccessControlEntry implements AccessControlEntry +{ + private AccessStatus accessStatus; + + private ACEType aceType; + + private String authority; + + private AccessControlEntryContext context; + + private PermissionReference permission; + + private Integer position; + + public AccessStatus getAccessStatus() + { + return accessStatus; + } + + public ACEType getAceType() + { + return aceType; + } + + public String getAuthority() + { + return authority; + } + + public AccessControlEntryContext getContext() + { + return context; + } + + public PermissionReference getPermission() + { + return permission; + } + + public Integer getPosition() + { + return position; + } + + public void setAccessStatus(AccessStatus accessStatus) + { + this.accessStatus = accessStatus; + } + + public void setAceType(ACEType aceType) + { + this.aceType = aceType; + } + + public void setAuthority(String authority) + { + this.authority = authority; + } + + public void setContext(AccessControlEntryContext context) + { + this.context = context; + } + + public void setPermission(PermissionReference permission) + { + this.permission = permission; + } + + public void setPosition(Integer position) + { + this.position = position; + } + + public int compareTo(AccessControlEntry other) + { + int diff = this.getPosition() - other.getPosition(); + if(diff == 0) + { + diff = (this.getAccessStatus()== AccessStatus.DENIED ? 0 : 1) - (other.getAccessStatus()== AccessStatus.DENIED ? 0 : 1); + if(diff == 0) + { + return AuthorityType.getAuthorityType(this.getAuthority()).getOrderPosition() - AuthorityType.getAuthorityType(other.getAuthority()).getOrderPosition(); + } + else + { + return diff; + } + } + else + { + return diff; + } + } + + +} diff --git a/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlEntryContext.java b/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlEntryContext.java new file mode 100644 index 0000000000..b3a6687280 --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlEntryContext.java @@ -0,0 +1,67 @@ + +/* + * 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.security.permissions; + +public class SimpleAccessControlEntryContext implements AccessControlEntryContext +{ + private String classContext; + + private String KVPContext; + + private String propertyContext; + + public String getClassContext() + { + return classContext; + } + + public String getKVPContext() + { + return KVPContext; + } + + public String getPropertyContext() + { + return propertyContext; + } + + public void setClassContext(String classContext) + { + this.classContext = classContext; + } + + public void setKVPContext(String context) + { + KVPContext = context; + } + + public void setPropertyContext(String propertyContext) + { + this.propertyContext = propertyContext; + } + + +} diff --git a/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlList.java b/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlList.java new file mode 100644 index 0000000000..3fed4fa82b --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlList.java @@ -0,0 +1,34 @@ +package org.alfresco.repo.security.permissions; + +import java.util.ArrayList; +import java.util.List; + +public class SimpleAccessControlList implements AccessControlList +{ + private AccessControlListProperties properties; + + private List entries = new ArrayList(); + + public List getEntries() + { + return entries; + } + + public AccessControlListProperties getProperties() + { + return properties; + } + + public void setEntries(List entries) + { + this.entries = entries; + } + + public void setProperties(AccessControlListProperties properties) + { + this.properties = properties; + } + + + +} diff --git a/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlListProperties.java b/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlListProperties.java new file mode 100644 index 0000000000..65c5cc8cbf --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/SimpleAccessControlListProperties.java @@ -0,0 +1,103 @@ +/* + * 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.security.permissions; + +public class SimpleAccessControlListProperties implements AccessControlListProperties +{ + private String aclId; + + private ACLType aclType; + + private Long aclVersion; + + private Boolean inherits; + + private Boolean latest; + + private Boolean versioned; + + 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; + } + + public void setAclId(String aclId) + { + this.aclId = aclId; + } + + public void setAclType(ACLType aclType) + { + this.aclType = aclType; + } + + public void setAclVersion(Long aclVersion) + { + this.aclVersion = aclVersion; + } + + public void setInherits(boolean inherits) + { + this.inherits = inherits; + } + + public void setLatest(boolean latest) + { + this.latest = latest; + } + + public void setVersioned(boolean versioned) + { + this.versioned = versioned; + } + + + +} diff --git a/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthority.java b/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthority.java index 2448948a7c..fe504fab80 100644 --- a/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthority.java +++ b/source/java/org/alfresco/repo/security/permissions/dynamic/LockOwnerDynamicAuthority.java @@ -27,6 +27,8 @@ package org.alfresco.repo.security.permissions.dynamic; import java.io.Serializable; import org.alfresco.model.ContentModel; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.permissions.DynamicAuthority; import org.alfresco.service.cmr.lock.LockService; import org.alfresco.service.cmr.lock.LockStatus; @@ -34,6 +36,7 @@ import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.util.EqualsHelper; import org.springframework.beans.factory.InitializingBean; /** @@ -46,33 +49,41 @@ public class LockOwnerDynamicAuthority implements DynamicAuthority, Initializing private NodeService nodeService; - public boolean hasAuthority(NodeRef nodeRef, String userName) + public boolean hasAuthority(final NodeRef nodeRef, final String userName) { - if (lockService.getLockStatus(nodeRef) == LockStatus.LOCK_OWNER) - { - return true; - } - if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY)) - { - NodeRef original = null; - Serializable reference = nodeService.getProperty(nodeRef, ContentModel.PROP_COPY_REFERENCE); - if (reference != null) + return AuthenticationUtil.runAs(new RunAsWork(){ + + public Boolean doWork() throws Exception { - original = DefaultTypeConverter.INSTANCE.convert(NodeRef.class, reference); - } - if (original != null && nodeService.exists(original)) - { - return (lockService.getLockStatus(original) == LockStatus.LOCK_OWNER); - } - else - { - return false; - } - } - else - { - return false; - } + if (lockService.getLockStatus(nodeRef, userName) == LockStatus.LOCK_OWNER) + { + return true; + } + if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY)) + { + NodeRef original = null; + Serializable reference = nodeService.getProperty(nodeRef, ContentModel.PROP_COPY_REFERENCE); + if (reference != null) + { + original = DefaultTypeConverter.INSTANCE.convert(NodeRef.class, reference); + } + if (original != null && nodeService.exists(original)) + { + return (lockService.getLockStatus(original, userName) == LockStatus.LOCK_OWNER); + } + else + { + return false; + } + } + else + { + return false; + } + }}, AuthenticationUtil.getSystemUserName()); + + + } public String getAuthority() diff --git a/source/java/org/alfresco/repo/security/permissions/dynamic/OwnerDynamicAuthority.java b/source/java/org/alfresco/repo/security/permissions/dynamic/OwnerDynamicAuthority.java index f8e5b15ef0..3ed327d326 100644 --- a/source/java/org/alfresco/repo/security/permissions/dynamic/OwnerDynamicAuthority.java +++ b/source/java/org/alfresco/repo/security/permissions/dynamic/OwnerDynamicAuthority.java @@ -24,6 +24,8 @@ */ package org.alfresco.repo.security.permissions.dynamic; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.permissions.DynamicAuthority; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.security.OwnableService; @@ -53,9 +55,16 @@ public class OwnerDynamicAuthority implements DynamicAuthority, InitializingBean } } - public boolean hasAuthority(NodeRef nodeRef, String userName) + public boolean hasAuthority(final NodeRef nodeRef, final String userName) { - return EqualsHelper.nullSafeEquals(ownableService.getOwner(nodeRef), userName); + return AuthenticationUtil.runAs(new RunAsWork(){ + + public Boolean doWork() throws Exception + { + // TODO Auto-generated method stub + return EqualsHelper.nullSafeEquals(ownableService.getOwner(nodeRef), userName); + }}, AuthenticationUtil.getSystemUserName()); + } public String getAuthority() diff --git a/source/java/org/alfresco/repo/security/permissions/impl/AclChange.java b/source/java/org/alfresco/repo/security/permissions/impl/AclChange.java new file mode 100644 index 0000000000..7260d09b5b --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/impl/AclChange.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.security.permissions.impl; + +import org.alfresco.repo.security.permissions.ACLType; + +/** + * + * @author andyh + * + */ +public interface AclChange +{ + public Long getBefore(); + public Long getAfter(); + public ACLType getTypeAfter(); + public ACLType getTypeBefore(); +} diff --git a/source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponent.java b/source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponent.java new file mode 100644 index 0000000000..0968645147 --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponent.java @@ -0,0 +1,184 @@ +/* + * 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.security.permissions.impl; + +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.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 + */ + DbAccessControlList getDbAccessControlList(Long id); + + + /** + * Get an ACL id. + * + * @param id + * @return + */ + public AccessControlList getAccessControlList(Long id); + + /** + * Delete an ACL + * + * @param id + * @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 + * + * @param id + * @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 + * + * @param id + * @return - the id of all ACLs affected + */ + 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 + */ + 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 + */ + 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 + */ + public List deleteAccessControlEntries(Long id, AccessControlEntry pattern); + + /** + * Add an access control entry + * + * @param id + * @param ace + * @return - the id of all ACLs affected + */ + public List setAccessControlEntry(Long id, AccessControlEntry ace); + + /** + * Enable inheritance + * + * @param id + * @param parent + * @return + */ + public List enableInheritance(Long id, Long parent); + + /** + * Disable inheritance + * + * @param id + * @param setInheritedOnAcl + * @return + */ + public List disableInheritance(Long id, boolean setInheritedOnAcl); + + /** + * Get the ACL properties + * + * @param id + * @return - the id of all ACLs affected + */ + public AccessControlListProperties getAccessControlListProperties(Long id); + + /** + * Create a bew ACL with teh given properties. Unset ones are assigned defaults. + * + * @param properties + * @return + */ + public Long createAccessControlList(AccessControlListProperties properties); + + /** + * 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 + */ + 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 + */ + public List mergeInheritedAccessControlList(Long inherited, Long target); + + public DbAccessControlList getDbAccessControlListCopy(Long toCopy, Long toInheritFrom, ACLCopyMode mode); + + public Long getCopy(Long toCopy, Long toInheritFrom, ACLCopyMode mode); + + public List getAvmNodesByACL(Long id); + + public List getAvmNodesByIndirection(final String indirection); + + /** + * hibernate lifecycle support + * @param id + */ + public void onDeleteAccessControlList(final long id); +} diff --git a/source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponentTest.java b/source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponentTest.java new file mode 100644 index 0000000000..6b6abee88e --- /dev/null +++ b/source/java/org/alfresco/repo/security/permissions/impl/AclDaoComponentTest.java @@ -0,0 +1,1509 @@ +/* + * 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.security.permissions.impl; + +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 javax.transaction.HeuristicMixedException; +import javax.transaction.HeuristicRollbackException; +import javax.transaction.RollbackException; +import javax.transaction.Status; +import javax.transaction.SystemException; +import javax.transaction.UserTransaction; + +import junit.framework.TestCase; + +import org.alfresco.model.ContentModel; +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.ACEType; +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.PermissionServiceSPI; +import org.alfresco.repo.security.permissions.SimpleAccessControlEntry; +import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.dictionary.DictionaryService; +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.AccessStatus; +import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.PersonService; +import org.alfresco.service.namespace.NamespacePrefixResolver; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.alfresco.util.EqualsHelper; +import org.springframework.context.ApplicationContext; +import org.springframework.orm.hibernate3.LocalSessionFactoryBean; + +public class AclDaoComponentTest extends TestCase +{ + private static ApplicationContext applicationContext = ApplicationContextHelper.getApplicationContext(); + + protected NodeService nodeService; + + protected DictionaryService dictionaryService; + + protected PermissionServiceSPI permissionService; + + protected AuthenticationService authenticationService; + + private MutableAuthenticationDao authenticationDAO; + + protected LocalSessionFactoryBean sessionFactory; + + protected NodeRef rootNodeRef; + + protected NamespacePrefixResolver namespacePrefixResolver; + + protected ServiceRegistry serviceRegistry; + + protected NodeRef systemNodeRef; + + protected AuthenticationComponent authenticationComponent; + + protected ModelDAO permissionModelDAO; + + protected PersonService personService; + + protected AuthorityService authorityService; + + private AclDaoComponent aclDaoComponent; + + private UserTransaction testTX; + + private TransactionService transactionService; + + public AclDaoComponentTest() + { + super(); + // TODO Auto-generated constructor stub + } + + public void setUp() throws Exception + { + aclDaoComponent = (AclDaoComponent) applicationContext.getBean("aclDaoComponent"); + + nodeService = (NodeService) applicationContext.getBean("nodeService"); + dictionaryService = (DictionaryService) applicationContext.getBean(ServiceRegistry.DICTIONARY_SERVICE + .getLocalName()); + permissionService = (PermissionServiceSPI) applicationContext.getBean("permissionService"); + namespacePrefixResolver = (NamespacePrefixResolver) applicationContext + .getBean(ServiceRegistry.NAMESPACE_SERVICE.getLocalName()); + authenticationService = (AuthenticationService) applicationContext.getBean("authenticationService"); + authenticationComponent = (AuthenticationComponent) applicationContext.getBean("authenticationComponent"); + serviceRegistry = (ServiceRegistry) applicationContext.getBean(ServiceRegistry.SERVICE_REGISTRY); + permissionModelDAO = (ModelDAO) applicationContext.getBean("permissionsModelDAO"); + personService = (PersonService) applicationContext.getBean("personService"); + authorityService = (AuthorityService) applicationContext.getBean("authorityService"); + + authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName()); + authenticationDAO = (MutableAuthenticationDao) applicationContext.getBean("authenticationDao"); + transactionService = (TransactionService) applicationContext.getBean("transactionComponent"); + + testTX = transactionService.getUserTransaction(); + testTX.begin(); + this.authenticationComponent.setSystemUserAsCurrentUser(); + + StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.nanoTime()); + rootNodeRef = nodeService.getRootNode(storeRef); + + QName children = ContentModel.ASSOC_CHILDREN; + QName system = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "system"); + QName container = ContentModel.TYPE_CONTAINER; + QName types = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "people"); + + systemNodeRef = nodeService.createNode(rootNodeRef, children, system, container).getChildRef(); + NodeRef typesNodeRef = nodeService.createNode(systemNodeRef, children, types, container).getChildRef(); + Map props = createPersonProperties("andy"); + nodeService.createNode(typesNodeRef, children, ContentModel.TYPE_PERSON, container, props).getChildRef(); + props = createPersonProperties("lemur"); + nodeService.createNode(typesNodeRef, children, ContentModel.TYPE_PERSON, container, props).getChildRef(); + + // create an authentication object e.g. the user + if(authenticationDAO.userExists("andy")) + { + authenticationService.deleteAuthentication("andy"); + } + authenticationService.createAuthentication("andy", "andy".toCharArray()); + + if(authenticationDAO.userExists("lemur")) + { + authenticationService.deleteAuthentication("lemur"); + } + authenticationService.createAuthentication("lemur", "lemur".toCharArray()); + + if(authenticationDAO.userExists("admin")) + { + authenticationService.deleteAuthentication("admin"); + } + authenticationService.createAuthentication("admin", "admin".toCharArray()); + + authenticationComponent.clearCurrentSecurityContext(); + } + + protected void tearDown() throws Exception + { + + if (testTX.getStatus() == Status.STATUS_ACTIVE) + { + testTX.rollback(); + } + AuthenticationUtil.clearCurrentSecurityContext(); + super.tearDown(); + } + + protected void runAs(String userName) + { + authenticationService.authenticate(userName, userName.toCharArray()); + assertNotNull(authenticationService.getCurrentUserName()); + // for(GrantedAuthority authority : woof.getAuthorities()) + // { + // System.out.println("Auth = "+authority.getAuthority()); + // } + + } + + private Map createPersonProperties(String userName) + { + HashMap properties = new HashMap(); + properties.put(ContentModel.PROP_USERNAME, userName); + return properties; + } + + protected PermissionReference getPermission(String permission) + { + return permissionModelDAO.getPermissionReference(null, permission); + } + + public void testCreateDefining() + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + properties.setVersioned(true); + Long id = aclDaoComponent.createAccessControlList(properties); + + AccessControlListProperties aclProps = aclDaoComponent.getAccessControlListProperties(id); + assertEquals(aclProps.getAclType(), ACLType.DEFINING); + assertEquals(aclProps.getAclVersion(), Long.valueOf(1l)); + assertEquals(aclProps.getInherits(), Boolean.TRUE); + + } + + public void testCreateShared() + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + properties.setVersioned(true); + Long id = aclDaoComponent.createAccessControlList(properties); + + AccessControlListProperties aclProps = aclDaoComponent.getAccessControlListProperties(id); + assertEquals(aclProps.getAclType(), ACLType.DEFINING); + assertEquals(aclProps.getAclVersion(), Long.valueOf(1l)); + assertEquals(aclProps.getInherits(), Boolean.TRUE); + + Long shared = aclDaoComponent.getInheritedAccessControlList(id); + AccessControlListProperties sharedProps = aclDaoComponent.getAccessControlListProperties(shared); + assertEquals(sharedProps.getAclType(), ACLType.SHARED); + assertEquals(sharedProps.getAclVersion(), Long.valueOf(1l)); + assertEquals(sharedProps.getInherits(), Boolean.TRUE); + assertEquals(aclDaoComponent.getInheritedAccessControlList(id), shared); + } + + public void testCreateOld() + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.OLD); + properties.setVersioned(false); + Long id = aclDaoComponent.createAccessControlList(properties); + + AccessControlListProperties aclProps = aclDaoComponent.getAccessControlListProperties(id); + assertEquals(aclProps.getAclType(), ACLType.OLD); + assertEquals(aclProps.getAclVersion(), Long.valueOf(1l)); + assertEquals(aclProps.getInherits(), Boolean.TRUE); + assertEquals(aclDaoComponent.getInheritedAccessControlList(id), null); + } + + public void testFixed() + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.FIXED); + properties.setVersioned(true); + Long id = aclDaoComponent.createAccessControlList(properties); + + AccessControlListProperties aclProps = aclDaoComponent.getAccessControlListProperties(id); + assertEquals(aclProps.getAclType(), ACLType.FIXED); + assertEquals(aclProps.getAclVersion(), Long.valueOf(1l)); + assertEquals(aclProps.getInherits(), Boolean.TRUE); + assertEquals(aclDaoComponent.getInheritedAccessControlList(id), id); + } + + public void testGlobal() + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.GLOBAL); + properties.setVersioned(false); + Long id = aclDaoComponent.createAccessControlList(properties); + + AccessControlListProperties aclProps = aclDaoComponent.getAccessControlListProperties(id); + assertEquals(aclProps.getAclType(), ACLType.GLOBAL); + assertEquals(aclProps.getAclVersion(), Long.valueOf(1l)); + assertEquals(aclProps.getInherits(), Boolean.TRUE); + assertEquals(aclDaoComponent.getInheritedAccessControlList(id), id); + } + + public void testSimpleInheritFromDefining() + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + properties.setVersioned(true); + Long id = aclDaoComponent.createAccessControlList(properties); + + AccessControlListProperties aclProps = aclDaoComponent.getAccessControlListProperties(id); + assertEquals(aclProps.getAclType(), ACLType.DEFINING); + assertEquals(aclProps.getAclVersion(), Long.valueOf(1l)); + assertEquals(aclProps.getInherits(), Boolean.TRUE); + + SimpleAccessControlEntry ace1 = new SimpleAccessControlEntry(); + 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); + + AccessControlList defined = aclDaoComponent.getAccessControlList(id); + assertEquals(defined.getProperties().getAclType(), ACLType.DEFINING); + assertEquals(defined.getProperties().getAclVersion(), Long.valueOf(1l)); + assertEquals(defined.getProperties().getInherits(), Boolean.TRUE); + assertEquals(defined.getEntries().size(), 1); + assertTrue(hasAce(defined.getEntries(), ace1, 0)); + + + Long sharedId = aclDaoComponent.getInheritedAccessControlList(id); + AccessControlListProperties sharedProps = aclDaoComponent.getAccessControlListProperties(sharedId); + assertEquals(sharedProps.getAclType(), ACLType.SHARED); + assertEquals(sharedProps.getAclVersion(), Long.valueOf(1l)); + assertEquals(sharedProps.getInherits(), Boolean.TRUE); + assertEquals(aclDaoComponent.getInheritedAccessControlList(id), sharedId); + + AccessControlList shared = aclDaoComponent.getAccessControlList(sharedId); + assertEquals(shared.getProperties().getAclType(), ACLType.SHARED); + assertEquals(shared.getProperties().getAclVersion(), Long.valueOf(1l)); + assertEquals(shared.getProperties().getInherits(), Boolean.TRUE); + assertEquals(shared.getEntries().size(), 1); + assertTrue(hasAce(shared.getEntries(), ace1, 1)); + + SimpleAccessControlEntry ace2 = new SimpleAccessControlEntry(); + 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); + + defined = aclDaoComponent.getAccessControlList(id); + assertEquals(defined.getProperties().getAclType(), ACLType.DEFINING); + assertEquals(defined.getProperties().getAclVersion(), Long.valueOf(1l)); + assertEquals(defined.getProperties().getInherits(), Boolean.TRUE); + assertEquals(defined.getEntries().size(), 2); + assertTrue(hasAce(defined.getEntries(), ace1, 0)); + assertTrue(hasAce(defined.getEntries(), ace2, 0)); + + sharedId = aclDaoComponent.getInheritedAccessControlList(id); + shared = aclDaoComponent.getAccessControlList(sharedId); + assertEquals(shared.getProperties().getAclType(), ACLType.SHARED); + assertEquals(shared.getProperties().getAclVersion(), Long.valueOf(1l)); + assertEquals(shared.getProperties().getInherits(), Boolean.TRUE); + assertEquals(shared.getEntries().size(), 2); + assertTrue(hasAce(shared.getEntries(), ace1, 1)); + assertTrue(hasAce(shared.getEntries(), ace2, 1)); + } + + public void testInheritanceChainDefShared() + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + properties.setVersioned(true); + Long def1 = aclDaoComponent.createAccessControlList(properties); + Long shared1 = aclDaoComponent.getInheritedAccessControlList(def1); + Long def2 = aclDaoComponent.createAccessControlList(properties); + aclDaoComponent.mergeInheritedAccessControlList(shared1, def2); + Long shared2 = aclDaoComponent.getInheritedAccessControlList(def2); + Long def3 = aclDaoComponent.createAccessControlList(properties); + aclDaoComponent.mergeInheritedAccessControlList(shared2, def3); + Long shared3 = aclDaoComponent.getInheritedAccessControlList(def3); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 0); + + SimpleAccessControlEntry ace1 = new SimpleAccessControlEntry(); + 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); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + + + Long def4 = aclDaoComponent.createAccessControlList(properties); + aclDaoComponent.mergeInheritedAccessControlList(shared3, def4); + Long shared4 = aclDaoComponent.getInheritedAccessControlList(def4); + + Long def5 = aclDaoComponent.createAccessControlList(properties); + aclDaoComponent.mergeInheritedAccessControlList(shared4, def5); + Long shared5 = aclDaoComponent.getInheritedAccessControlList(def5); + + Long def6_1 = aclDaoComponent.createAccessControlList(properties); + aclDaoComponent.mergeInheritedAccessControlList(shared5, def6_1); + Long shared6_1 = aclDaoComponent.getInheritedAccessControlList(def6_1); + + Long def6_2 = aclDaoComponent.createAccessControlList(properties); + aclDaoComponent.mergeInheritedAccessControlList(shared5, def6_2); + Long shared6_2 = aclDaoComponent.getInheritedAccessControlList(def6_2); + + Long def6_3 = aclDaoComponent.createAccessControlList(properties); + aclDaoComponent.mergeInheritedAccessControlList(shared5, def6_3); + Long shared6_3 = aclDaoComponent.getInheritedAccessControlList(def6_3); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace1, 6)); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace1, 7)); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace1, 8)); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace1, 9)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace1, 10)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace1, 11)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace1, 10)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace1, 11)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace1, 10)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_3).getEntries(), ace1, 11)); + + + + SimpleAccessControlEntry ace2 = new SimpleAccessControlEntry(); + 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); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace1, 6)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace2, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace1, 7)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace2, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace1, 8)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace2, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace1, 9)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace2, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace1, 11)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace1, 11)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace2, 4)); + 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); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace2, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace2, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace2, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace2, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_3).getEntries(), ace2, 5)); + + aclDaoComponent.enableInheritance(def4, shared3); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace1, 6)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace2, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace1, 7)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace2, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace1, 8)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace2, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace1, 9)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace2, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace1, 11)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace1, 11)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace2, 4)); + 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.enableInheritance(def4, shared2); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace1, 4)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace2, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace1, 5)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace2, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace1, 6)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace2, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace1, 7)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace2, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace1, 8)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace1, 9)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace1, 8)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace1, 9)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace1, 8)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_3).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_3).getEntries(), ace1, 9)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_3).getEntries(), ace2, 5)); + + aclDaoComponent.disableInheritance(def4, true); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace1, 0)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace2, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace1, 1)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace2, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace1, 2)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace2, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace1, 3)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace2, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace1, 4)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace1, 5)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace1, 4)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace1, 5)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace1, 4)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_3).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_3).getEntries(), ace1, 5)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_3).getEntries(), ace2, 5)); + + aclDaoComponent.deleteAccessControlEntries(def4, ace1); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace2, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace2, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace2, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace2, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 1);; + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_3).getEntries(), ace2, 5)); + + aclDaoComponent.deleteLocalAccessControlEntries(def4); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(),0); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared6_3).getEntries().size(), 0); + + aclDaoComponent.enableInheritance(def4, shared3); + aclDaoComponent.setAccessControlEntry(def4, ace2); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace1, 6)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace2, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace1, 7)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace2, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace1, 8)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace2, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace1, 9)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace2, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace1, 11)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace1, 11)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace2, 4)); + 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.deleteLocalAccessControlEntries(def4); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace1, 6)); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace1, 7)); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace1, 8)); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace1, 9)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace1, 10)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace1, 11)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace1, 10)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace1, 11)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace1, 10)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_3).getEntries(), ace1, 11)); + + aclDaoComponent.setAccessControlEntry(def4, ace2); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace1, 6)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace2, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace1, 7)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace2, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace1, 8)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace2, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace1, 9)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace2, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace1, 11)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace1, 11)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace2, 4)); + 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.deleteInheritedAccessControlEntries(def4); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace2, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace2, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace2, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace2, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_3).getEntries(), ace2, 5)); + + aclDaoComponent.deleteLocalAccessControlEntries(def4); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared6_3).getEntries().size(), 0); + + aclDaoComponent.enableInheritance(def4, shared3); + aclDaoComponent.setAccessControlEntry(def4, ace2); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace1, 6)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def4).getEntries(), ace2, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared4).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace1, 7)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared4).getEntries(), ace2, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace1, 8)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace2, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace1, 9)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace2, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace1, 11)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace2, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace1, 11)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace2, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace1, 10)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace2, 4)); + 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.deleteAccessControlList(def4); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def5).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def5).getEntries(), ace1, 6)); + assertEquals(aclDaoComponent.getAccessControlList(shared5).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared5).getEntries(), ace1, 7)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace1, 8)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace1, 9)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace1, 8)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace1, 9)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace1, 8)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_3).getEntries(), ace1, 9)); + + aclDaoComponent.deleteAccessControlList(def5); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace1, 6)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace1, 7)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace1, 6)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace1, 7)); + assertEquals(aclDaoComponent.getAccessControlList(def6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_3).getEntries(), ace1, 6)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_3).getEntries(), ace1, 7)); + + aclDaoComponent.deleteAccessControlList(def6_3); + + assertEquals(aclDaoComponent.getAccessControlList(def1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def3).getEntries(), ace1, 4)); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared3).getEntries(), ace1, 5)); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_1).getEntries(), ace1, 6)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_1).getEntries(), ace1, 7)); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(def6_2).getEntries(), ace1, 6)); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared6_2).getEntries(), ace1, 7)); + + aclDaoComponent.deleteAccessControlList(def1); + + assertEquals(aclDaoComponent.getAccessControlList(def2).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(def3).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared3).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(def6_1).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared6_1).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(def6_2).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(shared6_2).getEntries().size(), 0); + + } + + public void testDeleteAuthority() + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + 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); + + SimpleAccessControlEntry ace2 = new SimpleAccessControlEntry(); + 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); + + SimpleAccessControlEntry ace3 = new SimpleAccessControlEntry(); + 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); + + Long shared = aclDaoComponent.getInheritedAccessControlList(defined); + + properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.FIXED); + properties.setVersioned(true); + Long fixed = aclDaoComponent.createAccessControlList(properties); + + properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.GLOBAL); + properties.setVersioned(true); + Long global = aclDaoComponent.createAccessControlList(properties); + + properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.OLD); + properties.setVersioned(false); + Long old = aclDaoComponent.createAccessControlList(properties); + + + aclDaoComponent.setAccessControlEntry(defined, ace1); + aclDaoComponent.setAccessControlEntry(defined, ace2); + aclDaoComponent.setAccessControlEntry(defined, ace3); + + aclDaoComponent.setAccessControlEntry(fixed, ace1); + aclDaoComponent.setAccessControlEntry(fixed, ace2); + aclDaoComponent.setAccessControlEntry(fixed, ace3); + + aclDaoComponent.setAccessControlEntry(global, ace1); + aclDaoComponent.setAccessControlEntry(global, ace2); + aclDaoComponent.setAccessControlEntry(global, ace3); + + aclDaoComponent.setAccessControlEntry(old, ace1); + aclDaoComponent.setAccessControlEntry(old, ace2); + aclDaoComponent.setAccessControlEntry(old, ace3); + + assertEquals(aclDaoComponent.getAccessControlList(defined).getEntries().size(), 3); + assertEquals(aclDaoComponent.getAccessControlList(shared).getEntries().size(), 3); + assertEquals(aclDaoComponent.getAccessControlList(fixed).getEntries().size(), 3); + assertEquals(aclDaoComponent.getAccessControlList(global).getEntries().size(), 3); + assertEquals(aclDaoComponent.getAccessControlList(old).getEntries().size(), 3); + + aclDaoComponent.deleteAccessControlEntries("offski"); + + assertEquals(aclDaoComponent.getAccessControlList(defined).getEntries().size(), 1); + assertEquals(aclDaoComponent.getAccessControlList(shared).getEntries().size(), 1); + assertEquals(aclDaoComponent.getAccessControlList(fixed).getEntries().size(), 1); + assertEquals(aclDaoComponent.getAccessControlList(global).getEntries().size(), 1); + assertEquals(aclDaoComponent.getAccessControlList(old).getEntries().size(), 1); + + } + + public void testSimpleCow() throws Exception + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + properties.setVersioned(true); + Long id = aclDaoComponent.createAccessControlList(properties); + + AccessControlListProperties aclProps = aclDaoComponent.getAccessControlListProperties(id); + assertEquals(aclProps.getAclType(), ACLType.DEFINING); + assertEquals(aclProps.getAclVersion(), Long.valueOf(1l)); + assertEquals(aclProps.getInherits(), Boolean.TRUE); + + testTX.commit(); + + testTX = transactionService.getUserTransaction(); + testTX.begin(); + + AccessControlListProperties aclPropsBefore = aclDaoComponent.getAccessControlListProperties(id); + assertEquals(aclPropsBefore.getAclType(), ACLType.DEFINING); + assertEquals(aclPropsBefore.getAclVersion(), Long.valueOf(1l)); + assertEquals(aclPropsBefore.getInherits(), Boolean.TRUE); + + SimpleAccessControlEntry ace1 = new SimpleAccessControlEntry(); + 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); + assertEquals(changes.size(), 1); + assertEquals(changes.get(0).getBefore(), id); + assertFalse(changes.get(0).getBefore().equals(changes.get(0).getAfter())); + + aclPropsBefore = aclDaoComponent.getAccessControlListProperties(changes.get(0).getBefore()); + assertEquals(aclPropsBefore.getAclType(), ACLType.DEFINING); + assertEquals(aclPropsBefore.getAclVersion(), Long.valueOf(1l)); + assertEquals(aclPropsBefore.getInherits(), Boolean.TRUE); + assertEquals(aclPropsBefore.isLatest(), Boolean.FALSE); + assertEquals(aclPropsBefore.isVersioned(), Boolean.TRUE); + + AccessControlListProperties aclPropsAfter = aclDaoComponent.getAccessControlListProperties(changes.get(0).getAfter()); + assertEquals(aclPropsAfter.getAclType(), aclPropsBefore.getAclType()); + assertEquals(aclPropsAfter.getAclVersion(), Long.valueOf(aclPropsBefore.getAclVersion()+1)); + assertEquals(aclPropsAfter.getInherits(), aclPropsBefore.getInherits()); + assertEquals(aclPropsAfter.getAclId(), aclPropsBefore.getAclId()); + assertEquals(aclPropsAfter.isVersioned(), aclPropsBefore.isVersioned()); + assertEquals(aclPropsAfter.isLatest(), Boolean.TRUE); + + assertEquals(aclDaoComponent.getAccessControlList(changes.get(0).getBefore()).getEntries().size(), 0); + assertEquals(aclDaoComponent.getAccessControlList(changes.get(0).getAfter()).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(changes.get(0).getAfter()).getEntries(), ace1, 0)); + + } + + public void testSimpleCowHerd1() throws Exception + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + properties.setVersioned(true); + Long i_1 = aclDaoComponent.createAccessControlList(properties); + Long s_1 = aclDaoComponent.getInheritedAccessControlList(i_1); + + Long i_1_2 = aclDaoComponent.createAccessControlList(properties); + Long s_1_2 = aclDaoComponent.getInheritedAccessControlList(i_1_2); + aclDaoComponent.mergeInheritedAccessControlList(s_1, i_1_2); + Long i_1_3 = aclDaoComponent.createAccessControlList(properties); + Long s_1_3 = aclDaoComponent.getInheritedAccessControlList(i_1_3); + aclDaoComponent.mergeInheritedAccessControlList(s_1, i_1_3); + + Long i_1_2_4 = aclDaoComponent.createAccessControlList(properties); + Long s_1_2_4 = aclDaoComponent.getInheritedAccessControlList(i_1_2_4); + 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); + aclDaoComponent.mergeInheritedAccessControlList(s_1_2_4, i_1_2_4_5); + + Long i_1_3_6 = aclDaoComponent.createAccessControlList(properties); + Long s_1_3_6 = aclDaoComponent.getInheritedAccessControlList(i_1_3_6); + aclDaoComponent.mergeInheritedAccessControlList(s_1_3, i_1_3_6); + Long i_1_3_6_7 = aclDaoComponent.createAccessControlList(properties); + Long s_1_3_6_7 = aclDaoComponent.getInheritedAccessControlList(i_1_3_6_7); + aclDaoComponent.mergeInheritedAccessControlList(s_1_3_6, i_1_3_6_7); + + testTX.commit(); + + testTX = transactionService.getUserTransaction(); + testTX.begin(); + + SimpleAccessControlEntry ace1 = new SimpleAccessControlEntry(); + 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); + + // All should have changed + + Set changed = new HashSet(changes.size()); + for(AclChange change : changes) + { + changed.add(change.getBefore()); + assertFalse(change.getBefore().equals(change.getAfter())); + } + + assertTrue(changed.contains(i_1)); + assertTrue(changed.contains(s_1)); + assertTrue(changed.contains(i_1_2)); + assertTrue(changed.contains(s_1_2)); + assertTrue(changed.contains(i_1_3)); + assertTrue(changed.contains(s_1_3)); + assertTrue(changed.contains(i_1_2_4)); + assertTrue(changed.contains(s_1_2_4)); + assertTrue(changed.contains(i_1_2_4_5)); + assertTrue(changed.contains(s_1_2_4_5)); + assertTrue(changed.contains(i_1_3_6)); + assertTrue(changed.contains(s_1_3_6)); + assertTrue(changed.contains(i_1_3_6_7)); + assertTrue(changed.contains(s_1_3_6_7)); + } + + + public void testSimpleCowHerd2() throws Exception + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + properties.setVersioned(true); + Long i_1 = aclDaoComponent.createAccessControlList(properties); + Long s_1 = aclDaoComponent.getInheritedAccessControlList(i_1); + + Long i_1_2 = aclDaoComponent.createAccessControlList(properties); + Long s_1_2 = aclDaoComponent.getInheritedAccessControlList(i_1_2); + aclDaoComponent.mergeInheritedAccessControlList(s_1, i_1_2); + Long i_1_3 = aclDaoComponent.createAccessControlList(properties); + Long s_1_3 = aclDaoComponent.getInheritedAccessControlList(i_1_3); + aclDaoComponent.mergeInheritedAccessControlList(s_1, i_1_3); + + Long i_1_2_4 = aclDaoComponent.createAccessControlList(properties); + Long s_1_2_4 = aclDaoComponent.getInheritedAccessControlList(i_1_2_4); + 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); + aclDaoComponent.mergeInheritedAccessControlList(s_1_2_4, i_1_2_4_5); + + Long i_1_3_6 = aclDaoComponent.createAccessControlList(properties); + Long s_1_3_6 = aclDaoComponent.getInheritedAccessControlList(i_1_3_6); + aclDaoComponent.mergeInheritedAccessControlList(s_1_3, i_1_3_6); + Long i_1_3_6_7 = aclDaoComponent.createAccessControlList(properties); + Long s_1_3_6_7 = aclDaoComponent.getInheritedAccessControlList(i_1_3_6_7); + aclDaoComponent.mergeInheritedAccessControlList(s_1_3_6, i_1_3_6_7); + + testTX.commit(); + + testTX = transactionService.getUserTransaction(); + testTX.begin(); + + SimpleAccessControlEntry ace1 = new SimpleAccessControlEntry(); + 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); + + // All should have changed + + Set changed = new HashSet(changes.size()); + for(AclChange change : changes) + { + changed.add(change.getBefore()); + assertFalse(change.getBefore().equals(change.getAfter())); + } + + assertTrue(changed.contains(i_1_3)); + assertTrue(changed.contains(s_1_3)); + assertTrue(changed.contains(i_1_3_6)); + assertTrue(changed.contains(s_1_3_6)); + assertTrue(changed.contains(i_1_3_6_7)); + assertTrue(changed.contains(s_1_3_6_7)); + } + + + public void testOldDoesNotCow() throws Exception + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.OLD); + properties.setVersioned(false); + Long id = aclDaoComponent.createAccessControlList(properties); + + AccessControlListProperties aclProps = aclDaoComponent.getAccessControlListProperties(id); + assertEquals(aclProps.getAclType(), ACLType.OLD); + assertEquals(aclProps.getAclVersion(), Long.valueOf(1l)); + assertEquals(aclProps.getInherits(), Boolean.TRUE); + + testTX.commit(); + + testTX = transactionService.getUserTransaction(); + testTX.begin(); + + AccessControlListProperties aclPropsBefore = aclDaoComponent.getAccessControlListProperties(id); + assertEquals(aclPropsBefore.getAclType(), ACLType.OLD); + assertEquals(aclPropsBefore.getAclVersion(), Long.valueOf(1l)); + assertEquals(aclPropsBefore.getInherits(), Boolean.TRUE); + + SimpleAccessControlEntry ace1 = new SimpleAccessControlEntry(); + 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); + assertEquals(changes.size(), 1); + assertEquals(changes.get(0).getBefore(), id); + assertTrue(changes.get(0).getBefore().equals(changes.get(0).getAfter())); + + aclPropsBefore = aclDaoComponent.getAccessControlListProperties(changes.get(0).getBefore()); + assertEquals(aclPropsBefore.getAclType(), ACLType.OLD); + assertEquals(aclPropsBefore.getAclVersion(), Long.valueOf(1l)); + assertEquals(aclPropsBefore.getInherits(), Boolean.TRUE); + assertEquals(aclPropsBefore.isLatest(), Boolean.TRUE); + assertEquals(aclPropsBefore.isVersioned(), Boolean.FALSE); + + assertEquals(aclDaoComponent.getAccessControlList(changes.get(0).getBefore()).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(changes.get(0).getBefore()).getEntries(), ace1, 0)); + + } + + public void testAddSimilar() + { + SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties(); + properties.setAclType(ACLType.DEFINING); + properties.setVersioned(false); + Long id1 = aclDaoComponent.createAccessControlList(properties); + Long shared1 = aclDaoComponent.getInheritedAccessControlList(id1); + Long id2 = aclDaoComponent.createAccessControlList(properties); + Long shared2 = aclDaoComponent.getInheritedAccessControlList(id2); + aclDaoComponent.mergeInheritedAccessControlList(shared1, id2); + + SimpleAccessControlEntry ace1 = new SimpleAccessControlEntry(); + 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); + + SimpleAccessControlEntry ace2 = new SimpleAccessControlEntry(); + 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); + + aclDaoComponent.setAccessControlEntry(id1, ace1); + aclDaoComponent.setAccessControlEntry(id2, ace1); + + assertEquals(aclDaoComponent.getAccessControlList(id1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(id2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id2).getEntries(), ace1, 0)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 1)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + + aclDaoComponent.setAccessControlEntry(id1, ace2); + + assertEquals(aclDaoComponent.getAccessControlList(id1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id1).getEntries(), ace2, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace2, 1)); + assertEquals(aclDaoComponent.getAccessControlList(id2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id2).getEntries(), ace2, 0)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace2, 1)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + + aclDaoComponent.setAccessControlEntry(id1, ace1); + aclDaoComponent.setAccessControlEntry(id2, ace2); + + assertEquals(aclDaoComponent.getAccessControlList(id1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(id2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id2).getEntries(), ace1, 0)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id2).getEntries(), ace2, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 1)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace2, 3)); + + aclDaoComponent.setAccessControlEntry(id1, ace2); + + assertEquals(aclDaoComponent.getAccessControlList(id1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id1).getEntries(), ace2, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace2, 1)); + assertEquals(aclDaoComponent.getAccessControlList(id2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id2).getEntries(), ace2, 0)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id2).getEntries(), ace2, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace2, 1)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace2, 3)); + + aclDaoComponent.setAccessControlEntry(id1, ace1); + aclDaoComponent.setAccessControlEntry(id2, ace1); + + assertEquals(aclDaoComponent.getAccessControlList(id1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id1).getEntries(), ace1, 0)); + assertEquals(aclDaoComponent.getAccessControlList(shared1).getEntries().size(), 1); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared1).getEntries(), ace1, 1)); + assertEquals(aclDaoComponent.getAccessControlList(id2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id2).getEntries(), ace1, 0)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(id2).getEntries(), ace1, 2)); + assertEquals(aclDaoComponent.getAccessControlList(shared2).getEntries().size(), 2); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 1)); + assertTrue(hasAce(aclDaoComponent.getAccessControlList(shared2).getEntries(), ace1, 3)); + } + + private boolean hasAce(List aces, AccessControlEntry ace, int position) + { + for(AccessControlEntry test : aces) + { + if(!EqualsHelper.nullSafeEquals(test.getAccessStatus(), ace.getAccessStatus())) + { + continue; + } + if(!EqualsHelper.nullSafeEquals(test.getAceType(), ace.getAceType())) + { + continue; + } + if(!EqualsHelper.nullSafeEquals(test.getAuthority(), ace.getAuthority())) + { + continue; + } + if(!EqualsHelper.nullSafeEquals(test.getContext(), ace.getContext())) + { + continue; + } + if(!EqualsHelper.nullSafeEquals(test.getPermission(), ace.getPermission())) + { + continue; + } + if(!EqualsHelper.nullSafeEquals(test.getPosition(), Integer.valueOf(position))) + { + continue; + } + return true; + + } + return false; + } +} diff --git a/source/java/org/alfresco/repo/security/permissions/impl/ModelDAO.java b/source/java/org/alfresco/repo/security/permissions/impl/ModelDAO.java index 925ef86682..11b403708d 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/ModelDAO.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/ModelDAO.java @@ -46,6 +46,16 @@ public interface ModelDAO * @return */ public Set getAllPermissions(QName type); + + + /** + * Get the permissions that can be set for the given type. + * + * @param type - the type in the data dictionary. + * @param aspects + * @return + */ + public Set getAllPermissions(QName type, Set aspects); /** * Get the permissions that can be set for the given node. 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 3c6a1d2ee0..b0448020d2 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceImpl.java @@ -40,6 +40,10 @@ import org.alfresco.repo.cache.SimpleCache; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.security.permissions.AccessControlEntry; +import org.alfresco.repo.security.permissions.AccessControlList; import org.alfresco.repo.security.permissions.DynamicAuthority; import org.alfresco.repo.security.permissions.NodePermissionEntry; import org.alfresco.repo.security.permissions.PermissionEntry; @@ -53,6 +57,7 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.PermissionContext; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; @@ -64,7 +69,7 @@ import org.springframework.beans.factory.InitializingBean; /** * The Alfresco implementation of a permissions service against our APIs for the permissions model and permissions * persistence. - * + * * @author andyh */ public class PermissionServiceImpl implements PermissionServiceSPI, InitializingBean @@ -120,6 +125,8 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing private PolicyComponent policyComponent; + private AclDaoComponent aclDaoComponent; + /* * Standard spring construction. */ @@ -172,9 +179,14 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing this.dynamicAuthorities = dynamicAuthorities; } + public void setAclDaoComponent(AclDaoComponent aclDaoComponent) + { + this.aclDaoComponent = aclDaoComponent; + } + /** * Set the permissions access cache. - * + * * @param accessCache * a transactionally safe cache */ @@ -227,6 +239,10 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing { throw new IllegalArgumentException("Property 'policyComponent' has not been set"); } + if (aclDaoComponent == null) + { + throw new IllegalArgumentException("Property 'aclDaoComponent' has not been set"); + } policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onMoveNode"), ContentModel.TYPE_BASE, new JavaBehaviour(this, "onMoveNode")); @@ -315,20 +331,20 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing return permissionsDaoComponent.getPermissions(tenantService.getName(nodeRef)); } - public AccessStatus hasPermission(NodeRef nodeRef, PermissionReference perm) + public AccessStatus hasPermission(final NodeRef nodeRefIn, final PermissionReference permIn) { // If the node ref is null there is no sensible test to do - and there // must be no permissions // - so we allow it - if (nodeRef == null) + if (nodeRefIn == null) { return AccessStatus.ALLOWED; } - nodeRef = tenantService.getName(nodeRef); + final NodeRef nodeRef = tenantService.getName(nodeRefIn); // If the permission is null we deny - if (perm == null) + if (permIn == null) { return AccessStatus.DENIED; } @@ -339,24 +355,36 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing return AccessStatus.ALLOWED; } + final PermissionReference perm; + if (permIn.equals(OLD_ALL_PERMISSIONS_REFERENCE)) + { + perm = getAllPermissionReference(); + } + else + { + perm = permIn; + } + // Get the current authentications // Use the smart authentication cache to improve permissions performance Authentication auth = authenticationComponent.getCurrentAuthentication(); - Set authorisations = getAuthorisations(auth, nodeRef); - - Serializable key = generateKey(authorisations, nodeRef, perm, CacheType.HAS_PERMISSION); - AccessStatus status = accessCache.get(key); - if (status != null) - { - return status; - } + final Set authorisations = getAuthorisations(auth, nodeRef); // If the node does not support the given permission there is no point // doing the test - Set available = modelDAO.getAllPermissions(nodeRef); + Set available = AuthenticationUtil.runAs(new RunAsWork>() + { + public Set doWork() throws Exception + { + return modelDAO.getAllPermissions(nodeRef); + } + + }, AuthenticationUtil.getSystemUserName()); + available.add(getAllPermissionReference()); available.add(OLD_ALL_PERMISSIONS_REFERENCE); + final Serializable key = generateKey(authorisations, nodeRef, perm, CacheType.HAS_PERMISSION); if (!(available.contains(perm))) { accessCache.put(key, AccessStatus.DENIED); @@ -368,42 +396,108 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing return AccessStatus.ALLOWED; } - // - // TODO: Dynamic permissions via evaluators - // - - /* - * Does the current authentication have the supplied permission on the given node. - */ - - QName typeQname = nodeService.getType(nodeRef); - Set aspectQNames = nodeService.getAspects(nodeRef); - - if (perm.equals(OLD_ALL_PERMISSIONS_REFERENCE)) + return AuthenticationUtil.runAs(new RunAsWork() { - perm = getAllPermissionReference(); - } - NodeTest nt = new NodeTest(perm, typeQname, aspectQNames); - boolean result = nt.evaluate(authorisations, nodeRef); - if (log.isDebugEnabled()) - { - log.debug("Permission <" - + perm + "> is " + (result ? "allowed" : "denied") + " for " + authenticationComponent.getCurrentUserName() + " on node " + nodeService.getPath(nodeRef)); - } - status = result ? AccessStatus.ALLOWED : AccessStatus.DENIED; - accessCache.put(key, status); - return status; + public AccessStatus doWork() throws Exception + { + + AccessStatus status = accessCache.get(key); + if (status != null) + { + return status; + } + + // + // TODO: Dynamic permissions via evaluators + // + + /* + * Does the current authentication have the supplied permission on the given node. + */ + + QName typeQname = nodeService.getType(nodeRef); + Set aspectQNames = nodeService.getAspects(nodeRef); + + NodeTest nt = new NodeTest(perm, typeQname, aspectQNames); + boolean result = nt.evaluate(authorisations, nodeRef); + if (log.isDebugEnabled()) + { + log.debug("Permission <" + + perm + "> is " + (result ? "allowed" : "denied") + " for " + authenticationComponent.getCurrentUserName() + " on node " + + nodeService.getPath(nodeRef)); + } + + status = result ? AccessStatus.ALLOWED : AccessStatus.DENIED; + accessCache.put(key, status); + return status; + } + }, AuthenticationUtil.getSystemUserName()); + } - /* (non-Javadoc) - * @see org.alfresco.service.cmr.security.PermissionService#hasPermission(java.lang.Long, java.lang.String, java.lang.String) + /* + * (non-Javadoc) + * + * @see org.alfresco.service.cmr.security.PermissionService#hasPermission(java.lang.Long, java.lang.String, + * java.lang.String) */ - public AccessStatus hasPermission(Long aclID, Map context, - String permission) + public AccessStatus hasPermission(Long aclID, PermissionContext context, String permission) { - // TODO Implement. - return AccessStatus.ALLOWED; + return hasPermission(aclID, context, getPermissionReference(permission)); + } + + public AccessStatus hasPermission(Long aclId, PermissionContext context, PermissionReference permission) + { + if (aclId == null) + { + return AccessStatus.ALLOWED; + } + + if (permission == null) + { + return AccessStatus.DENIED; + } + + // Get the current authentications + // Use the smart authentication cache to improve permissions performance + Authentication auth = authenticationComponent.getCurrentAuthentication(); + if (auth == null) + { + throw new IllegalStateException("Unauthenticated"); + } + + Set authorisations = getAuthorisations(auth, context); + + // If the node does not support the given permission there is no point + // doing the test + + QName typeQname = context.getType(); + Set aspectQNames = context.getAspects(); + + Set available = modelDAO.getAllPermissions(typeQname, aspectQNames); + available.add(getAllPermissionReference()); + available.add(OLD_ALL_PERMISSIONS_REFERENCE); + + if (!(available.contains(permission))) + { + return AccessStatus.DENIED; + } + + if (authenticationComponent.getCurrentUserName().equals(authenticationComponent.getSystemUserName())) + { + return AccessStatus.ALLOWED; + } + + if (permission.equals(OLD_ALL_PERMISSIONS_REFERENCE)) + { + permission = getAllPermissionReference(); + } + AclTest aclTest = new AclTest(permission, typeQname, aspectQNames); + boolean result = aclTest.evaluate(authorisations, aclId); + + AccessStatus status = result ? AccessStatus.ALLOWED : AccessStatus.DENIED; + return status; } enum CacheType @@ -427,7 +521,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing /** * Get the authorisations for the currently authenticated user - * + * * @param auth * @return */ @@ -473,6 +567,41 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing return auths; } + private Set getAuthorisations(Authentication auth, PermissionContext context) + { + HashSet auths = new HashSet(); + // No authenticated user then no permissions + if (auth == null) + { + return auths; + } + // TODO: Refactor and use the authentication service for this. + User user = (User) auth.getPrincipal(); + auths.add(user.getUsername()); + for (GrantedAuthority authority : auth.getAuthorities()) + { + auths.add(authority.getAuthority()); + } + auths.addAll(authorityService.getAuthorities()); + + if (context != null) + { + Map> dynamicAuthorityAssignments = context.getDynamicAuthorityAssignment(); + HashSet dynAuths = new HashSet(); + for (String current : auths) + { + Set dynos = dynamicAuthorityAssignments.get(current); + if (dynos != null) + { + dynAuths.addAll(dynos); + } + } + auths.addAll(dynAuths); + } + + return auths; + } + public NodePermissionEntry explainPermission(NodeRef nodeRef, PermissionReference perm) { // TODO Auto-generated method stub @@ -612,7 +741,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing /** * Support class to test the permission on a node. - * + * * @author Andy Hind */ private class NodeTest @@ -685,7 +814,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing /** * External hook point - * + * * @param authorisations * @param nodeRef * @return @@ -698,7 +827,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing /** * Internal hook point for recursion - * + * * @param authorisations * @param nodeRef * @param denied @@ -943,7 +1072,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing /** * Check if we have a global permission - * + * * @param authorisations * @return */ @@ -961,7 +1090,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing /** * Get the list of permissions denied for this node. - * + * * @param nodeRef * @return */ @@ -1011,7 +1140,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing /** * Check that a given authentication is available on a node - * + * * @param authorisations * @param nodeRef * @param denied @@ -1041,7 +1170,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing /** * Is a permission granted - * + * * @param pe - * the permissions entry to consider * @param granters - @@ -1113,9 +1242,286 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing } + /** + * Test a permission in the context of the new ACL implementation. All components of the ACL are in the object - + * there is no need to walk up the parent chain. Parent conditions cna not be applied as there is no context to do + * this. Child conditions can not be applied as there is no context to do this + * + * @author andyh + */ + + private class AclTest + { + /* + * The required permission. + */ + PermissionReference required; + + /* + * Granters of the permission + */ + Set granters; + + /* + * The additional permissions required at the node level. + */ + Set nodeRequirements = new HashSet(); + + /* + * The type name of the node. + */ + QName typeQName; + + /* + * The aspects set on the node. + */ + Set aspectQNames; + + /* + * Constructor just gets the additional requirements + */ + AclTest(PermissionReference required, QName typeQName, Set aspectQNames) + { + this.required = required; + this.typeQName = typeQName; + this.aspectQNames = aspectQNames; + + // Set the required node permissions + if (required.equals(getPermissionReference(ALL_PERMISSIONS))) + { + nodeRequirements = modelDAO.getRequiredPermissions(getPermissionReference(PermissionService.FULL_CONTROL), typeQName, aspectQNames, RequiredPermission.On.NODE); + } + else + { + nodeRequirements = modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, RequiredPermission.On.NODE); + } + + if (modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, RequiredPermission.On.PARENT).size() > 0) + { + throw new IllegalStateException("Parent permissions can not be checked for an acl"); + } + + if (modelDAO.getRequiredPermissions(required, typeQName, aspectQNames, RequiredPermission.On.CHILDREN).size() > 0) + { + throw new IllegalStateException("Child permissions can not be checked for an acl"); + } + + // Find all the permissions that grant the allowed permission + // All permissions are treated specially. + granters = new LinkedHashSet(128, 1.0f); + granters.addAll(modelDAO.getGrantingPermissions(required)); + granters.add(getAllPermissionReference()); + granters.add(OLD_ALL_PERMISSIONS_REFERENCE); + } + + /** + * Internal hook point for recursion + * + * @param authorisations + * @param nodeRef + * @param denied + * @param recursiveIn + * @return + */ + boolean evaluate(Set authorisations, Long aclId) + { + // Do we defer our required test to a parent (yes if not null) + MutableBoolean recursiveOut = null; + + // Start out true and "and" all other results + boolean success = true; + + // Check the required permissions but not for sets they rely on + // their underlying permissions + if (modelDAO.checkPermission(required)) + { + + // We have to do the test as no parent will help us out + success &= hasSinglePermission(authorisations, aclId); + + if (!success) + { + return false; + } + } + + // Check the other permissions required on the node + for (PermissionReference pr : nodeRequirements) + { + // Build a new test + AclTest nt = new AclTest(pr, typeQName, aspectQNames); + success &= nt.evaluate(authorisations, aclId); + if (!success) + { + return false; + } + } + + return success; + } + + public boolean hasSinglePermission(Set authorisations, Long aclId) + { + // Check global permission + + if (checkGlobalPermissions(authorisations)) + { + return true; + } + + return checkRequired(authorisations, aclId); + + } + + /** + * Check if we have a global permission + * + * @param authorisations + * @return + */ + private boolean checkGlobalPermissions(Set authorisations) + { + for (PermissionEntry pe : modelDAO.getGlobalPermissionEntries()) + { + if (isGranted(pe, authorisations)) + { + return true; + } + } + return false; + } + + /** + * Check that a given authentication is available on a node + * + * @param authorisations + * @param nodeRef + * @param denied + * @return + */ + boolean checkRequired(Set authorisations, Long aclId) + { + AccessControlList acl = aclDaoComponent.getAccessControlList(aclId); + + if (acl == null) + { + return false; + } + + Set> denied = new HashSet>(); + + // Check if each permission allows - the first wins. + // We could have other voting style mechanisms here + for (AccessControlEntry ace : acl.getEntries()) + { + if (isGranted(ace, authorisations, denied)) + { + return true; + } + } + return false; + } + + /** + * Is a permission granted + * + * @param pe - + * the permissions entry to consider + * @param granters - + * the set of granters + * @param authorisations - + * the set of authorities + * @param denied - + * the set of denied permissions/authority pais + * @return + */ + private boolean isGranted(AccessControlEntry ace, Set authorisations, Set> denied) + { + // If the permission entry denies then we just deny + if (ace.getAccessStatus() == AccessStatus.DENIED) + { + denied.add(new Pair(ace.getAuthority(), ace.getPermission())); + return false; + } + + // The permission is allowed but we deny it as it is in the denied + // set + + if (denied != null) + { + Pair specific = new Pair(ace.getAuthority(), required); + if (denied.contains(specific)) + { + return false; + } + } + + // any deny denies + + if (false) + { + if (denied != null) + { + for (String auth : authorisations) + { + Pair specific = new Pair(auth, required); + if (denied.contains(specific)) + { + return false; + } + for (PermissionReference perm : granters) + { + specific = new Pair(auth, perm); + if (denied.contains(specific)) + { + return false; + } + } + } + } + } + + // If the permission has a match in both the authorities and + // granters list it is allowed + // It applies to the current user and it is granted + if (authorisations.contains(ace.getAuthority()) && granters.contains(ace.getPermission())) + { + { + return true; + } + } + + // Default deny + return false; + } + + private boolean isGranted(PermissionEntry pe, Set authorisations) + { + // If the permission entry denies then we just deny + if (pe.isDenied()) + { + return false; + } + + // If the permission has a match in both the authorities and + // granters list it is allowed + // It applies to the current user and it is granted + if (authorisations.contains(pe.getAuthority()) && granters.contains(pe.getPermissionReference())) + { + { + return true; + } + } + + // Default deny + return false; + } + + } + /** * Helper class to store a pair of objects which may be null - * + * * @author Andy Hind */ private static class Pair 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 4c3ecbad89..1a982a8b76 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionServiceTest.java @@ -34,7 +34,6 @@ import org.alfresco.model.ContentModel; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.permissions.PermissionEntry; 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.service.cmr.security.AuthorityType; @@ -1818,9 +1817,9 @@ public class PermissionServiceTest extends AbstractPermissionTest NodeRef n9 = nodeService.createNode(n1, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}nine"), ContentModel.TYPE_FOLDER).getChildRef(); NodeRef n10 = nodeService.createNode(n1, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}ten"), ContentModel.TYPE_FOLDER).getChildRef(); - assertEquals(0, permissionService.getAllSetPermissionsForCurrentUser().size()); - assertEquals(0, permissionService.getAllSetPermissionsForAuthority("admin").size()); - assertEquals(0, permissionService.getAllSetPermissionsForAuthority("andy").size()); + //assertEquals(0, permissionService.getAllSetPermissionsForCurrentUser().size()); + //assertEquals(0, permissionService.getAllSetPermissionsForAuthority("admin").size()); + //assertEquals(0, permissionService.getAllSetPermissionsForAuthority("andy").size()); permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ_CHILDREN), "admin", AccessStatus.ALLOWED)); permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.READ_CONTENT), "admin", AccessStatus.ALLOWED)); @@ -1837,50 +1836,50 @@ public class PermissionServiceTest extends AbstractPermissionTest permissionService.setPermission(new SimplePermissionEntry(n10, getPermission(PermissionService.READ_CHILDREN), "admin", AccessStatus.DENIED)); permissionService.setPermission(new SimplePermissionEntry(n10, getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED)); - assertEquals(10, permissionService.getAllSetPermissionsForCurrentUser().size()); - assertEquals(10, permissionService.getAllSetPermissionsForAuthority("admin").size()); - assertEquals(2, permissionService.getAllSetPermissionsForAuthority("andy").size()); - assertNull(permissionService.getAllSetPermissionsForCurrentUser().get(rootNodeRef)); - assertNull(permissionService.getAllSetPermissionsForAuthority("admin").get(rootNodeRef)); - assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(rootNodeRef)); - assertEquals(2, permissionService.getAllSetPermissionsForCurrentUser().get(n1).size()); - assertEquals(2, permissionService.getAllSetPermissionsForAuthority("admin").get(n1).size()); - assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n1)); - assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n2).size()); - assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n2).size()); - assertEquals(1, permissionService.getAllSetPermissionsForAuthority("andy").get(n2).size()); - assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n3).size()); - assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n3).size()); - assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n3)); - assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n4).size()); - assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n4).size()); - assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n4)); - assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n5).size()); - assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n5).size()); - assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n5)); - assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n6).size()); - assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n6).size()); - assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n6)); - assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n7).size()); - assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n7).size()); - assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n7)); - assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n8).size()); - assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n8).size()); - assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n8)); - assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n9).size()); - assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n9).size()); - assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n9)); - assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n10).size()); - assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n10).size()); - assertEquals(1, permissionService.getAllSetPermissionsForAuthority("andy").get(n10).size()); +// assertEquals(10, permissionService.getAllSetPermissionsForCurrentUser().size()); +// assertEquals(10, permissionService.getAllSetPermissionsForAuthority("admin").size()); +// assertEquals(2, permissionService.getAllSetPermissionsForAuthority("andy").size()); +// assertNull(permissionService.getAllSetPermissionsForCurrentUser().get(rootNodeRef)); +// assertNull(permissionService.getAllSetPermissionsForAuthority("admin").get(rootNodeRef)); +// assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(rootNodeRef)); +// assertEquals(2, permissionService.getAllSetPermissionsForCurrentUser().get(n1).size()); +// assertEquals(2, permissionService.getAllSetPermissionsForAuthority("admin").get(n1).size()); +// assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n1)); +// assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n2).size()); +// assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n2).size()); +// assertEquals(1, permissionService.getAllSetPermissionsForAuthority("andy").get(n2).size()); +// assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n3).size()); +// assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n3).size()); +// assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n3)); +// assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n4).size()); +// assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n4).size()); +// assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n4)); +// assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n5).size()); +// assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n5).size()); +// assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n5)); +// assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n6).size()); +// assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n6).size()); +// assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n6)); +// assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n7).size()); +// assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n7).size()); +// assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n7)); +// assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n8).size()); +// assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n8).size()); +// assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n8)); +// assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n9).size()); +// assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n9).size()); +// assertNull(permissionService.getAllSetPermissionsForAuthority("andy").get(n9)); +// assertEquals(1, permissionService.getAllSetPermissionsForCurrentUser().get(n10).size()); +// assertEquals(1, permissionService.getAllSetPermissionsForAuthority("admin").get(n10).size()); +// assertEquals(1, permissionService.getAllSetPermissionsForAuthority("andy").get(n10).size()); } - public void testFindNodesByPermission() + public void xtestFindNodesByPermission() { runAs("admin"); - StoreRef storeRef = rootNodeRef.getStoreRef(); + //StoreRef storeRef = rootNodeRef.getStoreRef(); NodeRef n1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}one"), ContentModel.TYPE_FOLDER).getChildRef(); NodeRef n2 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("{namespace}two"), ContentModel.TYPE_FOLDER).getChildRef(); @@ -1897,14 +1896,14 @@ public class PermissionServiceTest extends AbstractPermissionTest String groupAuth = authorityService.createAuthority(AuthorityType.GROUP, null, "G"); authorityService.addAuthority(groupAuth, "andy"); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser("Consumer", true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser("Consumer", false, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", "Consumer", true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", "Consumer", false, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", "Consumer", true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", "Consumer", false, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, "Consumer", true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, "Consumer", false, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser("Consumer", true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser("Consumer", false, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", "Consumer", true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", "Consumer", false, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", "Consumer", true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", "Consumer", false, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, "Consumer", true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, "Consumer", false, false, false), storeRef).size()); permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.CONSUMER), "admin", AccessStatus.ALLOWED)); permissionService.setPermission(new SimplePermissionEntry(n1, getPermission(PermissionService.CONSUMER), "andy", AccessStatus.ALLOWED)); @@ -1921,212 +1920,212 @@ public class PermissionServiceTest extends AbstractPermissionTest permissionService.setPermission(new SimplePermissionEntry(n4, getPermission(PermissionService.READ_CHILDREN), groupAuth, AccessStatus.ALLOWED)); permissionService.setPermission(new SimplePermissionEntry(n5, getPermission(PermissionService.READ_CONTENT), groupAuth, AccessStatus.ALLOWED)); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, false, false, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, false, false, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, true, false, false), storeRef).size()); - assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, false, false, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, true, false, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, false, false, false), storeRef).size()); - - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, false, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, false, false, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, false, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, false, false, false), storeRef).size()); - - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, false, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, false, false, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, false, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, false, false, false), storeRef).size()); - - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, false, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, false, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, false, false, false), storeRef).size()); - assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, false, false, false), storeRef).size()); - - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, false, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, false, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, false, false, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, true, false, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, false, false, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, false, false, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, false, false, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, true, false, false), storeRef).size()); +// assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, false, false, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, true, false, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, false, false, false), storeRef).size()); +// +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, false, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, false, false, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, false, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, false, false, false), storeRef).size()); +// +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, false, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, false, false, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, false, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, false, false, false), storeRef).size()); +// +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, false, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, false, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, false, false, false), storeRef).size()); +// assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, false, false, false), storeRef).size()); +// +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, false, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, false, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, false, false, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, true, false, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, false, false, false), storeRef).size()); // Include groups for exact match - for (NodeRef nodeRef : permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, true, true, false)) - { - System.out.println("Found " + nodeService.getPath(nodeRef)); - } +// for (NodeRef nodeRef : permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, true, true, false)) +// { +// System.out.println("Found " + nodeService.getPath(nodeRef)); +// } - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, false, true, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, false, true, false), storeRef).size()); - assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, true, true, false), storeRef).size()); - assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, false, true, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, true, true, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, false, true, false), storeRef).size()); - - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, false, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, false, true, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, false, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, false, true, false), storeRef).size()); - - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, false, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, false, true, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, false, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, false, true, false), storeRef).size()); - - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, false, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, false, true, false), storeRef).size()); - assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, false, true, false), storeRef).size()); - assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, false, true, false), storeRef).size()); - - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, false, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, false, true, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, false, true, false), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, true, true, false), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, false, true, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, false, true, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, false, true, false), storeRef).size()); +// assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, true, true, false), storeRef).size()); +// assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, false, true, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, true, true, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, false, true, false), storeRef).size()); +// +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, false, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, false, true, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, false, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, false, true, false), storeRef).size()); +// +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, false, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, false, true, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, false, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, false, true, false), storeRef).size()); +// +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, false, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, false, true, false), storeRef).size()); +// assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, false, true, false), storeRef).size()); +// assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, false, true, false), storeRef).size()); +// +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, false, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, false, true, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, false, true, false), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, true, true, false), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, false, true, false), storeRef).size()); // Include inexact permission - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, true, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, false, false, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, true, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, false, false, true), storeRef).size()); - assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, true, false, true), storeRef).size()); - assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, false, false, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, true, false, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, false, false, true), storeRef).size()); - - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, true, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, false, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, true, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, false, false, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, true, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, false, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, true, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, false, false, true), storeRef).size()); - - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, true, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, false, false, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, true, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, false, false, true), storeRef).size()); - assertEquals(3, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, true, false, true), storeRef).size()); - assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, false, false, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, true, false, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, false, false, true), storeRef).size()); - - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, true, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, false, false, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, true, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, false, false, true), storeRef).size()); - assertEquals(3, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, true, false, true), storeRef).size()); - assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, false, false, true), storeRef).size()); - assertEquals(3, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, true, false, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, false, false, true), storeRef).size()); - - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, true, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, false, false, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, true, false, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, false, false, true), storeRef).size()); - assertEquals(3, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, true, false, true), storeRef).size()); - assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, false, false, true), storeRef).size()); - assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, true, false, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, false, false, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, true, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, false, false, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, true, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, false, false, true), storeRef).size()); +// assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, true, false, true), storeRef).size()); +// assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, false, false, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, true, false, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, false, false, true), storeRef).size()); +// +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, true, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, false, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, true, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, false, false, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, true, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, false, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, true, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, false, false, true), storeRef).size()); +// +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, true, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, false, false, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, true, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, false, false, true), storeRef).size()); +// assertEquals(3, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, true, false, true), storeRef).size()); +// assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, false, false, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, true, false, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, false, false, true), storeRef).size()); +// +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, true, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, false, false, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, true, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, false, false, true), storeRef).size()); +// assertEquals(3, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, true, false, true), storeRef).size()); +// assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, false, false, true), storeRef).size()); +// assertEquals(3, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, true, false, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, false, false, true), storeRef).size()); +// +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, true, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, false, false, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, true, false, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, false, false, true), storeRef).size()); +// assertEquals(3, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, true, false, true), storeRef).size()); +// assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, false, false, true), storeRef).size()); +// assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, true, false, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, false, false, true), storeRef).size()); // Inexact for all - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, true, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, false, true, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, true, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, false, true, true), storeRef).size()); - assertEquals(3, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, true, true, true), storeRef).size()); - assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, false, true, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, true, true, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, false, true, true), storeRef).size()); - - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, true, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, false, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, true, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, false, true, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, true, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, false, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, true, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, false, true, true), storeRef).size()); - - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, true, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, false, true, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, true, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, false, true, true), storeRef).size()); - assertEquals(4, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, true, true, true), storeRef).size()); - assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, false, true, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, true, true, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, false, true, true), storeRef).size()); - - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, true, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, false, true, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, true, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, false, true, true), storeRef).size()); - assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, true, true, true), storeRef).size()); - assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, false, true, true), storeRef).size()); - assertEquals(3, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, true, true, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, false, true, true), storeRef).size()); - - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, true, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, false, true, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, true, true, true), storeRef).size()); - assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, false, true, true), storeRef).size()); - assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, true, true, true), storeRef).size()); - assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, false, true, true), storeRef).size()); - assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, true, true, true), storeRef).size()); - assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, false, true, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, true, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONSUMER, false, true, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, true, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONSUMER, false, true, true), storeRef).size()); +// assertEquals(3, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, true, true, true), storeRef).size()); +// assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONSUMER, false, true, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, true, true, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONSUMER, false, true, true), storeRef).size()); +// +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, true, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.CONTRIBUTOR, false, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, true, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.CONTRIBUTOR, false, true, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, true, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.CONTRIBUTOR, false, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, true, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.CONTRIBUTOR, false, true, true), storeRef).size()); +// +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, true, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ, false, true, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, true, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ, false, true, true), storeRef).size()); +// assertEquals(4, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, true, true, true), storeRef).size()); +// assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ, false, true, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, true, true, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ, false, true, true), storeRef).size()); +// +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, true, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CONTENT, false, true, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, true, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CONTENT, false, true, true), storeRef).size()); +// assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, true, true, true), storeRef).size()); +// assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CONTENT, false, true, true), storeRef).size()); +// assertEquals(3, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, true, true, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CONTENT, false, true, true), storeRef).size()); +// +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, true, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermissionForCurrentUser(PermissionService.READ_CHILDREN, false, true, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, true, true, true), storeRef).size()); +// assertEquals(0, filterForStore(permissionService.findNodesByAssignedPermission("admin", PermissionService.READ_CHILDREN, false, true, true), storeRef).size()); +// assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, true, true, true), storeRef).size()); +// assertEquals(5, filterForStore(permissionService.findNodesByAssignedPermission("andy", PermissionService.READ_CHILDREN, false, true, true), storeRef).size()); +// assertEquals(2, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, true, true, true), storeRef).size()); +// assertEquals(1, filterForStore(permissionService.findNodesByAssignedPermission(groupAuth, PermissionService.READ_CHILDREN, false, true, true), storeRef).size()); } - private Set filterForStore(Set set, StoreRef storeRef) - { - Set toRemove = new HashSet(); - for (NodeRef node : set) - { - if (!node.getStoreRef().equals(storeRef)) - { - toRemove.add(node); - } - } - set.removeAll(toRemove); - return set; - } +// private Set filterForStore(Set set, StoreRef storeRef) +// { +// Set toRemove = new HashSet(); +// for (NodeRef node : set) +// { +// if (!node.getStoreRef().equals(storeRef)) +// { +// toRemove.add(node); +// } +// } +// set.removeAll(toRemove); +// return set; +// } // TODO: Test permissions on missing nodes diff --git a/source/java/org/alfresco/repo/security/permissions/impl/PermissionsDaoComponent.java b/source/java/org/alfresco/repo/security/permissions/impl/PermissionsDaoComponent.java index d1be6ac957..7f0c7cdf57 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/PermissionsDaoComponent.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/PermissionsDaoComponent.java @@ -56,7 +56,7 @@ public interface PermissionsDaoComponent public void deletePermissions(NodeRef nodeRef); /** - * Remove all permissions for the specvified authority + * Remove all permissions for the specified authority * @param authority */ public void deletePermissions(String authority); diff --git a/source/java/org/alfresco/repo/security/permissions/impl/hibernate/HibernatePermissionTest.java b/source/java/org/alfresco/repo/security/permissions/impl/hibernate/HibernatePermissionTest.java deleted file mode 100644 index 0baa455f9b..0000000000 --- a/source/java/org/alfresco/repo/security/permissions/impl/hibernate/HibernatePermissionTest.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2005-2007 Alfresco Software Limited. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - * As a special exception to the terms and conditions of version 2.0 of - * the GPL, you may redistribute this Program in connection with Free/Libre - * and Open Source Software ("FLOSS") applications as described in Alfresco's - * FLOSS exception. You should have recieved a copy of the text describing - * the FLOSS exception, and it is also available here: - * http://www.alfresco.com/legal/licensing" - */ -package org.alfresco.repo.security.permissions.impl.hibernate; - -import java.io.Serializable; - -import org.alfresco.repo.domain.DbAccessControlEntry; -import org.alfresco.repo.domain.DbAccessControlList; -import org.alfresco.repo.domain.DbAuthority; -import org.alfresco.repo.domain.DbPermission; -import org.alfresco.repo.domain.Node; -import org.alfresco.repo.domain.Store; -import org.alfresco.repo.domain.hibernate.DbAccessControlEntryImpl; -import org.alfresco.repo.domain.hibernate.DbAccessControlListImpl; -import org.alfresco.repo.domain.hibernate.DbAuthorityImpl; -import org.alfresco.repo.domain.hibernate.DbPermissionImpl; -import org.alfresco.repo.node.db.NodeDaoService; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.BaseSpringTest; -import org.alfresco.util.GUID; - -/** - * @see org.alfresco.repo.domain.hibernate.PermissionsDaoComponentImpl - * @see org.alfresco.repo.domain.DbAccessControlList - * @see org.alfresco.repo.domain.DbAccessControlEntry - * - * @author Andy Hind - */ -public class HibernatePermissionTest extends BaseSpringTest -{ - private NodeDaoService nodeDaoService; - private Node node; - private QName qname; - - public HibernatePermissionTest() - { - } - - protected void onSetUpInTransaction() throws Exception - { - nodeDaoService = (NodeDaoService) applicationContext.getBean("nodeDaoService"); - - // create the node to play with - Store store = nodeDaoService.createStore( - StoreRef.PROTOCOL_WORKSPACE, - getName() + "_" + System.currentTimeMillis()); - qname = QName.createQName(NamespaceService.ALFRESCO_URI, getName()); - node = nodeDaoService.newNode( - store, - GUID.generate(), - qname); - } - - protected void onTearDownInTransaction() - { - try - { - // force a flush to ensure that the database updates succeed - getSession().flush(); - getSession().clear(); - } - catch (Throwable e) - { - // don't mask any other exception coming through - e.printStackTrace(); - } - } - - public void testSimpleAccessControlList() throws Exception - { - // create a new Node - DbAccessControlList accessControlList = new DbAccessControlListImpl(); - accessControlList.setInherits(true); - Serializable id = getSession().save(accessControlList); - node.setAccessControlList(accessControlList); - - // throw the reference away and get the a new one for the id - accessControlList = (DbAccessControlList) getSession().load(DbAccessControlListImpl.class, id); - assertNotNull("Access control list not found", accessControlList); - assertTrue(accessControlList.getInherits()); - - // Update inherits - - accessControlList.setInherits(false); - id = getSession().save(accessControlList); - - // throw the reference away and get the a new one for the id - accessControlList = (DbAccessControlList) getSession().load(DbAccessControlListImpl.class, id); - assertNotNull("Node not found", accessControlList); - assertFalse(accessControlList.getInherits()); - } - - public void testSimplePermission() - { - DbPermission permission = new DbPermissionImpl(); - permission.setTypeQname(qname); - permission.setName("Test"); - - Serializable id = getSession().save(permission); - - // throw the reference away and get the a new one for the id - permission = (DbPermission) getSession().load(DbPermissionImpl.class, id); - assertNotNull("Permission not found", permission); - assertEquals(qname, permission.getTypeQname()); - } - - public void testSimpleAuthority() - { - DbAuthority authority = new DbAuthorityImpl(); - authority.setRecipient("Test"); - authority.getExternalKeys().add("One"); - - Serializable id = getSession().save(authority); - - // throw the reference away and get the a new one for the id - authority = (DbAuthority) getSession().load(DbAuthorityImpl.class, id); - assertNotNull("Node not found", authority); - assertEquals("Test", authority.getRecipient()); - assertEquals(1, authority.getExternalKeys().size()); - - // Update - - authority.getExternalKeys().add("Two"); - id = getSession().save(authority); - - // throw the reference away and get the a new one for the id - authority = (DbAuthority) getSession().load(DbAuthorityImpl.class, id); - assertNotNull("Node not found", authority); - assertEquals("Test", authority.getRecipient()); - assertEquals(2, authority.getExternalKeys().size()); - - - // complex - - authority.getExternalKeys().add("Three"); - authority.getExternalKeys().remove("One"); - authority.getExternalKeys().remove("Two"); - id = getSession().save(authority); - - // Throw the reference away and get the a new one for the id - authority = (DbAuthority) getSession().load(DbAuthorityImpl.class, id); - assertNotNull("Node not found", authority); - assertEquals("Test", authority.getRecipient()); - assertEquals(1, authority.getExternalKeys().size()); - } - - public void testAccessControlList() - { - // create a new access control list for the node - DbAccessControlList accessControlList = new DbAccessControlListImpl(); - accessControlList.setInherits(true); - Serializable nodeAclId = getSession().save(accessControlList); - node.setAccessControlList(accessControlList); - - DbAuthority recipient = new DbAuthorityImpl(); - recipient.setRecipient("Test"); - recipient.getExternalKeys().add("One"); - getSession().save(recipient); - - DbPermission permission = new DbPermissionImpl(); - permission.setTypeQname(qname); - permission.setName("Test"); - getSession().save(permission); - - DbAccessControlEntry accessControlEntry = accessControlList.newEntry(permission, recipient, true); - Long aceEntryId = accessControlEntry.getId(); - assertNotNull("Entry is still transient", aceEntryId); - - accessControlEntry = (DbAccessControlEntry) getSession().load(DbAccessControlEntryImpl.class, aceEntryId); - assertNotNull("Permission entry not found", accessControlEntry); - assertTrue(accessControlEntry.isAllowed()); - assertNotNull(accessControlEntry.getAccessControlList()); - assertTrue(accessControlEntry.getAccessControlList().getInherits()); - assertNotNull(accessControlEntry.getPermission()); - assertEquals("Test", accessControlEntry.getPermission().getKey().getName()); - assertNotNull(accessControlEntry.getAuthority()); - assertEquals("Test", accessControlEntry.getAuthority().getRecipient()); - assertEquals(1, accessControlEntry.getAuthority().getExternalKeys().size()); - - // Check that deletion of the list cascades - node.setAccessControlList(null); - getSession().delete(accessControlList); - DbAccessControlEntry deletedAcl = (DbAccessControlEntry) getSession().get(DbAccessControlListImpl.class, nodeAclId); - assertNull("Access control list was not deleted", deletedAcl); - DbAccessControlEntry deletedAclEntry = (DbAccessControlEntry) getSession().get(DbAccessControlEntryImpl.class, aceEntryId); - assertNull("Access control entries were not cascade deleted", deletedAclEntry); - } -} \ No newline at end of file diff --git a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java index 3aa69f0a27..5a9bf3d1b2 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModel.java @@ -96,7 +96,6 @@ public class PermissionModel implements ModelDAO, InitializingBean private String model; - // Aprrox 6 - default size OK private Map permissionSets = new HashMap(); @@ -122,11 +121,9 @@ public class PermissionModel implements ModelDAO, InitializingBean private HashMap permissionReferenceMap; - private Map> cachedTypePermissionsExposed = new HashMap>( - 128, 1.0f); + private Map> cachedTypePermissionsExposed = new HashMap>(128, 1.0f); - private Map> cachedTypePermissionsUnexposed = new HashMap>( - 128, 1.0f); + private Map> cachedTypePermissionsUnexposed = new HashMap>(128, 1.0f); public PermissionModel() { @@ -202,8 +199,7 @@ public class PermissionModel implements ModelDAO, InitializingBean for (Iterator it = namespacesElement.elementIterator(NAMESPACE); it.hasNext(); /**/) { Element nameSpaceElement = (Element) it.next(); - nspr.registerNamespace(nameSpaceElement.attributeValue(NAMESPACE_PREFIX), nameSpaceElement - .attributeValue(NAMESPACE_URI)); + nspr.registerNamespace(nameSpaceElement.attributeValue(NAMESPACE_PREFIX), nameSpaceElement.attributeValue(NAMESPACE_URI)); } } @@ -290,15 +286,14 @@ public class PermissionModel implements ModelDAO, InitializingBean public Set getAllPermissions(QName type) { - return getAllPermissionsImpl(type, false); + return getAllPermissionsImpl(type, null, false); } public Set getExposedPermissions(QName type) { - return getAllPermissionsImpl(type, true); + return getAllPermissionsImpl(type, null, true); } - private Set getAllPermissionsImpl(QName type, boolean exposedOnly) { Map> cache; @@ -441,36 +436,49 @@ public class PermissionModel implements ModelDAO, InitializingBean public Set getAllPermissions(NodeRef nodeRef) { - return getExposedPermissionsImpl(nodeRef, false); + return getAllPermissionsImpl(nodeService.getType(nodeRef), nodeService.getAspects(nodeRef), false); } public Set getExposedPermissions(NodeRef nodeRef) { - return getExposedPermissionsImpl(nodeRef, true); + return getAllPermissionsImpl(nodeService.getType(nodeRef), nodeService.getAspects(nodeRef), true); } - public Set getExposedPermissionsImpl(NodeRef nodeRef, boolean exposedOnly) + public Set getAllPermissions(QName typeName, Set aspects) { - // - // TODO: cache permissions based on type and exposed flag - // create JMeter test to see before/after effect! - // - QName typeName = nodeService.getType(nodeRef); + return getAllPermissionsImpl(typeName, aspects, false); + } + private Set getAllPermissionsImpl(QName typeName, Set aspects, boolean exposedOnly) + { Set permissions = new LinkedHashSet(128, 1.0f); permissions.addAll(getAllPermissionsImpl(typeName, exposedOnly)); - mergeGeneralAspectPermissions(permissions, exposedOnly); - // Add non mandatory aspects... - Set defaultAspects = new HashSet(); - for (AspectDefinition aspDef : dictionaryService.getType(typeName).getDefaultAspects()) + + ClassDefinition cd = dictionaryService.getClass(typeName); + if (cd != null) { - defaultAspects.add(aspDef.getName()); - } - for (QName aspect : nodeService.getAspects(nodeRef)) - { - if (!defaultAspects.contains(aspect)) + if (cd.isAspect()) { - addAspectPermissions(aspect, permissions, exposedOnly); + // Do not merge in all general aspects + } + else + { + mergeGeneralAspectPermissions(permissions, exposedOnly); + } + Set defaultAspects = new HashSet(); + for (AspectDefinition aspDef : cd.getDefaultAspects()) + { + defaultAspects.add(aspDef.getName()); + } + if (aspects != null) + { + for (QName aspect : aspects) + { + if (!defaultAspects.contains(aspect)) + { + addAspectPermissions(aspect, permissions, exposedOnly); + } + } } } return permissions; @@ -582,8 +590,7 @@ public class PermissionModel implements ModelDAO, InitializingBean { if (pg.getTypeQName() != null) { - permissions.addAll(getGranteePermissions(new SimplePermissionReference(pg.getTypeQName(), - pg.getName()))); + permissions.addAll(getGranteePermissions(new SimplePermissionReference(pg.getTypeQName(), pg.getName()))); } else { @@ -592,8 +599,7 @@ public class PermissionModel implements ModelDAO, InitializingBean if (parent != null) { classDefinition = dictionaryService.getClass(parent); - PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference( - parent, pg.getName())); + PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference(parent, pg.getName())); if (attempt != null) { permissions.addAll(getGranteePermissions(attempt)); @@ -668,8 +674,7 @@ public class PermissionModel implements ModelDAO, InitializingBean PermissionGroup pg = getPermissionGroupOrNull(target); if (pg == null) { - throw new PermissionModelException("There is no permission group :" - + target.getQName() + " " + target.getName()); + throw new PermissionModelException("There is no permission group :" + target.getQName() + " " + target.getName()); } return pg; } @@ -716,8 +721,7 @@ public class PermissionModel implements ModelDAO, InitializingBean while ((parent = classDefinition.getParentName()) != null) { classDefinition = dictionaryService.getClass(parent); - PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference(parent, pg - .getName())); + PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference(parent, pg.getName())); if ((attempt != null) && (!attempt.isExtends())) { return attempt; @@ -737,14 +741,12 @@ public class PermissionModel implements ModelDAO, InitializingBean PermissionGroup pg = getBasePermissionGroupOrNull(target); if (pg == null) { - throw new PermissionModelException("There is no parent for permission group :" - + target.getQName() + " " + target.getName()); + throw new PermissionModelException("There is no parent for permission group :" + target.getQName() + " " + target.getName()); } return pg; } - - static Serializable generateKey(PermissionReference required, QName qName, Set aspectQNames, - RequiredPermission.On on) + + static Serializable generateKey(PermissionReference required, QName qName, Set aspectQNames, RequiredPermission.On on) { LinkedHashSet key = new LinkedHashSet(); key.add(required.toString()); @@ -754,12 +756,9 @@ public class PermissionModel implements ModelDAO, InitializingBean return key; } + private HashMap> requiredPermissionsCache = new HashMap>(1024); - private HashMap> requiredPermissionsCache = new HashMap>( - 1024); - - public Set getRequiredPermissions(PermissionReference required, QName qName, - Set aspectQNames, RequiredPermission.On on) + public Set getRequiredPermissions(PermissionReference required, QName qName, Set aspectQNames, RequiredPermission.On on) { // Cache lookup as this is static @@ -816,8 +815,7 @@ public class PermissionModel implements ModelDAO, InitializingBean * @param aspectQNames * @return */ - private Set getRequirementsForPermissionGroup(PermissionGroup target, - RequiredPermission.On on, QName qName, Set aspectQNames) + private Set getRequirementsForPermissionGroup(PermissionGroup target, RequiredPermission.On on, QName qName, Set aspectQNames) { HashSet requiredPermissions = new HashSet(8, 1.0f); if (target == null) @@ -829,14 +827,12 @@ public class PermissionModel implements ModelDAO, InitializingBean for (PermissionGroup pg : ps.getPermissionGroups()) { PermissionGroup base = getBasePermissionGroupOrNull(pg); - if ((target.equals(base) || target.isAllowFullControl()) - && (!base.isTypeRequired() || isPartOfDynamicPermissionGroup(pg, qName, aspectQNames))) + if ((target.equals(base) || target.isAllowFullControl()) && (!base.isTypeRequired() || isPartOfDynamicPermissionGroup(pg, qName, aspectQNames))) { // Add includes for (PermissionReference pr : pg.getIncludedPermissionGroups()) { - requiredPermissions.addAll(getRequirementsForPermissionGroup( - getBasePermissionGroupOrNull(getPermissionGroupOrNull(pr)), on, qName, aspectQNames)); + requiredPermissions.addAll(getRequirementsForPermissionGroup(getBasePermissionGroupOrNull(getPermissionGroupOrNull(pr)), on, qName, aspectQNames)); } } } @@ -845,8 +841,7 @@ public class PermissionModel implements ModelDAO, InitializingBean for (PermissionReference grantedTo : p.getGrantedToGroups()) { PermissionGroup base = getBasePermissionGroupOrNull(getPermissionGroupOrNull(grantedTo)); - if ((target.equals(base) || target.isAllowFullControl()) - && (!base.isTypeRequired() || isPartOfDynamicPermissionGroup(grantedTo, qName, aspectQNames))) + if ((target.equals(base) || target.isAllowFullControl()) && (!base.isTypeRequired() || isPartOfDynamicPermissionGroup(grantedTo, qName, aspectQNames))) { if (on == RequiredPermission.On.NODE) { @@ -918,8 +913,7 @@ public class PermissionModel implements ModelDAO, InitializingBean while ((parent = classDefinition.getParentName()) != null) { classDefinition = dictionaryService.getClass(parent); - PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference(parent, pg - .getName())); + PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference(parent, pg.getName())); if ((attempt != null) && attempt.isAllowFullControl()) { return true; @@ -1023,13 +1017,10 @@ public class PermissionModel implements ModelDAO, InitializingBean // Add all permissions to the unique list if (uniqueMap.containsKey(PermissionService.ALL_PERMISSIONS)) { - throw new IllegalStateException( - "There must not be a permission with the same name as the ALL_PERMISSION constant: " - + PermissionService.ALL_PERMISSIONS); + throw new IllegalStateException("There must not be a permission with the same name as the ALL_PERMISSION constant: " + PermissionService.ALL_PERMISSIONS); } - uniqueMap.put(PermissionService.ALL_PERMISSIONS, new SimplePermissionReference(QName.createQName( - NamespaceService.SECURITY_MODEL_1_0_URI, PermissionService.ALL_PERMISSIONS), - PermissionService.ALL_PERMISSIONS)); + uniqueMap.put(PermissionService.ALL_PERMISSIONS, new SimplePermissionReference(QName + .createQName(NamespaceService.SECURITY_MODEL_1_0_URI, PermissionService.ALL_PERMISSIONS), PermissionService.ALL_PERMISSIONS)); } diff --git a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModelTest.java b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModelTest.java index 19215f2d51..992ba5e5d1 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModelTest.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/model/PermissionModelTest.java @@ -89,7 +89,8 @@ public class PermissionModelTest extends AbstractPermissionTest namespacePrefixResolver), "Coordinator")); // NB This has gone from 59 to 63, I believe, because of the for new WCM roles. - assertEquals(63, grantees.size()); + // 63-97 from AVM permission fix up + assertEquals(97, grantees.size()); } public void testIncludePermissionGroups6() diff --git a/source/java/org/alfresco/repo/security/permissions/noop/PermissionServiceNOOPImpl.java b/source/java/org/alfresco/repo/security/permissions/noop/PermissionServiceNOOPImpl.java index f70e1e5cb3..876f83281e 100644 --- a/source/java/org/alfresco/repo/security/permissions/noop/PermissionServiceNOOPImpl.java +++ b/source/java/org/alfresco/repo/security/permissions/noop/PermissionServiceNOOPImpl.java @@ -33,9 +33,12 @@ import org.alfresco.repo.security.permissions.NodePermissionEntry; import org.alfresco.repo.security.permissions.PermissionEntry; import org.alfresco.repo.security.permissions.PermissionReference; import org.alfresco.repo.security.permissions.PermissionServiceSPI; +import org.alfresco.repo.security.permissions.impl.PermissionReferenceImpl; +import org.alfresco.repo.security.permissions.impl.SimpleNodePermissionEntry; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.AccessStatus; +import org.alfresco.service.cmr.security.PermissionContext; import org.alfresco.service.namespace.QName; @@ -76,7 +79,7 @@ public class PermissionServiceNOOPImpl */ public Set getPermissions(NodeRef nodeRef) { - return null; + return Collections.emptySet(); } /* (non-Javadoc) @@ -84,7 +87,7 @@ public class PermissionServiceNOOPImpl */ public Set getAllSetPermissions(NodeRef nodeRef) { - return null; + return Collections.emptySet(); } /* (non-Javadoc) @@ -179,48 +182,48 @@ public class PermissionServiceNOOPImpl public PermissionReference getAllPermissionReference() { - throw new UnsupportedOperationException(); + return getPermissionReference(ALL_PERMISSIONS); } public String getPermission(PermissionReference permissionReference) { - throw new UnsupportedOperationException(); + return permissionReference.toString(); } public PermissionReference getPermissionReference(QName qname, String permissionName) { - throw new UnsupportedOperationException(); + return new PermissionReferenceImpl(qname, permissionName); } public PermissionReference getPermissionReference(String permissionName) { - throw new UnsupportedOperationException(); + return new PermissionReferenceImpl(QName.createQName("uri", "local"), permissionName); } public NodePermissionEntry getSetPermissions(NodeRef nodeRef) { - throw new UnsupportedOperationException(); + return new SimpleNodePermissionEntry(nodeRef, true, Collections.emptySet()); } public Set getSettablePermissionReferences(NodeRef nodeRef) { - throw new UnsupportedOperationException(); + return Collections.emptySet(); } public Set getSettablePermissionReferences(QName type) { - throw new UnsupportedOperationException(); + return Collections.emptySet(); } public AccessStatus hasPermission(NodeRef nodeRef, PermissionReference perm) { - throw new UnsupportedOperationException(); + return AccessStatus.ALLOWED; } /* (non-Javadoc) * @see org.alfresco.service.cmr.security.PermissionService#hasPermission(java.lang.Long, java.lang.String, java.lang.String) */ - public AccessStatus hasPermission(Long aclID, Map context, + public AccessStatus hasPermission(Long aclID, PermissionContext context, String permission) { return AccessStatus.ALLOWED; @@ -228,12 +231,12 @@ public class PermissionServiceNOOPImpl public void setPermission(NodePermissionEntry nodePermissionEntry) { - throw new UnsupportedOperationException(); + } public void setPermission(PermissionEntry permissionEntry) { - throw new UnsupportedOperationException(); + } public Map> getAllSetPermissionsForCurrentUser() diff --git a/source/java/org/alfresco/service/cmr/lock/LockService.java b/source/java/org/alfresco/service/cmr/lock/LockService.java index 7c43825123..f10c1272c7 100644 --- a/source/java/org/alfresco/service/cmr/lock/LockService.java +++ b/source/java/org/alfresco/service/cmr/lock/LockService.java @@ -219,6 +219,18 @@ public interface LockService @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef"}) public LockStatus getLockStatus(NodeRef nodeRef); + + /** + * Gets the lock status for the node reference relative to the current user. + * + * @see LockService#getLockStatus(NodeRef, NodeRef) + * + * @param nodeRef the node reference + * @return the lock status + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = {"nodeRef", "userName"}) + public LockStatus getLockStatus(NodeRef nodeRef, String userName); + /** * Gets the lock type for the node indicated. *

diff --git a/source/java/org/alfresco/service/cmr/security/AuthorityType.java b/source/java/org/alfresco/service/cmr/security/AuthorityType.java index c7daa45b65..b1eb7c0637 100644 --- a/source/java/org/alfresco/service/cmr/security/AuthorityType.java +++ b/source/java/org/alfresco/service/cmr/security/AuthorityType.java @@ -34,8 +34,7 @@ package org.alfresco.service.cmr.security; *

  • GROUP - an authority that identifies a group *
  • OWNER - the special authority that applies to the owner of a node *
  • EVERYONE - the special authority that is interpreted as everyone - *
  • GUEST - the special authority that applies to a GUEST (An unknown, - * unauthenticated user) + *
  • GUEST - the special authority that applies to a GUEST (An unknown, unauthenticated user) * * * @author Andy Hind @@ -63,6 +62,11 @@ public enum AuthorityType { return ""; } + + public int getOrderPosition() + { + return 0; + } }, EVERYONE @@ -86,6 +90,11 @@ public enum AuthorityType { return ""; } + + public int getOrderPosition() + { + return 1; + } }, OWNER { @@ -108,6 +117,11 @@ public enum AuthorityType { return ""; } + + public int getOrderPosition() + { + return 2; + } }, GUEST { @@ -130,6 +144,11 @@ public enum AuthorityType { return ""; } + + public int getOrderPosition() + { + return 3; + } }, GROUP { @@ -152,6 +171,11 @@ public enum AuthorityType { return PermissionService.GROUP_PREFIX; } + + public int getOrderPosition() + { + return 4; + } }, ROLE { @@ -175,6 +199,11 @@ public enum AuthorityType { return PermissionService.ROLE_PREFIX; } + + public int getOrderPosition() + { + return 5; + } }, USER { @@ -197,6 +226,11 @@ public enum AuthorityType { return ""; } + + public int getOrderPosition() + { + return 6; + } }; public abstract boolean isFixedString(); @@ -207,6 +241,8 @@ public enum AuthorityType public abstract String getPrefixString(); + public abstract int getOrderPosition(); + public boolean equals(String authority) { return equals(getAuthorityType(authority)); diff --git a/source/java/org/alfresco/service/cmr/security/PermissionContext.java b/source/java/org/alfresco/service/cmr/security/PermissionContext.java new file mode 100644 index 0000000000..3045098aa2 --- /dev/null +++ b/source/java/org/alfresco/service/cmr/security/PermissionContext.java @@ -0,0 +1,90 @@ +/* + * 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.service.cmr.security; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.alfresco.service.namespace.QName; + +public class PermissionContext +{ + private QName type; + + private HashSet aspects = new HashSet(); + + private Map properties = new HashMap(); + + private Map> dynamicAuthorityAssignment = new HashMap>(); + + private Map additionalContext = new HashMap(); + + public PermissionContext(QName type) + { + this.type = type; + } + + public HashSet getAspects() + { + return aspects; + } + + public Map> getDynamicAuthorityAssignment() + { + return dynamicAuthorityAssignment; + } + + public void addDynamicAuthorityAssignment(String user, String dynamicAuthority) + { + Set dynamicAuthorities = dynamicAuthorityAssignment.get(user); + if(dynamicAuthorities == null) + { + dynamicAuthorities = new HashSet(); + dynamicAuthorityAssignment.put(user, dynamicAuthorities); + } + dynamicAuthorities.add(dynamicAuthority); + } + + public Map getAdditionalContext() + { + return additionalContext; + } + + public Map getProperties() + { + return properties; + } + + public QName getType() + { + return type; + } + + + +} diff --git a/source/java/org/alfresco/service/cmr/security/PermissionService.java b/source/java/org/alfresco/service/cmr/security/PermissionService.java index 55b428b95b..b19015710a 100644 --- a/source/java/org/alfresco/service/cmr/security/PermissionService.java +++ b/source/java/org/alfresco/service/cmr/security/PermissionService.java @@ -234,7 +234,7 @@ public interface PermissionService * @return */ @Auditable(parameters = { "aclID", "context", "permission" }) - public AccessStatus hasPermission(Long aclID, Map context, String permission); + public AccessStatus hasPermission(Long aclID, PermissionContext context, String permission); /** * Delete all the permission assigned to the node @@ -306,6 +306,7 @@ public interface PermissionService * Get all permissions set for the current user. * * @return - A map of noderefs to permissions set + * @deprecated */ @Auditable public Map> getAllSetPermissionsForCurrentUser(); @@ -315,6 +316,7 @@ public interface PermissionService * * @param authority * @return - A map of noderefs to permissions set + * @deprecated */ @Auditable(parameters = { "authority" }) public Map> getAllSetPermissionsForAuthority(String authority); @@ -331,6 +333,7 @@ public interface PermissionService * @param includeContainingPermissions - * true; do an exact match: false; search for any permission that woudl imply the one given * @return - the set of nodes where the user is assigned the permission + * @deprecated */ @Auditable(parameters = { "permission", "allow", "includeContainingAuthorities", "includeContainingPermissions" }) public Set findNodesByAssignedPermissionForCurrentUser(String permission, boolean allow, boolean includeContainingAuthorities, @@ -348,6 +351,7 @@ public interface PermissionService * @param exactPermissionMatch - * true; do an exact match: false; search for any permission that woudl imply the one given * @return - the set of nodes where the user is assigned the permission + * @deprecated */ @Auditable(parameters = { "authority", "permission", "allow", "includeContainingAuthorities", "exactPermissionMatch" })