diff --git a/config/alfresco/avm-services-context.xml b/config/alfresco/avm-services-context.xml
index 9a8a048ba6..3d30520a9e 100644
--- a/config/alfresco/avm-services-context.xml
+++ b/config/alfresco/avm-services-context.xml
@@ -4,54 +4,6 @@
-
-
-
-
- node
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- layer
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -113,9 +65,6 @@
-
-
-
@@ -186,12 +135,6 @@
-
-
-
-
-
-
diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml
index bdef462051..28d13be08a 100644
--- a/config/alfresco/bootstrap-context.xml
+++ b/config/alfresco/bootstrap-context.xml
@@ -95,6 +95,7 @@
+
@@ -118,12 +119,6 @@
-
-
-
-
-
-
diff --git a/config/alfresco/dbscripts/upgrade/3.2/org.hibernate.dialect.MySQLInnoDBDialect/remove-AVM-issuer.sql b/config/alfresco/dbscripts/upgrade/3.2/org.hibernate.dialect.MySQLInnoDBDialect/remove-AVM-issuer.sql
new file mode 100644
index 0000000000..1a717b86fe
--- /dev/null
+++ b/config/alfresco/dbscripts/upgrade/3.2/org.hibernate.dialect.MySQLInnoDBDialect/remove-AVM-issuer.sql
@@ -0,0 +1,53 @@
+--
+-- Title: Upgrade to V3.2 - Remove AVM Issuer
+-- Database: MySQL
+-- Since: V3.2 schema X
+-- Author: janv
+--
+-- remove AVM node issuer - replace with auto-increment id
+--
+-- Please contact support@alfresco.com if you need assistance with the upgrade.
+--
+
+-- -----------------------------
+-- Enable auto-increment --
+-- -----------------------------
+
+insert into avm_nodes
+select
+(select max(id)+1 from avm_nodes),
+class_type, vers, version_id, guid, creator, owner, lastModifier, createDate, modDate, accessDate, is_root, store_new_id, acl_id, deletedType, layer_id, indirection, indirection_version, primary_indirection, opacity, content_url, mime_type, encoding, length
+from avm_nodes where id = 0;
+
+update avm_aspects set node_id = (select max(id) from avm_nodes) where node_id = 0;
+
+update avm_child_entries set parent_id = (select max(id) from avm_nodes) where parent_id = 0;
+update avm_child_entries set child_id = (select max(id) from avm_nodes) where child_id = 0;
+
+update avm_history_links set ancestor = (select max(id) from avm_nodes) where ancestor = 0;
+update avm_history_links set descendent = (select max(id) from avm_nodes) where descendent = 0;
+
+update avm_merge_links set mfrom = (select max(id) from avm_nodes) where mfrom = 0;
+update avm_merge_links set mto = (select max(id) from avm_nodes) where mto = 0;
+
+update avm_node_properties set node_id = (select max(id) from avm_nodes) where node_id = 0;
+
+update avm_stores set current_root_id = (select max(id) from avm_nodes) where current_root_id = 0;
+
+update avm_version_roots set root_id = (select max(id) from avm_nodes) where root_id = 0;
+
+delete from avm_nodes where id = 0;
+
+alter table avm_nodes modify column id bigint not null auto_increment;
+
+--
+-- Record script finish
+--
+DELETE FROM alf_applied_patch WHERE id = 'patch.db-V3.2-Remove-AVM-Issuer';
+INSERT INTO alf_applied_patch
+ (id, description, fixes_from_schema, fixes_to_schema, applied_to_schema, target_schema, applied_on_date, applied_to_server, was_executed, succeeded, report)
+ VALUES
+ (
+ 'patch.db-V3.2-Remove-AVM-Issuer', 'Manually executed script upgrade V3.2 to remove AVM Issuer',
+ 0, 2007, -1, 2008, null, 'UNKOWN', 1, 1, 'Script completed'
+ );
diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml
index 7f42569e90..162329b4d6 100644
--- a/config/alfresco/patch/patch-services-context.xml
+++ b/config/alfresco/patch/patch-services-context.xml
@@ -1759,5 +1759,15 @@
+
+ patch.db-V3.2-Remove-AVM-Issuer
+ patch.schemaUpgradeScript.description
+ 0
+ 2007
+ 2008
+
+ classpath:alfresco/dbscripts/upgrade/3.2/${db.script.dialect}/remove-AVM-issuer.sql
+
+
diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties
index e9f9595b33..cbb62f2360 100644
--- a/config/alfresco/version.properties
+++ b/config/alfresco/version.properties
@@ -19,4 +19,4 @@ version.build=@build-number@
# Schema number
-version.schema=2007
+version.schema=2008
diff --git a/source/java/org/alfresco/repo/avm/AVMDAOs.java b/source/java/org/alfresco/repo/avm/AVMDAOs.java
index d42812fef9..2a08d5b2a8 100644
--- a/source/java/org/alfresco/repo/avm/AVMDAOs.java
+++ b/source/java/org/alfresco/repo/avm/AVMDAOs.java
@@ -1,6 +1,26 @@
-/**
- *
- */
+/*
+ * Copyright (C) 2005-2009 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.attributes.AttributeDAO;
@@ -34,11 +54,6 @@ public class AVMDAOs
return fgInstance;
}
- /**
- * The IssuerDAO.
- */
- public IssuerDAO fIssuerDAO;
-
/**
* The AVMNodeDAO.
*/
@@ -141,14 +156,6 @@ public class AVMDAOs
{
fVersionRootDAO = versionRootDAO;
}
-
- /**
- * @param issuerDAO the fIssuerDAO to set
- */
- public void setIssuerDAO(IssuerDAO issuerDAO)
- {
- fIssuerDAO = issuerDAO;
- }
public void setAvmStorePropertyDAO(AVMStorePropertyDAO avmStorePropertyDAO)
{
diff --git a/source/java/org/alfresco/repo/avm/AVMNodeImpl.java b/source/java/org/alfresco/repo/avm/AVMNodeImpl.java
index 45516440f9..dfdc0a11c1 100644
--- a/source/java/org/alfresco/repo/avm/AVMNodeImpl.java
+++ b/source/java/org/alfresco/repo/avm/AVMNodeImpl.java
@@ -1,543 +1,540 @@
-/*
- * 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.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 = fgLogger.isDebugEnabled();
-
- /**
- * The Object ID.
- */
- private long fID;
-
- /**
- * The Version ID.
- */
- private int fVersionID;
-
- /**
- * The basic attributes of this. Owner, creator, mod time, etc.
- */
- private BasicAttributes fBasicAttributes;
-
- /**
- * The version number (for concurrency control).
- */
- private long fVers;
-
- /**
- * The rootness of this node.
- */
- private boolean fIsRoot;
-
- /**
- * The ACL on this node.
- */
- private DbAccessControlList fACL;
-
- /**
- * The Store that we're new in.
- */
- private AVMStore fStoreNew;
-
- /**
- * The GUID for this version.
- */
- private String fGUID;
-
- /**
- * The Aspects that belong to this node.
- */
- private Set fAspects;
-
- private Map fProperties;
-
- /**
- * Default constructor.
- */
- protected AVMNodeImpl()
- {
- 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 copyCreationAndOwnerBasicAttributes(AVMNode other)
- {
- fBasicAttributes.setCreateDate(other.getBasicAttributes().getCreateDate());
- fBasicAttributes.setCreator(other.getBasicAttributes().getCreator());
- fBasicAttributes.setOwner(other.getBasicAttributes().getOwner());
- }
-
- protected void copyACLs(AVMNode other, Long parentAcl, ACLCopyMode mode)
- {
- DbAccessControlList acl = other.getAcl();
- if (acl != null)
- {
- setAcl(acl.getCopy(parentAcl, mode));
- }
- }
-
- /**
- * Copy out metadata from another node.
- * @param other The other node.
- */
- public void copyMetaDataFrom(AVMNode other, Long parentAcl)
- {
- copyAspects(other);
- copyACLs(other, parentAcl, ACLCopyMode.COPY);
- copyProperties(other);
- copyCreationAndOwnerBasicAttributes(other);
- }
-
- /**
- * Set a property on a node. Overwrite it if it exists.
- * @param name The name of the property.
- * @param value The value to set.
- */
- public void setProperty(Long qnameEntityId, PropertyValue value)
- {
- if (DEBUG)
- {
- checkReadOnly();
- }
- fProperties.put(qnameEntityId, 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(Long qnameEntityId)
- {
- return fProperties.get(qnameEntityId);
- }
-
- /**
- * {@inheritDoc}
- */
- public Map getProperties()
- {
- return fProperties;
- }
-
- /**
- * Delete a property from this node.
- * @param name The name of the property.
- */
- public void deleteProperty(Long qnameEntityId)
- {
- if (DEBUG)
- {
- checkReadOnly();
- }
- fProperties.remove(qnameEntityId);
- }
-
- /**
- * 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;
- }
-}
+/*
+ * Copyright (C) 2005-2009 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.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 = fgLogger.isDebugEnabled();
+
+ /**
+ * The Object ID.
+ */
+ private long fID;
+
+ /**
+ * The Version ID.
+ */
+ private int fVersionID;
+
+ /**
+ * The basic attributes of this. Owner, creator, mod time, etc.
+ */
+ private BasicAttributes fBasicAttributes;
+
+ /**
+ * The version number (for concurrency control).
+ */
+ private long fVers;
+
+ /**
+ * The rootness of this node.
+ */
+ private boolean fIsRoot;
+
+ /**
+ * The ACL on this node.
+ */
+ private DbAccessControlList fACL;
+
+ /**
+ * The Store that we're new in.
+ */
+ private AVMStore fStoreNew;
+
+ /**
+ * The GUID for this version.
+ */
+ private String fGUID;
+
+ /**
+ * The Aspects that belong to this node.
+ */
+ private Set fAspects;
+
+ private Map fProperties;
+
+ /**
+ * Default constructor.
+ */
+ protected AVMNodeImpl()
+ {
+ fAspects = new HashSet();
+ fProperties = new HashMap();
+ }
+
+ /**
+ * Constructor used when creating a new concrete subclass instance.
+ * @param store The AVMStore that owns this.
+ */
+ protected AVMNodeImpl(AVMStore store)
+ {
+ fAspects = new HashSet();
+ fProperties = new HashMap();
+ 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 copyCreationAndOwnerBasicAttributes(AVMNode other)
+ {
+ fBasicAttributes.setCreateDate(other.getBasicAttributes().getCreateDate());
+ fBasicAttributes.setCreator(other.getBasicAttributes().getCreator());
+ fBasicAttributes.setOwner(other.getBasicAttributes().getOwner());
+ }
+
+ protected void copyACLs(AVMNode other, Long parentAcl, ACLCopyMode mode)
+ {
+ DbAccessControlList acl = other.getAcl();
+ if (acl != null)
+ {
+ setAcl(acl.getCopy(parentAcl, mode));
+ }
+ }
+
+ /**
+ * Copy out metadata from another node.
+ * @param other The other node.
+ */
+ public void copyMetaDataFrom(AVMNode other, Long parentAcl)
+ {
+ copyAspects(other);
+ copyACLs(other, parentAcl, ACLCopyMode.COPY);
+ copyProperties(other);
+ copyCreationAndOwnerBasicAttributes(other);
+ }
+
+ /**
+ * Set a property on a node. Overwrite it if it exists.
+ * @param name The name of the property.
+ * @param value The value to set.
+ */
+ public void setProperty(Long qnameEntityId, PropertyValue value)
+ {
+ if (DEBUG)
+ {
+ checkReadOnly();
+ }
+ fProperties.put(qnameEntityId, 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(Long qnameEntityId)
+ {
+ return fProperties.get(qnameEntityId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Map getProperties()
+ {
+ return fProperties;
+ }
+
+ /**
+ * Delete a property from this node.
+ * @param name The name of the property.
+ */
+ public void deleteProperty(Long qnameEntityId)
+ {
+ if (DEBUG)
+ {
+ checkReadOnly();
+ }
+ fProperties.remove(qnameEntityId);
+ }
+
+ /**
+ * 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 705a048eba..6d9b0708a7 100644
--- a/source/java/org/alfresco/repo/avm/AVMRepository.java
+++ b/source/java/org/alfresco/repo/avm/AVMRepository.java
@@ -1,3371 +1,3320 @@
-/*
- * 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.domain.QNameDAO;
-import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor.StoreType;
-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 QNameDAO qnameDAO;
-
- private AVMStoreDAO fAVMStoreDAO;
-
- private AVMNodeDAO fAVMNodeDAO;
-
- private VersionRootDAO fVersionRootDAO;
-
- private VersionLayeredNodeEntryDAO fVersionLayeredNodeEntryDAO;
-
- private AVMStorePropertyDAO fAVMStorePropertyDAO;
-
- private ChildEntryDAO fChildEntryDAO;
-
- private PermissionService fPermissionService;
-
- private DictionaryService fDictionaryService;
-
- // A bunch of TransactionListeners that do work for this.
-
- /**
- * One for create store.
- */
- private CreateStoreTxnListener fCreateStoreTxnListener;
-
- /**
- * One for purge store.
- */
- private PurgeStoreTxnListener fPurgeStoreTxnListener;
-
- /**
- * One for create version.
- */
- private CreateVersionTxnListener fCreateVersionTxnListener;
-
- /**
- * One for purge version.
- */
- private PurgeVersionTxnListener fPurgeVersionTxnListener;
-
- /**
- * Create a new one.
- */
- public AVMRepository()
- {
- fLookupCount = new ThreadLocal();
- fgInstance = this;
- }
-
- /**
- * Set the 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 setQnameDAO(QNameDAO qnameDAO)
- {
- this.qnameDAO = qnameDAO;
- }
-
- public void setAvmStoreDAO(AVMStoreDAO dao)
- {
- fAVMStoreDAO = dao;
- }
-
- public void setAvmNodeDAO(AVMNodeDAO dao)
- {
- fAVMNodeDAO = dao;
- }
-
- public void setVersionRootDAO(VersionRootDAO dao)
- {
- fVersionRootDAO = dao;
- }
-
- public void setVersionLayeredNodeEntryDAO(VersionLayeredNodeEntryDAO dao)
- {
- fVersionLayeredNodeEntryDAO = dao;
- }
-
- public void setAvmStorePropertyDAO(AVMStorePropertyDAO dao)
- {
- fAVMStorePropertyDAO = dao;
- }
-
- public void setChildEntryDAO(ChildEntryDAO dao)
- {
- fChildEntryDAO = dao;
- }
-
- public void setPermissionService(PermissionService service)
- {
- fPermissionService = service;
- }
-
- public void setDictionaryService(DictionaryService service)
- {
- fDictionaryService = service;
- }
-
- /**
- * Create a file.
- *
- * @param path
- * The path to the containing directory.
- * @param name
- * The name for the new file.
- */
- public OutputStream createFile(String path, String name)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- fLookupCache.onWrite(pathParts[0]);
- OutputStream out = store.createFile(pathParts[1], name);
- return out;
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Create a file with the given File as content.
- *
- * @param path
- * The path to the containing directory.
- * @param name
- * The name to give the file.
- * @param data
- * The file contents.
- */
- public void createFile(String path, String name, File data, List aspects, Map properties)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- fLookupCache.onWrite(pathParts[0]);
- store.createFile(pathParts[1], name, data, aspects, properties);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Create a new directory.
- *
- * @param path
- * The path to the containing directory.
- * @param name
- * The name to give the directory.
- */
- public void createDirectory(String path, String name, List aspects, Map properties)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- fLookupCache.onWrite(pathParts[0]);
- store.createDirectory(pathParts[1], name, aspects, properties);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Create a new directory. This assumes that the parent is already copied and therefore should only be used with
- * great care.
- *
- * @param parent
- * The parent node.
- * @param name
- * The name of the new directory.
- * @return A descriptor for the newly created directory.
- */
- public AVMNodeDescriptor createDirectory(AVMNodeDescriptor parent, String name)
- {
- AVMNode node = fAVMNodeDAO.getByID(parent.getId());
- if (node == null)
- {
- throw new AVMNotFoundException(parent.getId() + " not found.");
- }
- if (!(node instanceof DirectoryNode))
- {
- throw new AVMWrongTypeException("Not a directory.");
- }
- if (!can(null, node, PermissionService.CREATE_CHILDREN, true))
- {
- throw new AccessDeniedException("Not allowed to write in: " + parent);
- }
- // We need the store to do anything so...
- String[] pathParts = SplitPath(parent.getPath());
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- DirectoryNode dir = (DirectoryNode) node;
- DirectoryNode child = null;
- Long parentAcl = dir.getAcl() == null ? null : dir.getAcl().getId();
- if (dir instanceof LayeredDirectoryNode)
- {
- 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(dstRepo, dirNode, PermissionService.ADD_CHILDREN, dPath.getDirectlyContained()))
- {
- throw new AccessDeniedException("Not permitted to add children: " + dstPath);
- }
- AVMNode srcNode = sPath.getCurrentNode();
- AVMNode dstNode = null;
- // We do different things depending on what kind of thing we're
- // branching from. I'd be considerably happier if we disallowed
- // certain scenarios, but Jon won't let me :P (bhp).
-
- Long inheritAcl = srcNode.getAcl() == null ? null : srcNode.getAcl().getId();
-
- if (srcNode.getType() == AVMNodeType.PLAIN_DIRECTORY)
- {
- dstNode = new PlainDirectoryNodeImpl((PlainDirectoryNode) srcNode, dstRepo, inheritAcl, ACLCopyMode.INHERIT);
- }
- else if (srcNode.getType() == AVMNodeType.LAYERED_DIRECTORY)
- {
- dstNode = new LayeredDirectoryNodeImpl((LayeredDirectoryNode) srcNode, dstRepo, sPath, false, inheritAcl, ACLCopyMode.INHERIT);
- ((LayeredDirectoryNode) dstNode).setLayerID(issueLayerID());
- }
- else if (srcNode.getType() == AVMNodeType.LAYERED_FILE)
- {
- dstNode = new LayeredFileNodeImpl((LayeredFileNode) srcNode, dstRepo, inheritAcl, ACLCopyMode.INHERIT);
- }
- else
- // This is a plain file.
- {
- dstNode = new PlainFileNodeImpl((PlainFileNode) srcNode, dstRepo, inheritAcl, ACLCopyMode.INHERIT);
- }
- // dstNode.setVersionID(dstRepo.getNextVersionID());
- dstNode.setAncestor(srcNode);
- dirNode.putChild(name, dstNode);
- // dirNode.updateModTime();
- String beginingPath = 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();
-
- Pair temp = srcDir.lookupChild(sPath, srcName, false);
- srcNode = (temp == null) ? null : temp.getFirst();
- if (srcNode == null)
- {
- throw new AVMNotFoundException("Not found: " + srcName);
- }
- if (!can(srcRepo, srcNode, PermissionService.DELETE_NODE, false))
- {
- throw new AccessDeniedException("Not allowed to delete target: " + srcPath);
- }
-
- fLookupCache.onDelete(pathParts[0]);
- }
- finally
- {
- fLookupCount.set(null);
- }
- fLookupCount.set(1);
- try
- {
- pathParts = SplitPath(dstPath);
- AVMStore dstRepo = getAVMStoreByName(pathParts[0]);
- if (dstRepo == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true);
- if (dPath == null)
- {
- throw new AVMNotFoundException("Path not found.");
- }
- DirectoryNode dstDir = (DirectoryNode) dPath.getCurrentNode();
- if (!can(dstRepo, dstDir, PermissionService.ADD_CHILDREN, dPath.getDirectlyContained()))
- {
- throw new AccessDeniedException("Not allowed to write: " + dstPath);
- }
- Pair temp = dstDir.lookupChild(dPath, dstName, true);
- AVMNode child = (temp == null) ? null : temp.getFirst();
- 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)
- {
- try
- {
- fAVMNodeDAO.noCache();
- AlfrescoTransactionSupport.bindListener(fCreateVersionTxnListener);
- AVMStore store = getAVMStoreByName(storeName);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- Map result = store.createSnapshot(tag, description, new HashMap());
- for (Map.Entry entry : result.entrySet())
- {
- fLookupCache.onSnapshot(entry.getKey());
- fCreateVersionTxnListener.versionCreated(entry.getKey(), entry.getValue());
- }
- return result;
- }
- finally
- {
- fAVMNodeDAO.yesCache();
- }
- }
-
- /**
- * Remove a node and everything underneath it.
- *
- * @param path
- * The path to the containing directory.
- * @param name
- * The name of the node to remove.
- */
- public void remove(String path, String name)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- fLookupCache.onDelete(pathParts[0]);
- store.removeNode(pathParts[1], name);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Get rid of all content that lives only in the given AVMStore. Also removes the AVMStore.
- *
- * @param name
- * The name of the AVMStore to purge.
- */
- @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(store, root, PermissionService.DELETE_CHILDREN, true))
- {
- 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(null, node, PermissionService.READ_CONTENT, false))
- {
- throw new AccessDeniedException("Not allowed to read content: " + desc);
- }
- FileNode file = (FileNode) node;
- ContentData data = file.getContentData(null);
- if (data == null)
- {
- throw new AVMException(desc + " has no content.");
- }
- ContentReader reader = fContentStore.getReader(data.getContentUrl());
- return reader.getContentInputStream();
- }
-
- /**
- * Get a listing of a directory.
- *
- * @param version
- * The version to look under.
- * @param path
- * The path to the directory.
- * @param includeDeleted
- * Whether to see DeletedNodes.
- * @return A List of FolderEntries.
- */
- public SortedMap getListing(int version, String path, boolean includeDeleted)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- return store.getListing(version, pathParts[1], includeDeleted);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Get the list of nodes directly contained in a directory.
- *
- * @param version
- * The version to look under.
- * @param path
- * The path to the directory to list.
- * @return A Map of names to descriptors.
- */
- public SortedMap getListingDirect(int version, String path, boolean includeDeleted)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- return store.getListingDirect(version, pathParts[1], includeDeleted);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Get the list of nodes directly contained in a directory.
- *
- * @param dir
- * The descriptor to the directory node.
- * @param includeDeleted
- * Whether to include deleted children.
- * @return A Map of names to descriptors.
- */
- public SortedMap getListingDirect(AVMNodeDescriptor dir, boolean includeDeleted)
- {
- AVMNode node = fAVMNodeDAO.getByID(dir.getId());
- if (node == null)
- {
- throw new AVMBadArgumentException("Invalid Node.");
- }
- if (!can(null, node, PermissionService.READ_CHILDREN, false))
- {
- throw new AccessDeniedException("Not allowed to read children: " + dir);
- }
- if (node.getType() == AVMNodeType.PLAIN_DIRECTORY)
- {
- return getListing(dir, includeDeleted);
- }
- if (node.getType() != AVMNodeType.LAYERED_DIRECTORY)
- {
- throw new AVMWrongTypeException("Not a directory.");
- }
- LayeredDirectoryNode dirNode = (LayeredDirectoryNode) node;
- return dirNode.getListingDirect(dir, includeDeleted);
- }
-
- /**
- * Get a directory listing from a directory node descriptor.
- *
- * @param dir
- * The directory node descriptor.
- * @return A SortedMap listing.
- */
- public SortedMap getListing(AVMNodeDescriptor dir, boolean includeDeleted)
- {
- fLookupCount.set(1);
- try
- {
- AVMNode node = fAVMNodeDAO.getByID(dir.getId());
- if (node == null)
- {
- throw new AVMBadArgumentException("Invalid Node.");
- }
- if (node.getType() != AVMNodeType.LAYERED_DIRECTORY && node.getType() != AVMNodeType.PLAIN_DIRECTORY)
- {
- throw new AVMWrongTypeException("Not a directory.");
- }
- if (!can(null, node, PermissionService.READ_CHILDREN, false))
- {
- throw new AccessDeniedException("Not allowed to read children: " + dir);
- }
- DirectoryNode dirNode = (DirectoryNode) node;
- SortedMap listing = dirNode.getListing(dir, includeDeleted);
- return listing;
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Get a directory listing from a directory node descriptor fo children that match the given pattern
- *
- * @param dir
- * The directory node descriptor.
- * @return A SortedMap listing.
- */
- public SortedMap getListing(AVMNodeDescriptor dir, String childNamePattern, boolean includeDeleted)
- {
- fLookupCount.set(1);
- try
- {
- AVMNode node = fAVMNodeDAO.getByID(dir.getId());
- if (node == null)
- {
- throw new AVMBadArgumentException("Invalid Node.");
- }
- if (node.getType() != AVMNodeType.LAYERED_DIRECTORY && node.getType() != AVMNodeType.PLAIN_DIRECTORY)
- {
- throw new AVMWrongTypeException("Not a directory.");
- }
- if (!can(null, node, PermissionService.READ_CHILDREN, false))
- {
- throw new AccessDeniedException("Not allowed to read children: " + dir);
- }
- DirectoryNode dirNode = (DirectoryNode) node;
- SortedMap listing = dirNode.getListing(dir, childNamePattern, includeDeleted);
- return listing;
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
-
- /**
- * Get the names of deleted nodes in a directory.
- *
- * @param version
- * The version to look under.
- * @param path
- * The path to the directory.
- * @return A List of names.
- */
- public List getDeleted(int version, String path)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- return store.getDeleted(version, pathParts[1]);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Get descriptors of all AVMStores.
- *
- * @return A list of all descriptors.
- */
- @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(null, dirNode, PermissionService.READ_CHILDREN, false))
- {
- throw new AccessDeniedException("Not allowed to read children: " + dir);
- }
- return dirNode.lookupChild(dir, name, includeDeleted);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Get all the paths to a particular node.
- *
- * @param desc
- * The node descriptor.
- * @return The list of version, paths.
- */
- public List> getPaths(AVMNodeDescriptor desc)
- {
- AVMNode node = fAVMNodeDAO.getByID(desc.getId());
- if (node == null)
- {
- throw new AVMNotFoundException("Not found: " + desc);
- }
- List> paths = new ArrayList>();
- List components = new ArrayList();
- recursiveGetPaths(node, components, paths);
- return paths;
- }
-
- /**
- * Get a single valid path for a node.
- *
- * @param desc
- * The node descriptor.
- * @return A version, path
- */
- public Pair getAPath(AVMNodeDescriptor desc)
- {
- AVMNode node = fAVMNodeDAO.getByID(desc.getId());
- if (node == null)
- {
- throw new AVMNotFoundException("Could not find node: " + desc);
- }
- if (fgLogger.isDebugEnabled())
- {
- fgLogger.debug("Getting A Path for: " + desc);
- }
- List components = new ArrayList();
- return recursiveGetAPath(node, components);
- }
-
- /**
- * Get all paths for a node reachable by HEAD.
- *
- * @param desc
- * The node descriptor.
- * @return A List of all the version, path Pairs that match.
- */
- public List> getHeadPaths(AVMNodeDescriptor desc)
- {
- AVMNode node = fAVMNodeDAO.getByID(desc.getId());
- if (node == null)
- {
- throw new AVMNotFoundException("Not found: " + desc.getPath());
- }
- List> paths = new ArrayList>();
- List components = new ArrayList();
- recursiveGetHeadPaths(node, components, paths);
- return paths;
- }
-
- /**
- * Gets all the pass from to the given node starting from the give version root.
- *
- * @param version
- * The version root.
- * @param node
- * The node to get the paths of.
- * @return A list of all paths in the given version to the node.
- */
- public List getVersionPaths(VersionRoot version, AVMNode node)
- {
- List paths = new ArrayList();
- List components = new ArrayList();
- recursiveGetVersionPaths(node, components, paths, version.getRoot(), version.getAvmStore().getName());
- return paths;
- }
-
- /**
- * Helper to get all version paths.
- *
- * @param node
- * The current node we are examining.
- * @param components
- * The current path components.
- * @param paths
- * The list to contain found paths.
- * @param root
- * The root node of the version.
- * @param storeName
- * The name of the store.
- */
- private void recursiveGetVersionPaths(AVMNode node, List components, List paths, DirectoryNode root, String storeName)
- {
- if (!can(null, node, PermissionService.READ_CHILDREN, false))
- {
- return;
- }
- if (node.equals(root))
- {
- paths.add(this.makePath(components, storeName));
- return;
- }
- List entries = fChildEntryDAO.getByChild(node);
- for (ChildEntry entry : entries)
- {
- String name = entry.getKey().getName();
- components.add(name);
- AVMNode parent = entry.getKey().getParent();
- recursiveGetVersionPaths(parent, components, paths, root, storeName);
- components.remove(components.size() - 1);
- }
- }
-
- /**
- * Get all paths in a particular store in the head version for a particular node.
- *
- * @param desc
- * The node descriptor.
- * @param store
- * The name of the store.
- * @return All matching paths.
- */
- public List> getPathsInStoreHead(AVMNodeDescriptor desc, String store)
- {
- AVMStore st = getAVMStoreByName(store);
- if (st == null)
- {
- throw new AVMNotFoundException("Store not found: " + store);
- }
- AVMNode node = fAVMNodeDAO.getByID(desc.getId());
- if (node == null)
- {
- throw new AVMNotFoundException("Not found: " + desc);
- }
- List> paths = new ArrayList>();
- List components = new ArrayList();
- recursiveGetPathsInStoreHead(node, components, paths, st.getRoot(), store);
- return paths;
- }
-
- /**
- * Do the actual work.
- *
- * @param node
- * The current node.
- * @param components
- * The currently accumulated path components.
- * @param paths
- * The list to put full paths in.
- */
- private void recursiveGetPaths(AVMNode node, List components, List> paths)
- {
- if (!can(null, node, PermissionService.READ_CHILDREN, false))
- {
- return;
- }
- if (node.getIsRoot())
- {
- AVMStore store = fAVMStoreDAO.getByRoot(node);
- if (store != null)
- {
- addPath(components, -1, store.getName(), paths);
- }
- VersionRoot vr = fVersionRootDAO.getByRoot(node);
- if (vr != null)
- {
- addPath(components, vr.getVersionID(), vr.getAvmStore().getName(), paths);
- }
- return;
- }
- List entries = fChildEntryDAO.getByChild(node);
- for (ChildEntry entry : entries)
- {
- String name = entry.getKey().getName();
- components.add(name);
- AVMNode parent = entry.getKey().getParent();
- recursiveGetPaths(parent, components, paths);
- components.remove(components.size() - 1);
- }
- }
-
- /**
- * Do the work of getting one path for a node.
- *
- * @param node
- * The node to get the path of.
- * @param components
- * The storage for path components.
- * @return A path or null.
- */
- private Pair recursiveGetAPath(AVMNode node, List components)
- {
- if (!can(null, node, PermissionService.READ_CHILDREN, false))
- {
- return null;
- }
- if (node.getIsRoot())
- {
- AVMStore store = fAVMStoreDAO.getByRoot(node);
- if (store != null)
- {
- if (fgLogger.isDebugEnabled())
- {
- fgLogger.debug("Found path in HEAD of: " + store.getName());
- }
- return new Pair(-1, makePath(components, store.getName()));
- }
- VersionRoot vr = fVersionRootDAO.getByRoot(node);
- if (vr != null)
- {
- if (fgLogger.isDebugEnabled())
- {
- fgLogger.debug("Found path in version " + vr.getVersionID() + " in: " + vr.getAvmStore().getName());
- }
- return new Pair(vr.getVersionID(), makePath(components, vr.getAvmStore().getName()));
- }
- return null;
- }
- List entries = fChildEntryDAO.getByChild(node);
- for (ChildEntry entry : entries)
- {
- String name = entry.getKey().getName();
- if (fgLogger.isDebugEnabled())
- {
- fgLogger.debug("Found component: " + name);
- }
- components.add(name);
- Pair path = recursiveGetAPath(AVMNodeUnwrapper.Unwrap(entry.getKey().getParent()), components);
- if (path != null)
- {
- return path;
- }
- components.remove(components.size() - 1);
- }
- return null;
- }
-
- /**
- * Do the actual work.
- *
- * @param node
- * The current node.
- * @param components
- * The currently accumulated path components.
- * @param paths
- * The list to put full paths in.
- */
- private void recursiveGetHeadPaths(AVMNode node, List components, List> paths)
- {
- if (!can(null, node, PermissionService.READ_CHILDREN, false))
- {
- return;
- }
- if (node.getIsRoot())
- {
- AVMStore store = fAVMStoreDAO.getByRoot(node);
- if (store != null)
- {
- addPath(components, -1, store.getName(), paths);
- return;
- }
- return;
- }
- List entries = fChildEntryDAO.getByChild(node);
- for (ChildEntry entry : entries)
- {
- String name = entry.getKey().getName();
- components.add(name);
- AVMNode parent = entry.getKey().getParent();
- recursiveGetHeadPaths(parent, components, paths);
- components.remove(components.size() - 1);
- }
- }
-
- /**
- * Do the actual work.
- *
- * @param node
- * The current node.
- * @param components
- * The currently accumulated path components.
- * @param paths
- * The list to put full paths in.
- */
- private void recursiveGetPathsInStoreHead(AVMNode node, List components, List> paths, DirectoryNode root, String storeName)
- {
- if (!can(null, node, PermissionService.READ_CHILDREN, false))
- {
- return;
- }
- if (node.equals(root))
- {
- addPath(components, -1, storeName, paths);
- return;
- }
- List entries = fChildEntryDAO.getByChild(node);
- for (ChildEntry entry : entries)
- {
- String name = entry.getKey().getName();
- components.add(name);
- AVMNode parent = entry.getKey().getParent();
- recursiveGetHeadPaths(parent, components, paths);
- components.remove(components.size() - 1);
- }
- }
-
- /**
- * Add a path to the list.
- *
- * @param components
- * The path name components.
- * @param version
- * The version id.
- * @param storeName
- * The name of the
- * @param paths
- * The List to add to.
- */
- private void addPath(List components, int version, String storeName, List> paths)
- {
- paths.add(new Pair(version, makePath(components, storeName)));
- }
-
- /**
- * Alternate version.
- *
- * @param components
- * @param storeName
- * @param paths
- */
- private void addPath(List components, String storeName, List paths)
- {
- paths.add(makePath(components, storeName));
- }
-
- /**
- * Helper for generating paths.
- *
- * @param components
- * The path components.
- * @param storeName
- * The store that the path is in.
- * @return The path.
- */
- private String makePath(List components, String storeName)
- {
- StringBuilder pathBuilder = new StringBuilder();
- pathBuilder.append(storeName);
- pathBuilder.append(":");
- if (components.size() == 0)
- {
- pathBuilder.append("/");
- return pathBuilder.toString();
- }
- for (int i = components.size() - 1; i >= 0; i--)
- {
- pathBuilder.append("/");
- pathBuilder.append(components.get(i));
- }
- return pathBuilder.toString();
- }
-
- /**
- * Get information about layering of a path.
- *
- * @param version
- * The version to look under.
- * @param path
- * The full avm path.
- * @return A LayeringDescriptor.
- */
- public LayeringDescriptor getLayeringInfo(int version, String path)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- Lookup lookup = store.lookup(version, pathParts[1], false, true);
- if (lookup == null)
- {
- throw new AVMNotFoundException("Path not found.");
- }
- if (!can(store, lookup.getCurrentNode(), PermissionService.READ_PROPERTIES, false))
- {
- throw new AccessDeniedException("Not allowed to read properties: " + path);
- }
- return new LayeringDescriptor(!lookup.getDirectlyContained(), lookup.getAVMStore().getDescriptor(), lookup.getFinalStore().getDescriptor());
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Lookup a directory specifically.
- *
- * @param version
- * The version to look under.
- * @param path
- * The path to lookup.
- * @return A lookup object.
- */
- public Lookup lookupDirectory(int version, String path)
- {
- Integer count = fLookupCount.get();
- try
- {
- if (count == null)
- {
- fLookupCount.set(1);
- }
- fLookupCount.set(fLookupCount.get() + 1);
- if (fLookupCount.get() > 50)
- {
- throw new AVMCycleException("Cycle in lookup.");
- }
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- return null;
- }
- return store.lookupDirectory(version, pathParts[1], false);
- }
- finally
- {
- if (count == null)
- {
- fLookupCount.set(null);
- }
- }
- }
-
- /**
- * Utility to split a path, foo:bar/baz into its repository and path parts.
- *
- * @param path
- * The fully qualified path.
- * @return The repository name and the repository path.
- */
- private String[] SplitPath(String path)
- {
- 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(null, node, PermissionService.READ_PROPERTIES, false))
- {
- throw new AccessDeniedException("Not allowed to read properties: " + desc);
- }
- if (count < 0)
- {
- count = Integer.MAX_VALUE;
- }
- List history = new ArrayList();
- for (int i = 0; i < count; i++)
- {
- node = node.getAncestor();
- if (node == null)
- {
- break;
- }
- if (!can(null, node, PermissionService.READ_PROPERTIES, false))
- {
- 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.
- */
- @SuppressWarnings("unchecked")
- 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 matchesMap = new HashMap();
- for (AVMStoreProperty prop : matches)
- {
- matchesMap.put(prop.getQnameId(), prop.getValue());
- }
- Map propertyMap = (Map) qnameDAO.convertIdMapToQNameMap(matchesMap);
- return propertyMap;
- }
-
- /**
- * 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();
- QName propQName = qnameDAO.getQName(prop.getQnameId()).getSecond();
- Map pairs = null;
- if ((pairs = results.get(storeName)) == null)
- {
- pairs = new HashMap();
- results.put(storeName, pairs);
- }
- pairs.put(propQName, 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(null, lNode, PermissionService.READ_PROPERTIES, false))
- {
- throw new AccessDeniedException("Not allowed to read properties: " + left);
- }
- if (!can(null, rNode, PermissionService.READ_PROPERTIES, false))
- {
- throw new AccessDeniedException("Not allowed to read properties: " + right);
- }
- // TODO Short changing the permissions checking here. I'm not sure
- // if that's OK.
- List leftHistory = new ArrayList();
- List rightHistory = new ArrayList();
- while (lNode != null || rNode != null)
- {
- boolean checkRight = false;
- if (lNode != null)
- {
- leftHistory.add(lNode);
- checkRight = true;
- lNode = lNode.getAncestor();
- }
- boolean checkLeft = false;
- if (rNode != null)
- {
- rightHistory.add(rNode);
- checkLeft = true;
- rNode = rNode.getAncestor();
- }
- if (checkRight)
- {
- AVMNode check = leftHistory.get(leftHistory.size() - 1);
- for (AVMNode node : rightHistory)
- {
- if (node.equals(check))
- {
- return node.getDescriptor("", "", "", -1);
- }
- }
- }
- if (checkLeft)
- {
- AVMNode check = rightHistory.get(rightHistory.size() - 1);
- for (AVMNode node : leftHistory)
- {
- if (node.equals(check))
- {
- return node.getDescriptor("", "", "", -1);
- }
- }
- }
- }
- return null;
- }
-
- /**
- * Get the ContentData for a file.
- *
- * @param version
- * The version to look under.
- * @param path
- * The path to the file.
- * @return The ContentData for the file.
- */
- public ContentData getContentDataForRead(int version, String path)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- return store.getContentDataForRead(version, pathParts[1]);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Get the ContentData for a file for writing.
- *
- * @param path
- * The path to the file.
- * @return The ContentData object.
- */
- public ContentData getContentDataForWrite(String path)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- fLookupCache.onWrite(pathParts[0]);
- ContentData result = store.getContentDataForWrite(pathParts[1]);
- return result;
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Set the ContentData on a file.
- *
- * @param path
- * The path to the file.
- * @param data
- * The content data to set.
- */
- public void setContentData(String path, ContentData data)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- fLookupCache.onWrite(pathParts[0]);
- store.setContentData(pathParts[1], data);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Get the single instance of AVMRepository.
- *
- * @return The single instance.
- */
- public static AVMRepository GetInstance()
- {
- return fgInstance;
- }
-
- public void setMetaDataFrom(String path, AVMNodeDescriptor from)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found: " + pathParts[0]);
- }
- AVMNode fromNode = fAVMNodeDAO.getByID(from.getId());
- if (fromNode == null)
- {
- throw new AVMNotFoundException("Node not found: " + from.getPath());
- }
- fLookupCache.onWrite(pathParts[0]);
- store.setMetaDataFrom(pathParts[1], fromNode);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Add an aspect to an AVM Node.
- *
- * @param path
- * The path to the node.
- * @param aspectName
- * The name of the aspect.
- */
- public void addAspect(String path, QName aspectName)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- fLookupCache.onWrite(pathParts[0]);
- store.addAspect(pathParts[1], aspectName);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Get all the aspects on an AVM node.
- *
- * @param version
- * The version to look under.
- * @param path
- * The path to the node.
- * @return A List of the QNames of the Aspects.
- */
- public Set getAspects(int version, String path)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- return store.getAspects(version, pathParts[1]);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Remove an aspect and all associated properties from a node.
- *
- * @param path
- * The path to the node.
- * @param aspectName
- * The name of the aspect.
- */
- public void removeAspect(String path, QName aspectName)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- fLookupCache.onWrite(pathParts[0]);
- store.removeAspect(pathParts[1], aspectName);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Does a node have a particular aspect.
- *
- * @param version
- * The version to look under.
- * @param path
- * The path to the node.
- * @param aspectName
- * The name of the aspect.
- * @return Whether the node has the aspect.
- */
- public boolean hasAspect(int version, String path, QName aspectName)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- return store.hasAspect(version, pathParts[1], aspectName);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Set the ACL on a node.
- *
- * @param path
- * The path to the node.
- * @param acl
- * The ACL to set.
- */
- public void setACL(String path, DbAccessControlList acl)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- fLookupCache.onWrite(pathParts[0]);
- store.setACL(pathParts[1], acl);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Get the ACL on a node.
- *
- * @param version
- * The version to look under.
- * @param path
- * The path to the node.
- * @return The ACL.
- */
- public DbAccessControlList getACL(int version, String path)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- return store.getACL(version, pathParts[1]);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Link a node into a directory, directly.
- *
- * @param parentPath
- * The path to the parent.
- * @param name
- * The name to give the node.
- * @param toLink
- * The node to link.
- */
- public void link(String parentPath, String name, AVMNodeDescriptor toLink)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(parentPath);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- store.link(pathParts[1], name, toLink);
- fLookupCache.onWrite(pathParts[0]);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Update a link, directly.
- *
- * @param parentPath
- * The path to the parent.
- * @param name
- * The name to give the node.
- * @param toLink
- * The node to link.
- */
- public void updateLink(String parentPath, String name, AVMNodeDescriptor toLink)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(parentPath);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- store.updateLink(pathParts[1], name, toLink);
- fLookupCache.onWrite(pathParts[0]);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * This is the danger version of link. It must be called on a copied and unsnapshotted directory. It blithely
- * inserts a child without checking if a child exists with a conflicting name.
- *
- * @param parent
- * The parent directory.
- * @param name
- * The name to give the child.
- * @param child
- * The child to link in.
- */
- public void link(AVMNodeDescriptor parent, String name, AVMNodeDescriptor child)
- {
- AVMNode node = fAVMNodeDAO.getByID(parent.getId());
- if (!(node instanceof DirectoryNode))
- {
- throw new AVMWrongTypeException("Not a Directory.");
- }
- DirectoryNode dir = (DirectoryNode) node;
- if (!dir.getIsNew())
- {
- throw new AVMException("Directory has not already been copied.");
- }
- if (!can(null, dir, PermissionService.ADD_CHILDREN, false))
- {
- throw new AccessDeniedException("Not allowed to write: " + parent);
- }
- dir.link(name, child);
- }
-
- /**
- * Remove name without leaving behind a deleted node. Dangerous if used unwisely.
- *
- * @param path
- * The path to the layered directory.
- * @param name
- * The name of the child.
- */
- public void flatten(String path, String name)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- fLookupCache.onDelete(pathParts[0]);
- Lookup lPath = store.lookup(-1, pathParts[1], true, false);
- AVMNode node = lPath.getCurrentNode();
- if (node == null)
- {
- throw new AVMNotFoundException("Path not found.");
- }
- if (!(node instanceof LayeredDirectoryNode))
- {
- throw new AVMWrongTypeException("Not a Layered Directory.");
- }
- if (!can(store, node, PermissionService.FLATTEN, lPath.getDirectlyContained()))
- {
- throw new AccessDeniedException("Not allowed to write in: " + path);
- }
- LayeredDirectoryNode dir = (LayeredDirectoryNode) node;
- dir.flatten(name);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Force a copy on write.
- *
- * @param path
- * The path to force.
- */
- public AVMNodeDescriptor forceCopy(String path)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found.");
- }
- fLookupCache.onWrite(pathParts[0]);
- // Just force a copy if needed by looking up in write mode.
- Lookup lPath = store.lookup(-1, pathParts[1], true, true);
- if (lPath == null)
- {
- throw new AVMNotFoundException("Path not found.");
- }
- AVMNode node = lPath.getCurrentNode();
- AVMNodeDescriptor desc = node.getDescriptor(lPath);
- return desc;
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Rename a store.
- *
- * @param sourceName
- * The original name.
- * @param destName
- * The new name.
- * @throws AVMNotFoundException
- * @throws AVMExistsException
- */
- public void renameStore(String sourceName, String destName)
- {
- AlfrescoTransactionSupport.bindListener(fPurgeStoreTxnListener);
- AlfrescoTransactionSupport.bindListener(fCreateStoreTxnListener);
- AVMStore store = getAVMStoreByName(sourceName);
- if (store == null)
- {
- throw new AVMNotFoundException("Store Not Found: " + sourceName);
- }
- if (getAVMStoreByName(destName) != null)
- {
- throw new AVMExistsException("Store Already Exists: " + destName);
- }
- if (!FileNameValidator.IsValid(destName))
- {
- throw new AVMBadArgumentException("Bad store name: " + destName);
- }
- store.setName(destName);
- store.createSnapshot("Rename Store", "Rename Store from " + sourceName + " to " + destName, new HashMap());
- fLookupCache.onDelete(sourceName);
- fAVMStoreDAO.invalidateCache();
- fPurgeStoreTxnListener.storePurged(sourceName);
- fCreateStoreTxnListener.storeCreated(destName);
- }
-
- /**
- * Revert a head path to a given version. This works by cloning the version to revert to, and then linking that new
- * version into head. The reverted version will have the previous head version as ancestor.
- *
- * @param path
- * The path to the parent directory.
- * @param name
- * The name of the node.
- * @param toRevertTo
- * The descriptor of the version to revert to.
- */
- public void revert(String path, String name, AVMNodeDescriptor toRevertTo)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found: " + pathParts[0]);
- }
- fLookupCache.onWrite(pathParts[0]);
- store.revert(pathParts[1], name, toRevertTo);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Set the GUID on a node.
- *
- * @param path
- * @param guid
- */
- public void setGuid(String path, String guid)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found:" + pathParts[0]);
- }
- fLookupCache.onWrite(pathParts[0]);
- store.setGuid(pathParts[1], guid);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Set the encoding on a node.
- *
- * @param path
- * @param encoding
- */
- public void setEncoding(String path, String encoding)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store Not Found: " + pathParts[0]);
- }
- fLookupCache.onWrite(pathParts[0]);
- store.setEncoding(pathParts[1], encoding);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- /**
- * Set the mime type on a node.
- *
- * @param path
- * @param encoding
- */
- public void setMimeType(String path, String mimeType)
- {
- fLookupCount.set(1);
- try
- {
- String[] pathParts = SplitPath(path);
- AVMStore store = getAVMStoreByName(pathParts[0]);
- if (store == null)
- {
- throw new AVMNotFoundException("Store Not Found: " + pathParts[0]);
- }
- fLookupCache.onWrite(pathParts[0]);
- store.setMimeType(pathParts[1], mimeType);
- }
- finally
- {
- fLookupCount.set(null);
- }
- }
-
- public List getPathsInStoreVersion(AVMNodeDescriptor desc, String store, int version)
- {
- AVMNode node = fAVMNodeDAO.getByID(desc.getId());
- if (node == null)
- {
- throw new AVMNotFoundException("Not found: " + desc);
- }
- List paths = new ArrayList();
- List components = new ArrayList();
- recursiveGetStoreVersionPaths(store, node, version, components, paths);
- return paths;
- }
-
- /**
- * Do the actual work.
- *
- * @param node
- * The current node.
- * @param components
- * The currently accumulated path components.
- * @param paths
- * The list to put full paths in.
- */
- private void recursiveGetStoreVersionPaths(String storeName, AVMNode node, int version, List components, List paths)
- {
- if (!can(null, node, PermissionService.READ, false))
- {
- return;
- }
- if (node.getIsRoot())
- {
- VersionRoot versionRoot = fVersionRootDAO.getByRoot(node);
- if (versionRoot.getAvmStore().getName().equals(storeName) && versionRoot.getVersionID() == version)
- {
- addPath(components, storeName, paths);
- return;
- }
- return;
- }
- List entries = fChildEntryDAO.getByChild(node);
- for (ChildEntry entry : entries)
- {
- String name = entry.getKey().getName();
- components.add(name);
- AVMNode parent = entry.getKey().getParent();
- recursiveGetStoreVersionPaths(storeName, parent, version, components, paths);
- components.remove(components.size() - 1);
- }
- }
-
- public Map getNodeProperties(AVMNodeDescriptor desc)
- {
- AVMNode node = fAVMNodeDAO.getByID(desc.getId());
- if (node == null)
- {
- throw new AVMNotFoundException("Node not found: " + desc);
- }
- if (!can(null, node, PermissionService.READ_PROPERTIES, false))
- {
- throw new AccessDeniedException("Not allowed to read properties: " + desc);
- }
- QNameDAO qnameDAO = AVMDAOs.Instance().fQNameDAO;
- @SuppressWarnings("unchecked")
- Map converted = (Map) qnameDAO.convertIdMapToQNameMap(node.getProperties());
- return converted;
- }
-
- public ContentData getContentDataForRead(AVMNodeDescriptor desc)
- {
- AVMNode node = fAVMNodeDAO.getByID(desc.getId());
- if (node == null)
- {
- throw new AVMNotFoundException("Node not found: " + desc);
- }
- if (!can(null, node, PermissionService.READ_CONTENT, false))
- {
- throw new AccessDeniedException("Not allowed to read: " + desc);
- }
- if (node.getType() == AVMNodeType.PLAIN_FILE)
- {
- PlainFileNode file = (PlainFileNode) node;
- return file.getContentData();
- }
- 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(null, node, PermissionService.READ_PROPERTIES, false))
- {
- throw new AccessDeniedException("Not allowed to read properties: " + desc);
- }
- Set aspectIds = node.getAspects();
- // Convert to QNames
- Set aspectQNames = qnameDAO.convertIdsToQNames(aspectIds);
- return aspectQNames;
- }
-
- /**
- * Evaluate permission on a node. I've got a bad feeling about this...
- *
- * @param store
- * @param node
- * @param permission
- * @return
- */
- public boolean can(AVMStore store, AVMNode node, String permission, boolean isDirectlyContained)
- {
- DbAccessControlList acl = node.getAcl();
-
- QName type;
- if (node.getType() == AVMNodeType.PLAIN_DIRECTORY)
- {
- type = WCMModel.TYPE_AVM_PLAIN_FOLDER;
- }
- else if (node.getType() == AVMNodeType.PLAIN_FILE)
- {
- type = WCMModel.TYPE_AVM_PLAIN_CONTENT;
- }
- else if (node.getType() == AVMNodeType.LAYERED_DIRECTORY)
- {
- type = WCMModel.TYPE_AVM_LAYERED_FOLDER;
- }
- else
- {
- type = WCMModel.TYPE_AVM_LAYERED_CONTENT;
- }
- PermissionContext context = new PermissionContext(type);
-
- // We're doing the hand unrolling of the proxy because Hibernate/CGLIB proxies are broken
- context.addDynamicAuthorityAssignment(AVMNodeUnwrapper.Unwrap(node).getBasicAttributes().getOwner(), PermissionService.OWNER_AUTHORITY);
-
- if ((store != null) && isDirectlyContained)
- {
- StoreType storeType = StoreType.getStoreType(store.getName(), store.getDescriptor(), store.getProperties());
- switch (storeType)
- {
- case AUTHOR:
- case AUTHOR_PREVIEW:
- case AUTHOR_WORKFLOW:
- case AUTHOR_WORKFLOW_PREVIEW:
- String storeName = store.getName();
- int first = -1;
- int second = -1;
- first = storeName.indexOf("--");
- if (first >= 0)
- {
- second = storeName.indexOf("--", first + 2);
- String storeOwner;
- if (second >= 0)
- {
- storeOwner = storeName.substring(first + 2, second);
- }
- else
- {
- storeOwner = storeName.substring(first + 2);
- }
- context.addDynamicAuthorityAssignment(storeOwner, PermissionService.WCM_STORE_OWNER_AUTHORITY);
- }
- break;
- case STAGING:
- case STAGING_PREVIEW:
- case UNKNOWN:
- case WORKFLOW:
- case WORKFLOW_PREVIEW:
- default:
- }
-
- }
- // Pass in node aspects
- Set nodeAspectQNames = qnameDAO.convertIdsToQNames(node.getAspects());
- Set contextQNames = context.getAspects();
- contextQNames.addAll(nodeAspectQNames);
- // Pass in node properties
- Map nodeProperties = node.getProperties();
- Map contextProperties = new HashMap(5);
- QNameDAO qnameDAO = AVMDAOs.Instance().fQNameDAO;
- for (Map.Entry entry : nodeProperties.entrySet())
- {
- QName qname = qnameDAO.getQName(entry.getKey()).getSecond();
- PropertyDefinition def = fDictionaryService.getProperty(qname);
- if (def == null)
- {
- contextProperties.put(qname, entry.getValue().getValue(DataTypeDefinition.ANY));
- }
- else
- {
- contextProperties.put(qname, entry.getValue().getValue(def.getDataType().getName()));
- }
- }
- context.getProperties().putAll(contextProperties);
- Long aclId = null;
- if (acl != null)
- {
- aclId = acl.getId();
- }
- if (store != null)
- {
- DbAccessControlList storeAcl = store.getStoreAcl();
- if (storeAcl != null)
- {
- Long storeAclID = storeAcl.getId();
- context.setStoreAcl(storeAclID);
- }
- }
- return fPermissionService.hasPermission(aclId, context, permission) == AccessStatus.ALLOWED;
- }
-
- public boolean can(String storeName, int version, String path, String permission)
- {
- Lookup lookup = AVMRepository.GetInstance().lookup(version, path, true);
- if (lookup != null)
- {
- AVMNode node = lookup.getCurrentNode();
- AVMStore store = getAVMStoreByName(storeName);
- return can(store, node, permission, lookup.getDirectlyContained());
- }
- else
- {
- // Does not exist => allowed
- return true;
- }
- }
-
- /**
- * Set the acl on a store.
- *
- * @param storeName
- * @param acl
- */
- public void setStoreAcl(String storeName, DbAccessControlList acl)
- {
- AVMStore store = getAVMStoreByName(storeName);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found: " + storeName);
- }
- store.setStoreAcl(acl);
- }
-
- /**
- * Get the ACL on a store.
- *
- * @param storeName
- * @return
- */
- public DbAccessControlList getStoreAcl(String storeName)
- {
- AVMStore store = getAVMStoreByName(storeName);
- if (store == null)
- {
- throw new AVMNotFoundException("Store not found: " + storeName);
- }
- return store.getStoreAcl();
- }
-}
+/*
+ * Copyright (C) 2005-2009 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.domain.QNameDAO;
+import org.alfresco.repo.search.AVMSnapShotTriggeredIndexingMethodInterceptor.StoreType;
+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
+{
+ private static Log fgLogger = LogFactory.getLog(AVMRepository.class);
+
+ /**
+ * The single instance of AVMRepository.
+ */
+ private static AVMRepository fgInstance;
+
+ /**
+ * The current lookup count.
+ */
+ private ThreadLocal fLookupCount;
+
+ /**
+ * Reference to the ContentStoreImpl
+ */
+ private ContentStore fContentStore;
+
+ /**
+ * The Lookup Cache instance.
+ */
+ private LookupCache fLookupCache;
+
+ private QNameDAO qnameDAO;
+
+ private AVMStoreDAO fAVMStoreDAO;
+
+ private AVMNodeDAO fAVMNodeDAO;
+
+ private VersionRootDAO fVersionRootDAO;
+
+ private VersionLayeredNodeEntryDAO fVersionLayeredNodeEntryDAO;
+
+ private AVMStorePropertyDAO fAVMStorePropertyDAO;
+
+ private ChildEntryDAO fChildEntryDAO;
+
+ private PermissionService fPermissionService;
+
+ private DictionaryService fDictionaryService;
+
+ // A bunch of TransactionListeners that do work for this.
+
+ /**
+ * One for create store.
+ */
+ private CreateStoreTxnListener fCreateStoreTxnListener;
+
+ /**
+ * One for purge store.
+ */
+ private PurgeStoreTxnListener fPurgeStoreTxnListener;
+
+ /**
+ * One for create version.
+ */
+ private CreateVersionTxnListener fCreateVersionTxnListener;
+
+ /**
+ * One for purge version.
+ */
+ private PurgeVersionTxnListener fPurgeVersionTxnListener;
+
+ /**
+ * Create a new one.
+ */
+ public AVMRepository()
+ {
+ fLookupCount = new ThreadLocal();
+ fgInstance = this;
+ }
+
+ /**
+ * Set the ContentService.
+ */
+ public void setContentStore(ContentStore store)
+ {
+ fContentStore = store;
+ }
+
+ /**
+ * Set the Lookup Cache instance.
+ *
+ * @param cache
+ * The instance to set.
+ */
+ public void setLookupCache(LookupCache cache)
+ {
+ fLookupCache = cache;
+ }
+
+ public void setCreateStoreTxnListener(CreateStoreTxnListener listener)
+ {
+ fCreateStoreTxnListener = listener;
+ }
+
+ public void setPurgeStoreTxnListener(PurgeStoreTxnListener listener)
+ {
+ fPurgeStoreTxnListener = listener;
+ }
+
+ public void setCreateVersionTxnListener(CreateVersionTxnListener listener)
+ {
+ fCreateVersionTxnListener = listener;
+ }
+
+ public void setPurgeVersionTxnListener(PurgeVersionTxnListener listener)
+ {
+ fPurgeVersionTxnListener = listener;
+ }
+
+ public void setQnameDAO(QNameDAO qnameDAO)
+ {
+ this.qnameDAO = qnameDAO;
+ }
+
+ public void setAvmStoreDAO(AVMStoreDAO dao)
+ {
+ fAVMStoreDAO = dao;
+ }
+
+ public void setAvmNodeDAO(AVMNodeDAO dao)
+ {
+ fAVMNodeDAO = dao;
+ }
+
+ public void setVersionRootDAO(VersionRootDAO dao)
+ {
+ fVersionRootDAO = dao;
+ }
+
+ public void setVersionLayeredNodeEntryDAO(VersionLayeredNodeEntryDAO dao)
+ {
+ fVersionLayeredNodeEntryDAO = dao;
+ }
+
+ public void setAvmStorePropertyDAO(AVMStorePropertyDAO dao)
+ {
+ fAVMStorePropertyDAO = dao;
+ }
+
+ public void setChildEntryDAO(ChildEntryDAO dao)
+ {
+ fChildEntryDAO = dao;
+ }
+
+ public void setPermissionService(PermissionService service)
+ {
+ fPermissionService = service;
+ }
+
+ public void setDictionaryService(DictionaryService service)
+ {
+ fDictionaryService = service;
+ }
+
+ /**
+ * Create a file.
+ *
+ * @param path
+ * The path to the containing directory.
+ * @param name
+ * The name for the new file.
+ */
+ public OutputStream createFile(String path, String name)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ fLookupCache.onWrite(pathParts[0]);
+ OutputStream out = store.createFile(pathParts[1], name);
+ return out;
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Create a file with the given File as content.
+ *
+ * @param path
+ * The path to the containing directory.
+ * @param name
+ * The name to give the file.
+ * @param data
+ * The file contents.
+ */
+ public void createFile(String path, String name, File data, List aspects, Map properties)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ fLookupCache.onWrite(pathParts[0]);
+ store.createFile(pathParts[1], name, data, aspects, properties);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Create a new directory.
+ *
+ * @param path
+ * The path to the containing directory.
+ * @param name
+ * The name to give the directory.
+ */
+ public void createDirectory(String path, String name, List aspects, Map properties)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ fLookupCache.onWrite(pathParts[0]);
+ store.createDirectory(pathParts[1], name, aspects, properties);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Create a new directory. This assumes that the parent is already copied and therefore should only be used with
+ * great care.
+ *
+ * @param parent
+ * The parent node.
+ * @param name
+ * The name of the new directory.
+ * @return A descriptor for the newly created directory.
+ */
+ public AVMNodeDescriptor createDirectory(AVMNodeDescriptor parent, String name)
+ {
+ AVMNode node = fAVMNodeDAO.getByID(parent.getId());
+ if (node == null)
+ {
+ throw new AVMNotFoundException(parent.getId() + " not found.");
+ }
+ if (!(node instanceof DirectoryNode))
+ {
+ throw new AVMWrongTypeException("Not a directory.");
+ }
+ if (!can(null, node, PermissionService.CREATE_CHILDREN, true))
+ {
+ throw new AccessDeniedException("Not allowed to write in: " + parent);
+ }
+ // We need the store to do anything so...
+ String[] pathParts = SplitPath(parent.getPath());
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ DirectoryNode dir = (DirectoryNode) node;
+ DirectoryNode child = null;
+ Long parentAcl = dir.getAcl() == null ? null : dir.getAcl().getId();
+ if (dir instanceof LayeredDirectoryNode)
+ {
+ 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.
+ 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(dstRepo, dirNode, PermissionService.ADD_CHILDREN, dPath.getDirectlyContained()))
+ {
+ throw new AccessDeniedException("Not permitted to add children: " + dstPath);
+ }
+ AVMNode srcNode = sPath.getCurrentNode();
+ AVMNode dstNode = null;
+ // We do different things depending on what kind of thing we're
+ // branching from. I'd be considerably happier if we disallowed
+ // certain scenarios, but Jon won't let me :P (bhp).
+
+ Long inheritAcl = srcNode.getAcl() == null ? null : srcNode.getAcl().getId();
+
+ if (srcNode.getType() == AVMNodeType.PLAIN_DIRECTORY)
+ {
+ dstNode = new PlainDirectoryNodeImpl((PlainDirectoryNode) srcNode, dstRepo, inheritAcl, ACLCopyMode.INHERIT);
+ }
+ else if (srcNode.getType() == AVMNodeType.LAYERED_DIRECTORY)
+ {
+ dstNode = new LayeredDirectoryNodeImpl((LayeredDirectoryNode) srcNode, dstRepo, sPath, false, inheritAcl, ACLCopyMode.INHERIT);
+
+ // note: re-use generated node id as a layer id
+ ((LayeredDirectoryNode) dstNode).setLayerID(dstNode.getId());
+ }
+ else if (srcNode.getType() == AVMNodeType.LAYERED_FILE)
+ {
+ dstNode = new LayeredFileNodeImpl((LayeredFileNode) srcNode, dstRepo, inheritAcl, ACLCopyMode.INHERIT);
+ }
+ else
+ // This is a plain file.
+ {
+ dstNode = new PlainFileNodeImpl((PlainFileNode) srcNode, dstRepo, inheritAcl, ACLCopyMode.INHERIT);
+ }
+ // dstNode.setVersionID(dstRepo.getNextVersionID());
+ dstNode.setAncestor(srcNode);
+ dirNode.putChild(name, dstNode);
+ // dirNode.updateModTime();
+ String beginingPath = 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();
+
+ Pair temp = srcDir.lookupChild(sPath, srcName, false);
+ srcNode = (temp == null) ? null : temp.getFirst();
+ if (srcNode == null)
+ {
+ throw new AVMNotFoundException("Not found: " + srcName);
+ }
+ if (!can(srcRepo, srcNode, PermissionService.DELETE_NODE, false))
+ {
+ throw new AccessDeniedException("Not allowed to delete target: " + srcPath);
+ }
+
+ fLookupCache.onDelete(pathParts[0]);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ fLookupCount.set(1);
+ try
+ {
+ pathParts = SplitPath(dstPath);
+ AVMStore dstRepo = getAVMStoreByName(pathParts[0]);
+ if (dstRepo == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true);
+ if (dPath == null)
+ {
+ throw new AVMNotFoundException("Path not found.");
+ }
+ DirectoryNode dstDir = (DirectoryNode) dPath.getCurrentNode();
+ if (!can(dstRepo, dstDir, PermissionService.ADD_CHILDREN, dPath.getDirectlyContained()))
+ {
+ throw new AccessDeniedException("Not allowed to write: " + dstPath);
+ }
+ Pair temp = dstDir.lookupChild(dPath, dstName, true);
+ AVMNode child = (temp == null) ? null : temp.getFirst();
+ 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);
+
+ // note: re-use generated node id as a layer id
+ ((LayeredDirectoryNode) dstNode).setLayerID(dstNode.getId());
+ }
+ }
+ else
+ {
+ dstNode = new PlainDirectoryNodeImpl((PlainDirectoryNode) srcNode, dstRepo, parentAcl, ACLCopyMode.COPY);
+ }
+ }
+ else if (srcNode.getType() == AVMNodeType.LAYERED_DIRECTORY)
+ {
+ if (!sPath.isLayered() || (sPath.isInThisLayer() && srcDir.getType() == AVMNodeType.LAYERED_DIRECTORY && ((LayeredDirectoryNode) srcDir).directlyContains(srcNode)))
+ {
+ Lookup srcLookup = lookup(-1, srcPath + "/" + srcName, true);
+ // Use the simple 'copy' constructor.
+ dstNode = new LayeredDirectoryNodeImpl((LayeredDirectoryNode) srcNode, dstRepo, srcLookup, true, parentAcl, ACLCopyMode.COPY);
+ ((LayeredDirectoryNode) dstNode).setLayerID(((LayeredDirectoryNode) srcNode).getLayerID());
+ }
+ else
+ {
+ // If the source node is a primary indirection, then the 'copy' constructor
+ // is used. Otherwise the alternate constructor is called and its
+ // indirection is calculated from it's source context.
+ if (((LayeredDirectoryNode) srcNode).getPrimaryIndirection())
+ {
+ Lookup srcLookup = lookup(-1, srcPath + "/" + srcName, true);
+ dstNode = new LayeredDirectoryNodeImpl((LayeredDirectoryNode) srcNode, dstRepo, srcLookup, true, parentAcl, ACLCopyMode.COPY);
+ }
+ else
+ {
+ dstNode = new LayeredDirectoryNodeImpl((DirectoryNode) srcNode, dstRepo, sPath, srcName, parentAcl, ACLCopyMode.COPY);
+ }
+ // What needs to be done here is dependent on whether the
+ // rename is to a layered context. If so then it should get the layer id
+ // of its destination parent. Otherwise it should get a new layer
+ // id.
+ if (dPath.isLayered())
+ {
+ ((LayeredDirectoryNode) dstNode).setLayerID(dPath.getTopLayer().getLayerID());
+ }
+ else
+ {
+ // note: re-use generated node id as a layer id
+ ((LayeredDirectoryNode) dstNode).setLayerID(dstNode.getId());
+ }
+ }
+ }
+ 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)
+ {
+ try
+ {
+ fAVMNodeDAO.noCache();
+ AlfrescoTransactionSupport.bindListener(fCreateVersionTxnListener);
+ AVMStore store = getAVMStoreByName(storeName);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ Map result = store.createSnapshot(tag, description, new HashMap());
+ for (Map.Entry entry : result.entrySet())
+ {
+ fLookupCache.onSnapshot(entry.getKey());
+ fCreateVersionTxnListener.versionCreated(entry.getKey(), entry.getValue());
+ }
+ return result;
+ }
+ finally
+ {
+ fAVMNodeDAO.yesCache();
+ }
+ }
+
+ /**
+ * Remove a node and everything underneath it.
+ *
+ * @param path
+ * The path to the containing directory.
+ * @param name
+ * The name of the node to remove.
+ */
+ public void remove(String path, String name)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ fLookupCache.onDelete(pathParts[0]);
+ store.removeNode(pathParts[1], name);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Get rid of all content that lives only in the given AVMStore. Also removes the AVMStore.
+ *
+ * @param name
+ * The name of the AVMStore to purge.
+ */
+ public void purgeAVMStore(String name)
+ {
+ AlfrescoTransactionSupport.bindListener(fPurgeStoreTxnListener);
+ AVMStore store = getAVMStoreByName(name);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ fLookupCache.onDelete(name);
+ AVMNode root = store.getRoot();
+ // TODO Probably a special PermissionService.PURGE is needed.
+ if (!can(store, root, PermissionService.DELETE_CHILDREN, true))
+ {
+ throw new AccessDeniedException("Not allowed to purge: " + name);
+ }
+ 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(null, node, PermissionService.READ_CONTENT, false))
+ {
+ throw new AccessDeniedException("Not allowed to read content: " + desc);
+ }
+ FileNode file = (FileNode) node;
+ ContentData data = file.getContentData(null);
+ if (data == null)
+ {
+ throw new AVMException(desc + " has no content.");
+ }
+ ContentReader reader = fContentStore.getReader(data.getContentUrl());
+ return reader.getContentInputStream();
+ }
+
+ /**
+ * Get a listing of a directory.
+ *
+ * @param version
+ * The version to look under.
+ * @param path
+ * The path to the directory.
+ * @param includeDeleted
+ * Whether to see DeletedNodes.
+ * @return A List of FolderEntries.
+ */
+ public SortedMap getListing(int version, String path, boolean includeDeleted)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ return store.getListing(version, pathParts[1], includeDeleted);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Get the list of nodes directly contained in a directory.
+ *
+ * @param version
+ * The version to look under.
+ * @param path
+ * The path to the directory to list.
+ * @return A Map of names to descriptors.
+ */
+ public SortedMap getListingDirect(int version, String path, boolean includeDeleted)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ return store.getListingDirect(version, pathParts[1], includeDeleted);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Get the list of nodes directly contained in a directory.
+ *
+ * @param dir
+ * The descriptor to the directory node.
+ * @param includeDeleted
+ * Whether to include deleted children.
+ * @return A Map of names to descriptors.
+ */
+ public SortedMap getListingDirect(AVMNodeDescriptor dir, boolean includeDeleted)
+ {
+ AVMNode node = fAVMNodeDAO.getByID(dir.getId());
+ if (node == null)
+ {
+ throw new AVMBadArgumentException("Invalid Node.");
+ }
+ if (!can(null, node, PermissionService.READ_CHILDREN, false))
+ {
+ throw new AccessDeniedException("Not allowed to read children: " + dir);
+ }
+ if (node.getType() == AVMNodeType.PLAIN_DIRECTORY)
+ {
+ return getListing(dir, includeDeleted);
+ }
+ if (node.getType() != AVMNodeType.LAYERED_DIRECTORY)
+ {
+ throw new AVMWrongTypeException("Not a directory.");
+ }
+ LayeredDirectoryNode dirNode = (LayeredDirectoryNode) node;
+ return dirNode.getListingDirect(dir, includeDeleted);
+ }
+
+ /**
+ * Get a directory listing from a directory node descriptor.
+ *
+ * @param dir
+ * The directory node descriptor.
+ * @return A SortedMap listing.
+ */
+ public SortedMap getListing(AVMNodeDescriptor dir, boolean includeDeleted)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ AVMNode node = fAVMNodeDAO.getByID(dir.getId());
+ if (node == null)
+ {
+ throw new AVMBadArgumentException("Invalid Node.");
+ }
+ if (node.getType() != AVMNodeType.LAYERED_DIRECTORY && node.getType() != AVMNodeType.PLAIN_DIRECTORY)
+ {
+ throw new AVMWrongTypeException("Not a directory.");
+ }
+ if (!can(null, node, PermissionService.READ_CHILDREN, false))
+ {
+ throw new AccessDeniedException("Not allowed to read children: " + dir);
+ }
+ DirectoryNode dirNode = (DirectoryNode) node;
+ SortedMap listing = dirNode.getListing(dir, includeDeleted);
+ return listing;
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Get a directory listing from a directory node descriptor fo children that match the given pattern
+ *
+ * @param dir
+ * The directory node descriptor.
+ * @return A SortedMap listing.
+ */
+ public SortedMap getListing(AVMNodeDescriptor dir, String childNamePattern, boolean includeDeleted)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ AVMNode node = fAVMNodeDAO.getByID(dir.getId());
+ if (node == null)
+ {
+ throw new AVMBadArgumentException("Invalid Node.");
+ }
+ if (node.getType() != AVMNodeType.LAYERED_DIRECTORY && node.getType() != AVMNodeType.PLAIN_DIRECTORY)
+ {
+ throw new AVMWrongTypeException("Not a directory.");
+ }
+ if (!can(null, node, PermissionService.READ_CHILDREN, false))
+ {
+ throw new AccessDeniedException("Not allowed to read children: " + dir);
+ }
+ DirectoryNode dirNode = (DirectoryNode) node;
+ SortedMap listing = dirNode.getListing(dir, childNamePattern, includeDeleted);
+ return listing;
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+
+ /**
+ * Get the names of deleted nodes in a directory.
+ *
+ * @param version
+ * The version to look under.
+ * @param path
+ * The path to the directory.
+ * @return A List of names.
+ */
+ public List getDeleted(int version, String path)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ return store.getDeleted(version, pathParts[1]);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Get descriptors of all AVMStores.
+ *
+ * @return A list of all descriptors.
+ */
+ public List getAVMStores()
+ {
+ List 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);
+ }
+
+ /**
+ * Get the indirection path for a layered node.
+ *
+ * @param version
+ * The version to look under.
+ * @param path
+ * The path to the node.
+ * @return The indirection path.
+ */
+ public String getIndirectionPath(int version, String path)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ return store.getIndirectionPath(version, pathParts[1]);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Get the next version id for the given AVMStore.
+ *
+ * @param name
+ * The name of the AVMStore.
+ * @return The next version id.
+ */
+ public int getLatestVersionID(String name)
+ {
+ AVMStore store = getAVMStoreByName(name);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ return store.getNextVersionID();
+ }
+
+ /**
+ * Get the latest extant snapshotted version id.
+ *
+ * @param name
+ * The store name.
+ */
+ public int getLatestSnapshotID(String name)
+ {
+ AVMStore store = getAVMStoreByName(name);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ return store.getLastVersionID();
+ }
+
+ /**
+ * Get an AVMStore by name.
+ *
+ * @param name
+ * The name of the AVMStore.
+ * @return The AVMStore.
+ */
+ private AVMStore getAVMStoreByName(String name)
+ {
+ AVMStore store = fAVMStoreDAO.getByName(name);
+ return store;
+ }
+
+ /**
+ * Get a descriptor for an AVMStore root.
+ *
+ * @param version
+ * The version to get.
+ * @param name
+ * The name of the AVMStore.
+ * @return The descriptor for the root.
+ */
+ public AVMNodeDescriptor getAVMStoreRoot(int version, String name)
+ {
+ AVMStore store = getAVMStoreByName(name);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Not found: " + name);
+ }
+ return store.getRoot(version);
+ }
+
+ // TODO Fix this awful mess regarding cycle detection.
+ /**
+ * Lookup a node.
+ *
+ * @param version
+ * The version to look under.
+ * @param path
+ * The path to lookup.
+ * @param includeDeleted
+ * Whether to see DeletedNodes.
+ * @return A lookup object.
+ */
+ public Lookup lookup(int version, String path, boolean includeDeleted)
+ {
+ Integer count = fLookupCount.get();
+ try
+ {
+ if (count == null)
+ {
+ fLookupCount.set(1);
+ }
+ else
+ {
+ fLookupCount.set(count + 1);
+ }
+ if (fLookupCount.get() > 50)
+ {
+ throw new AVMCycleException("Cycle in lookup.");
+ }
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ return null;
+ }
+ return store.lookup(version, pathParts[1], false, includeDeleted);
+ }
+ finally
+ {
+ if (count == null)
+ {
+ fLookupCount.set(null);
+ }
+ }
+ }
+
+ /**
+ * Lookup a descriptor from a directory descriptor.
+ *
+ * @param dir
+ * The directory descriptor.
+ * @param name
+ * The name of the child to lookup.
+ * @return The child's descriptor.
+ */
+ public AVMNodeDescriptor lookup(AVMNodeDescriptor dir, String name, boolean includeDeleted)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ AVMNode node = fAVMNodeDAO.getByID(dir.getId());
+ if (node == null)
+ {
+ throw new AVMNotFoundException("Not found: " + dir.getId());
+ }
+ if (node.getType() != AVMNodeType.LAYERED_DIRECTORY && node.getType() != AVMNodeType.PLAIN_DIRECTORY)
+ {
+ throw new AVMWrongTypeException("Not a directory.");
+ }
+ DirectoryNode dirNode = (DirectoryNode) node;
+ if (!can(null, dirNode, PermissionService.READ_CHILDREN, false))
+ {
+ throw new AccessDeniedException("Not allowed to read children: " + dir);
+ }
+ return dirNode.lookupChild(dir, name, includeDeleted);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Get all the paths to a particular node.
+ *
+ * @param desc
+ * The node descriptor.
+ * @return The list of version, paths.
+ */
+ public List> getPaths(AVMNodeDescriptor desc)
+ {
+ AVMNode node = fAVMNodeDAO.getByID(desc.getId());
+ if (node == null)
+ {
+ throw new AVMNotFoundException("Not found: " + desc);
+ }
+ List> paths = new ArrayList>();
+ List components = new ArrayList();
+ recursiveGetPaths(node, components, paths);
+ return paths;
+ }
+
+ /**
+ * Get a single valid path for a node.
+ *
+ * @param desc
+ * The node descriptor.
+ * @return A version, path
+ */
+ public Pair getAPath(AVMNodeDescriptor desc)
+ {
+ AVMNode node = fAVMNodeDAO.getByID(desc.getId());
+ if (node == null)
+ {
+ throw new AVMNotFoundException("Could not find node: " + desc);
+ }
+ if (fgLogger.isDebugEnabled())
+ {
+ fgLogger.debug("Getting A Path for: " + desc);
+ }
+ List components = new ArrayList();
+ return recursiveGetAPath(node, components);
+ }
+
+ /**
+ * Get all paths for a node reachable by HEAD.
+ *
+ * @param desc
+ * The node descriptor.
+ * @return A List of all the version, path Pairs that match.
+ */
+ public List> getHeadPaths(AVMNodeDescriptor desc)
+ {
+ AVMNode node = fAVMNodeDAO.getByID(desc.getId());
+ if (node == null)
+ {
+ throw new AVMNotFoundException("Not found: " + desc.getPath());
+ }
+ List> paths = new ArrayList>();
+ List components = new ArrayList();
+ recursiveGetHeadPaths(node, components, paths);
+ return paths;
+ }
+
+ /**
+ * Gets all the pass from to the given node starting from the give version root.
+ *
+ * @param version
+ * The version root.
+ * @param node
+ * The node to get the paths of.
+ * @return A list of all paths in the given version to the node.
+ */
+ public List getVersionPaths(VersionRoot version, AVMNode node)
+ {
+ List paths = new ArrayList();
+ List components = new ArrayList();
+ recursiveGetVersionPaths(node, components, paths, version.getRoot(), version.getAvmStore().getName());
+ return paths;
+ }
+
+ /**
+ * Helper to get all version paths.
+ *
+ * @param node
+ * The current node we are examining.
+ * @param components
+ * The current path components.
+ * @param paths
+ * The list to contain found paths.
+ * @param root
+ * The root node of the version.
+ * @param storeName
+ * The name of the store.
+ */
+ private void recursiveGetVersionPaths(AVMNode node, List components, List paths, DirectoryNode root, String storeName)
+ {
+ if (!can(null, node, PermissionService.READ_CHILDREN, false))
+ {
+ return;
+ }
+ if (node.equals(root))
+ {
+ paths.add(this.makePath(components, storeName));
+ return;
+ }
+ List entries = fChildEntryDAO.getByChild(node);
+ for (ChildEntry entry : entries)
+ {
+ String name = entry.getKey().getName();
+ components.add(name);
+ AVMNode parent = entry.getKey().getParent();
+ recursiveGetVersionPaths(parent, components, paths, root, storeName);
+ components.remove(components.size() - 1);
+ }
+ }
+
+ /**
+ * Get all paths in a particular store in the head version for a particular node.
+ *
+ * @param desc
+ * The node descriptor.
+ * @param store
+ * The name of the store.
+ * @return All matching paths.
+ */
+ public List> getPathsInStoreHead(AVMNodeDescriptor desc, String store)
+ {
+ AVMStore st = getAVMStoreByName(store);
+ if (st == null)
+ {
+ throw new AVMNotFoundException("Store not found: " + store);
+ }
+ AVMNode node = fAVMNodeDAO.getByID(desc.getId());
+ if (node == null)
+ {
+ throw new AVMNotFoundException("Not found: " + desc);
+ }
+ List> paths = new ArrayList>();
+ List components = new ArrayList();
+ recursiveGetPathsInStoreHead(node, components, paths, st.getRoot(), store);
+ return paths;
+ }
+
+ /**
+ * Do the actual work.
+ *
+ * @param node
+ * The current node.
+ * @param components
+ * The currently accumulated path components.
+ * @param paths
+ * The list to put full paths in.
+ */
+ private void recursiveGetPaths(AVMNode node, List components, List> paths)
+ {
+ if (!can(null, node, PermissionService.READ_CHILDREN, false))
+ {
+ return;
+ }
+ if (node.getIsRoot())
+ {
+ AVMStore store = fAVMStoreDAO.getByRoot(node);
+ if (store != null)
+ {
+ addPath(components, -1, store.getName(), paths);
+ }
+ VersionRoot vr = fVersionRootDAO.getByRoot(node);
+ if (vr != null)
+ {
+ addPath(components, vr.getVersionID(), vr.getAvmStore().getName(), paths);
+ }
+ return;
+ }
+ List entries = fChildEntryDAO.getByChild(node);
+ for (ChildEntry entry : entries)
+ {
+ String name = entry.getKey().getName();
+ components.add(name);
+ AVMNode parent = entry.getKey().getParent();
+ recursiveGetPaths(parent, components, paths);
+ components.remove(components.size() - 1);
+ }
+ }
+
+ /**
+ * Do the work of getting one path for a node.
+ *
+ * @param node
+ * The node to get the path of.
+ * @param components
+ * The storage for path components.
+ * @return A path or null.
+ */
+ private Pair recursiveGetAPath(AVMNode node, List components)
+ {
+ if (!can(null, node, PermissionService.READ_CHILDREN, false))
+ {
+ return null;
+ }
+ if (node.getIsRoot())
+ {
+ AVMStore store = fAVMStoreDAO.getByRoot(node);
+ if (store != null)
+ {
+ if (fgLogger.isDebugEnabled())
+ {
+ fgLogger.debug("Found path in HEAD of: " + store.getName());
+ }
+ return new Pair(-1, makePath(components, store.getName()));
+ }
+ VersionRoot vr = fVersionRootDAO.getByRoot(node);
+ if (vr != null)
+ {
+ if (fgLogger.isDebugEnabled())
+ {
+ fgLogger.debug("Found path in version " + vr.getVersionID() + " in: " + vr.getAvmStore().getName());
+ }
+ return new Pair(vr.getVersionID(), makePath(components, vr.getAvmStore().getName()));
+ }
+ return null;
+ }
+ List entries = fChildEntryDAO.getByChild(node);
+ for (ChildEntry entry : entries)
+ {
+ String name = entry.getKey().getName();
+ if (fgLogger.isDebugEnabled())
+ {
+ fgLogger.debug("Found component: " + name);
+ }
+ components.add(name);
+ Pair path = recursiveGetAPath(AVMNodeUnwrapper.Unwrap(entry.getKey().getParent()), components);
+ if (path != null)
+ {
+ return path;
+ }
+ components.remove(components.size() - 1);
+ }
+ return null;
+ }
+
+ /**
+ * Do the actual work.
+ *
+ * @param node
+ * The current node.
+ * @param components
+ * The currently accumulated path components.
+ * @param paths
+ * The list to put full paths in.
+ */
+ private void recursiveGetHeadPaths(AVMNode node, List components, List> paths)
+ {
+ if (!can(null, node, PermissionService.READ_CHILDREN, false))
+ {
+ return;
+ }
+ if (node.getIsRoot())
+ {
+ AVMStore store = fAVMStoreDAO.getByRoot(node);
+ if (store != null)
+ {
+ addPath(components, -1, store.getName(), paths);
+ return;
+ }
+ return;
+ }
+ List entries = fChildEntryDAO.getByChild(node);
+ for (ChildEntry entry : entries)
+ {
+ String name = entry.getKey().getName();
+ components.add(name);
+ AVMNode parent = entry.getKey().getParent();
+ recursiveGetHeadPaths(parent, components, paths);
+ components.remove(components.size() - 1);
+ }
+ }
+
+ /**
+ * Do the actual work.
+ *
+ * @param node
+ * The current node.
+ * @param components
+ * The currently accumulated path components.
+ * @param paths
+ * The list to put full paths in.
+ */
+ private void recursiveGetPathsInStoreHead(AVMNode node, List components, List> paths, DirectoryNode root, String storeName)
+ {
+ if (!can(null, node, PermissionService.READ_CHILDREN, false))
+ {
+ return;
+ }
+ if (node.equals(root))
+ {
+ addPath(components, -1, storeName, paths);
+ return;
+ }
+ List entries = fChildEntryDAO.getByChild(node);
+ for (ChildEntry entry : entries)
+ {
+ String name = entry.getKey().getName();
+ components.add(name);
+ AVMNode parent = entry.getKey().getParent();
+ recursiveGetHeadPaths(parent, components, paths);
+ components.remove(components.size() - 1);
+ }
+ }
+
+ /**
+ * Add a path to the list.
+ *
+ * @param components
+ * The path name components.
+ * @param version
+ * The version id.
+ * @param storeName
+ * The name of the
+ * @param paths
+ * The List to add to.
+ */
+ private void addPath(List components, int version, String storeName, List> paths)
+ {
+ paths.add(new Pair(version, makePath(components, storeName)));
+ }
+
+ /**
+ * Alternate version.
+ *
+ * @param components
+ * @param storeName
+ * @param paths
+ */
+ private void addPath(List components, String storeName, List paths)
+ {
+ paths.add(makePath(components, storeName));
+ }
+
+ /**
+ * Helper for generating paths.
+ *
+ * @param components
+ * The path components.
+ * @param storeName
+ * The store that the path is in.
+ * @return The path.
+ */
+ private String makePath(List components, String storeName)
+ {
+ StringBuilder pathBuilder = new StringBuilder();
+ pathBuilder.append(storeName);
+ pathBuilder.append(":");
+ if (components.size() == 0)
+ {
+ pathBuilder.append("/");
+ return pathBuilder.toString();
+ }
+ for (int i = components.size() - 1; i >= 0; i--)
+ {
+ pathBuilder.append("/");
+ pathBuilder.append(components.get(i));
+ }
+ return pathBuilder.toString();
+ }
+
+ /**
+ * Get information about layering of a path.
+ *
+ * @param version
+ * The version to look under.
+ * @param path
+ * The full avm path.
+ * @return A LayeringDescriptor.
+ */
+ public LayeringDescriptor getLayeringInfo(int version, String path)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ Lookup lookup = store.lookup(version, pathParts[1], false, true);
+ if (lookup == null)
+ {
+ throw new AVMNotFoundException("Path not found.");
+ }
+ if (!can(store, lookup.getCurrentNode(), PermissionService.READ_PROPERTIES, false))
+ {
+ throw new AccessDeniedException("Not allowed to read properties: " + path);
+ }
+ return new LayeringDescriptor(!lookup.getDirectlyContained(), lookup.getAVMStore().getDescriptor(), lookup.getFinalStore().getDescriptor());
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Lookup a directory specifically.
+ *
+ * @param version
+ * The version to look under.
+ * @param path
+ * The path to lookup.
+ * @return A lookup object.
+ */
+ public Lookup lookupDirectory(int version, String path)
+ {
+ Integer count = fLookupCount.get();
+ try
+ {
+ if (count == null)
+ {
+ fLookupCount.set(1);
+ }
+ fLookupCount.set(fLookupCount.get() + 1);
+ if (fLookupCount.get() > 50)
+ {
+ throw new AVMCycleException("Cycle in lookup.");
+ }
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ return null;
+ }
+ return store.lookupDirectory(version, pathParts[1], false);
+ }
+ finally
+ {
+ if (count == null)
+ {
+ fLookupCount.set(null);
+ }
+ }
+ }
+
+ /**
+ * Utility to split a path, foo:bar/baz into its repository and path parts.
+ *
+ * @param path
+ * The fully qualified path.
+ * @return The repository name and the repository path.
+ */
+ private String[] SplitPath(String path)
+ {
+ 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(null, node, PermissionService.READ_PROPERTIES, false))
+ {
+ throw new AccessDeniedException("Not allowed to read properties: " + desc);
+ }
+ if (count < 0)
+ {
+ count = Integer.MAX_VALUE;
+ }
+ List history = new ArrayList();
+ for (int i = 0; i < count; i++)
+ {
+ node = node.getAncestor();
+ if (node == null)
+ {
+ break;
+ }
+ if (!can(null, node, PermissionService.READ_PROPERTIES, false))
+ {
+ 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.
+ */
+ @SuppressWarnings("unchecked")
+ 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 matchesMap = new HashMap();
+ for (AVMStoreProperty prop : matches)
+ {
+ matchesMap.put(prop.getQnameId(), prop.getValue());
+ }
+ Map propertyMap = (Map) qnameDAO.convertIdMapToQNameMap(matchesMap);
+ return propertyMap;
+ }
+
+ /**
+ * 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();
+ QName propQName = qnameDAO.getQName(prop.getQnameId()).getSecond();
+ Map pairs = null;
+ if ((pairs = results.get(storeName)) == null)
+ {
+ pairs = new HashMap();
+ results.put(storeName, pairs);
+ }
+ pairs.put(propQName, 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(null, lNode, PermissionService.READ_PROPERTIES, false))
+ {
+ throw new AccessDeniedException("Not allowed to read properties: " + left);
+ }
+ if (!can(null, rNode, PermissionService.READ_PROPERTIES, false))
+ {
+ throw new AccessDeniedException("Not allowed to read properties: " + right);
+ }
+ // TODO Short changing the permissions checking here. I'm not sure
+ // if that's OK.
+ List leftHistory = new ArrayList();
+ List rightHistory = new ArrayList();
+ while (lNode != null || rNode != null)
+ {
+ boolean checkRight = false;
+ if (lNode != null)
+ {
+ leftHistory.add(lNode);
+ checkRight = true;
+ lNode = lNode.getAncestor();
+ }
+ boolean checkLeft = false;
+ if (rNode != null)
+ {
+ rightHistory.add(rNode);
+ checkLeft = true;
+ rNode = rNode.getAncestor();
+ }
+ if (checkRight)
+ {
+ AVMNode check = leftHistory.get(leftHistory.size() - 1);
+ for (AVMNode node : rightHistory)
+ {
+ if (node.equals(check))
+ {
+ return node.getDescriptor("", "", "", -1);
+ }
+ }
+ }
+ if (checkLeft)
+ {
+ AVMNode check = rightHistory.get(rightHistory.size() - 1);
+ for (AVMNode node : leftHistory)
+ {
+ if (node.equals(check))
+ {
+ return node.getDescriptor("", "", "", -1);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the ContentData for a file.
+ *
+ * @param version
+ * The version to look under.
+ * @param path
+ * The path to the file.
+ * @return The ContentData for the file.
+ */
+ public ContentData getContentDataForRead(int version, String path)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ return store.getContentDataForRead(version, pathParts[1]);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Get the ContentData for a file for writing.
+ *
+ * @param path
+ * The path to the file.
+ * @return The ContentData object.
+ */
+ public ContentData getContentDataForWrite(String path)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ fLookupCache.onWrite(pathParts[0]);
+ ContentData result = store.getContentDataForWrite(pathParts[1]);
+ return result;
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Set the ContentData on a file.
+ *
+ * @param path
+ * The path to the file.
+ * @param data
+ * The content data to set.
+ */
+ public void setContentData(String path, ContentData data)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ fLookupCache.onWrite(pathParts[0]);
+ store.setContentData(pathParts[1], data);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Get the single instance of AVMRepository.
+ *
+ * @return The single instance.
+ */
+ public static AVMRepository GetInstance()
+ {
+ return fgInstance;
+ }
+
+ public void setMetaDataFrom(String path, AVMNodeDescriptor from)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found: " + pathParts[0]);
+ }
+ AVMNode fromNode = fAVMNodeDAO.getByID(from.getId());
+ if (fromNode == null)
+ {
+ throw new AVMNotFoundException("Node not found: " + from.getPath());
+ }
+ fLookupCache.onWrite(pathParts[0]);
+ store.setMetaDataFrom(pathParts[1], fromNode);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Add an aspect to an AVM Node.
+ *
+ * @param path
+ * The path to the node.
+ * @param aspectName
+ * The name of the aspect.
+ */
+ public void addAspect(String path, QName aspectName)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ fLookupCache.onWrite(pathParts[0]);
+ store.addAspect(pathParts[1], aspectName);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Get all the aspects on an AVM node.
+ *
+ * @param version
+ * The version to look under.
+ * @param path
+ * The path to the node.
+ * @return A List of the QNames of the Aspects.
+ */
+ public Set getAspects(int version, String path)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ return store.getAspects(version, pathParts[1]);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Remove an aspect and all associated properties from a node.
+ *
+ * @param path
+ * The path to the node.
+ * @param aspectName
+ * The name of the aspect.
+ */
+ public void removeAspect(String path, QName aspectName)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ fLookupCache.onWrite(pathParts[0]);
+ store.removeAspect(pathParts[1], aspectName);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Does a node have a particular aspect.
+ *
+ * @param version
+ * The version to look under.
+ * @param path
+ * The path to the node.
+ * @param aspectName
+ * The name of the aspect.
+ * @return Whether the node has the aspect.
+ */
+ public boolean hasAspect(int version, String path, QName aspectName)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ return store.hasAspect(version, pathParts[1], aspectName);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Set the ACL on a node.
+ *
+ * @param path
+ * The path to the node.
+ * @param acl
+ * The ACL to set.
+ */
+ public void setACL(String path, DbAccessControlList acl)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ fLookupCache.onWrite(pathParts[0]);
+ store.setACL(pathParts[1], acl);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Get the ACL on a node.
+ *
+ * @param version
+ * The version to look under.
+ * @param path
+ * The path to the node.
+ * @return The ACL.
+ */
+ public DbAccessControlList getACL(int version, String path)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ return store.getACL(version, pathParts[1]);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Link a node into a directory, directly.
+ *
+ * @param parentPath
+ * The path to the parent.
+ * @param name
+ * The name to give the node.
+ * @param toLink
+ * The node to link.
+ */
+ public void link(String parentPath, String name, AVMNodeDescriptor toLink)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(parentPath);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ store.link(pathParts[1], name, toLink);
+ fLookupCache.onWrite(pathParts[0]);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Update a link, directly.
+ *
+ * @param parentPath
+ * The path to the parent.
+ * @param name
+ * The name to give the node.
+ * @param toLink
+ * The node to link.
+ */
+ public void updateLink(String parentPath, String name, AVMNodeDescriptor toLink)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(parentPath);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ store.updateLink(pathParts[1], name, toLink);
+ fLookupCache.onWrite(pathParts[0]);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * This is the danger version of link. It must be called on a copied and unsnapshotted directory. It blithely
+ * inserts a child without checking if a child exists with a conflicting name.
+ *
+ * @param parent
+ * The parent directory.
+ * @param name
+ * The name to give the child.
+ * @param child
+ * The child to link in.
+ */
+ public void link(AVMNodeDescriptor parent, String name, AVMNodeDescriptor child)
+ {
+ AVMNode node = fAVMNodeDAO.getByID(parent.getId());
+ if (!(node instanceof DirectoryNode))
+ {
+ throw new AVMWrongTypeException("Not a Directory.");
+ }
+ DirectoryNode dir = (DirectoryNode) node;
+ if (!dir.getIsNew())
+ {
+ throw new AVMException("Directory has not already been copied.");
+ }
+ if (!can(null, dir, PermissionService.ADD_CHILDREN, false))
+ {
+ throw new AccessDeniedException("Not allowed to write: " + parent);
+ }
+ dir.link(name, child);
+ }
+
+ /**
+ * Remove name without leaving behind a deleted node. Dangerous if used unwisely.
+ *
+ * @param path
+ * The path to the layered directory.
+ * @param name
+ * The name of the child.
+ */
+ public void flatten(String path, String name)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ fLookupCache.onDelete(pathParts[0]);
+ Lookup lPath = store.lookup(-1, pathParts[1], true, false);
+ AVMNode node = lPath.getCurrentNode();
+ if (node == null)
+ {
+ throw new AVMNotFoundException("Path not found.");
+ }
+ if (!(node instanceof LayeredDirectoryNode))
+ {
+ throw new AVMWrongTypeException("Not a Layered Directory.");
+ }
+ if (!can(store, node, PermissionService.FLATTEN, lPath.getDirectlyContained()))
+ {
+ throw new AccessDeniedException("Not allowed to write in: " + path);
+ }
+ LayeredDirectoryNode dir = (LayeredDirectoryNode) node;
+ dir.flatten(name);
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Force a copy on write.
+ *
+ * @param path
+ * The path to force.
+ */
+ public AVMNodeDescriptor forceCopy(String path)
+ {
+ fLookupCount.set(1);
+ try
+ {
+ String[] pathParts = SplitPath(path);
+ AVMStore store = getAVMStoreByName(pathParts[0]);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store not found.");
+ }
+ fLookupCache.onWrite(pathParts[0]);
+ // Just force a copy if needed by looking up in write mode.
+ Lookup lPath = store.lookup(-1, pathParts[1], true, true);
+ if (lPath == null)
+ {
+ throw new AVMNotFoundException("Path not found.");
+ }
+ AVMNode node = lPath.getCurrentNode();
+ AVMNodeDescriptor desc = node.getDescriptor(lPath);
+ return desc;
+ }
+ finally
+ {
+ fLookupCount.set(null);
+ }
+ }
+
+ /**
+ * Rename a store.
+ *
+ * @param sourceName
+ * The original name.
+ * @param destName
+ * The new name.
+ * @throws AVMNotFoundException
+ * @throws AVMExistsException
+ */
+ public void renameStore(String sourceName, String destName)
+ {
+ AlfrescoTransactionSupport.bindListener(fPurgeStoreTxnListener);
+ AlfrescoTransactionSupport.bindListener(fCreateStoreTxnListener);
+ AVMStore store = getAVMStoreByName(sourceName);
+ if (store == null)
+ {
+ throw new AVMNotFoundException("Store Not Found: " + sourceName);
+ }
+ if (getAVMStoreByName(destName) != null)
+ {
+ throw new AVMExistsException("Store Already Exists: " + destName);
+ }
+ if (!FileNameValidator.IsValid(destName))
+ {
+ throw new AVMBadArgumentException("Bad store name: " + destName);
+ }
+ store.setName(destName);
+ 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