diff --git a/config/alfresco/model/contentModel.xml b/config/alfresco/model/contentModel.xml index dc35262083..b48f0085bd 100644 --- a/config/alfresco/model/contentModel.xml +++ b/config/alfresco/model/contentModel.xml @@ -79,11 +79,29 @@ + - AVM Content - cm:content + AVM Content + cm:content + + AVM Plain content + cm:avmcontent + + + + AVM Layered Content + cm:content + + + File Layer Indirection + d:noderef + true + + + + Dictionary Model cm:content @@ -143,9 +161,27 @@ cm:folder + - AVM Folder - cm:folder + AVM Folder + cm:folder + + + + AVM Plain Folder + cm:avmfolder + + + + AVM Layered Folder + cm:avmfolder + + + Directory Layer Indirection + d:noderef + true + + @@ -696,16 +732,6 @@ - - Mounted - - - Mountpoint - d:noderef - - - - diff --git a/source/java/org/alfresco/model/ContentModel.java b/source/java/org/alfresco/model/ContentModel.java index fd2f92fc79..c2558c4ba5 100644 --- a/source/java/org/alfresco/model/ContentModel.java +++ b/source/java/org/alfresco/model/ContentModel.java @@ -98,6 +98,12 @@ public interface ContentModel static final QName TYPE_CONTENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "content"); static final QName PROP_CONTENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "content"); static final QName TYPE_AVM_CONTENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "avmcontent"); + static final QName TYPE_AVM_PLAIN_CONTENT = + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "avmplaincontent"); + static final QName TYPE_AVM_LAYERED_CONTENT = + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "avmlayeredcontent"); + static final QName PROP_AVM_FILE_INDIRECTION = + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "avmfileindirection"); // title aspect static final QName ASPECT_TITLED = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "titled"); @@ -133,8 +139,8 @@ public interface ContentModel public final static QName PROP_EXPIRY_DATE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "expiryDate"); // version aspect - static final QName ASPECT_VERSIONABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "versionable"); - static final QName PROP_VERSION_LABEL = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "versionLabel"); + static final QName ASPECT_VERSIONABLE = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "versionable"); + static final QName PROP_VERSION_LABEL = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "versionLabel"); static final QName PROP_INITIAL_VERSION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "initialVersion"); static final QName PROP_AUTO_VERSION = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "autoVersion"); @@ -144,6 +150,12 @@ public interface ContentModel /** child association type supported by {@link #TYPE_FOLDER} */ static final QName ASSOC_CONTAINS = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "contains"); static final QName TYPE_AVM_FOLDER = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "avmfolder"); + static final QName TYPE_AVM_PLAIN_FOLDER = + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "avmplainfolder"); + static final QName TYPE_AVM_LAYERED_FOLDER = + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "avmlayeredfolder"); + static final QName PROP_AVM_DIR_INDIRECTION = + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "avmdirindirection"); // person static final QName TYPE_PERSON = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "person"); diff --git a/source/java/org/alfresco/repo/avm/AVMInterpreter.java b/source/java/org/alfresco/repo/avm/AVMInterpreter.java index 8b1f4a070a..149fb3cc21 100644 --- a/source/java/org/alfresco/repo/avm/AVMInterpreter.java +++ b/source/java/org/alfresco/repo/avm/AVMInterpreter.java @@ -437,48 +437,6 @@ public class AVMInterpreter AVMNodeDescriptor ca = fService.getCommonAncestor(left, right); out.println(ca); } - else if (command[0].equals("mount")) - { - if (command.length != 5) - { - return "Syntax Error."; - } - int version = Integer.parseInt(command[1]); - String avmPath = command[2]; - String alfPath = command[3]; - String mountName = command[4]; - String [] components = alfPath.split("/"); - NodeRef nodeRef = fNodeService.getRootNode(new StoreRef(StoreRef.PROTOCOL_WORKSPACE, "SpacesStore")); - for (String name : components) - { - fgLogger.error(name); - List children = - fNodeService.getChildAssocs(nodeRef); - for (ChildAssociationRef child : children) - { - fgLogger.error(" " + child.getQName()); - if (child.getQName().getLocalName().equals(name)) - { - nodeRef = child.getChildRef(); - break; - } - } - } - Map properties = - new HashMap(); - properties.put(ContentModel.PROP_NAME, mountName); - ChildAssociationRef childRef = - fNodeService.createNode(nodeRef, ContentModel.ASSOC_CONTAINS, - QName.createQName(NamespaceService.APP_MODEL_1_0_URI, mountName), - ContentModel.TYPE_FOLDER, - properties); - properties.clear(); - properties.put(ContentModel.PROP_MOUNTPOINT, - AVMNodeConverter.ToNodeRef(version, avmPath)); - fNodeService.addAspect(childRef.getChildRef(), - ContentModel.ASPECT_MOUNTED, - properties); - } else { return "Syntax Error."; diff --git a/source/java/org/alfresco/repo/avm/AVMNodeService.java b/source/java/org/alfresco/repo/avm/AVMNodeService.java index 41ea718498..281f578bd7 100644 --- a/source/java/org/alfresco/repo/avm/AVMNodeService.java +++ b/source/java/org/alfresco/repo/avm/AVMNodeService.java @@ -268,16 +268,36 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi // Do the creates for supported types, or error out. try { - if (nodeTypeQName.equals(ContentModel.TYPE_AVM_FOLDER) || + if (nodeTypeQName.equals(ContentModel.TYPE_AVM_PLAIN_FOLDER) || nodeTypeQName.equals(ContentModel.TYPE_FOLDER)) { fAVMService.createDirectory(avmPath, nodeName); } - else if (nodeTypeQName.equals(ContentModel.TYPE_AVM_CONTENT) + else if (nodeTypeQName.equals(ContentModel.TYPE_AVM_PLAIN_CONTENT) ||nodeTypeQName.equals(ContentModel.TYPE_CONTENT)) { fAVMService.createFile(avmPath, nodeName); } + else if (nodeTypeQName.equals(ContentModel.TYPE_AVM_LAYERED_CONTENT)) + { + NodeRef indirection = (NodeRef)properties.get(ContentModel.PROP_AVM_FILE_INDIRECTION); + if (indirection == null) + { + throw new InvalidTypeException("No Indirection Property", nodeTypeQName); + } + Object [] indVersionPath = AVMNodeConverter.ToAVMVersionPath(indirection); + fAVMService.createLayeredFile((String)indVersionPath[1], avmPath, nodeName); + } + else if (nodeTypeQName.equals(ContentModel.TYPE_AVM_LAYERED_FOLDER)) + { + NodeRef indirection = (NodeRef)properties.get(ContentModel.PROP_AVM_DIR_INDIRECTION); + if (indirection == null) + { + throw new InvalidTypeException("No Indirection Property.", nodeTypeQName); + } + Object [] indVersionPath = AVMNodeConverter.ToAVMVersionPath(indirection); + fAVMService.createLayeredDirectory((String)indVersionPath[1], avmPath, nodeName); + } else { throw new InvalidTypeException("Invalid node type for AVM.", nodeTypeQName); @@ -450,14 +470,23 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi { AVMNodeDescriptor desc = fAVMService.lookup((Integer)avmVersionPath[0], (String)avmVersionPath[1]); - if (desc.isDirectory()) + if (desc.isPlainDirectory()) { - return ContentModel.TYPE_AVM_FOLDER; + return ContentModel.TYPE_AVM_PLAIN_FOLDER; + } + else if (desc.isPlainFile()) + { + return ContentModel.TYPE_AVM_PLAIN_CONTENT; + } + else if (desc.isLayeredDirectory()) + { + return ContentModel.TYPE_AVM_LAYERED_FOLDER; } else { - return ContentModel.TYPE_AVM_CONTENT; + return ContentModel.TYPE_AVM_LAYERED_CONTENT; } + } catch (AVMNotFoundException e) { @@ -845,6 +874,16 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi result.put(ContentModel.PROP_NODE_DBID, new Long(desc.getId())); result.put(ContentModel.PROP_STORE_PROTOCOL, "avm"); result.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier()); + if (desc.isLayeredDirectory()) + { + result.put(ContentModel.PROP_AVM_DIR_INDIRECTION, + AVMNodeConverter.ToNodeRef(-1, desc.getIndirection())); + } + if (desc.isLayeredFile()) + { + result.put(ContentModel.PROP_AVM_FILE_INDIRECTION, + AVMNodeConverter.ToNodeRef(-1, desc.getIndirection())); + } if (desc.isFile()) { try @@ -969,6 +1008,22 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi { return nodeRef.getStoreRef().getIdentifier(); } + else if (qName.equals(ContentModel.PROP_AVM_DIR_INDIRECTION)) + { + if (desc.isLayeredDirectory()) + { + return AVMNodeConverter.ToNodeRef(-1, desc.getIndirection()); + } + return null; + } + else if (qName.equals(ContentModel.PROP_AVM_FILE_INDIRECTION)) + { + if (desc.isLayeredFile()) + { + return AVMNodeConverter.ToNodeRef(-1, desc.getIndirection()); + } + return null; + } else { fgLogger.error("Invalid Built In Property: " + qName); @@ -1002,14 +1057,17 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi Map values = new HashMap(); for (QName qName : properties.keySet()) { - // TODO This is until modification of built-in properties // For AVM nodes is in place. if (isBuiltInProperty(qName)) { if (qName.equals(ContentModel.PROP_CONTENT)) { - fAVMService.setContentData((String)avmVersionPath[1], - (ContentData)properties.get(qName)); + AVMNodeDescriptor desc = fAVMService.lookup(-1, (String)avmVersionPath[1]); + if (desc.isPlainFile()) + { + fAVMService.setContentData((String)avmVersionPath[1], + (ContentData)properties.get(qName)); + } } } values.put(qName, new PropertyValue(null, properties.get(qName))); @@ -1036,7 +1094,9 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi ContentModel.PROP_NODE_UUID, ContentModel.PROP_NODE_DBID, ContentModel.PROP_STORE_PROTOCOL, - ContentModel.PROP_STORE_IDENTIFIER + ContentModel.PROP_STORE_IDENTIFIER, + ContentModel.PROP_AVM_FILE_INDIRECTION, + ContentModel.PROP_AVM_DIR_INDIRECTION }; /** diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTest.java b/source/java/org/alfresco/repo/avm/AVMServiceTest.java index e6c7e40106..e4ecdc2504 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceTest.java @@ -21,6 +21,7 @@ import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.InputStreamReader; import java.io.PrintStream; +import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -41,8 +42,10 @@ import org.alfresco.service.cmr.avm.AVMStoreDescriptor; import org.alfresco.service.cmr.avm.LayeringDescriptor; import org.alfresco.service.cmr.avm.VersionDescriptor; import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.PermissionService; +import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.transaction.TransactionService; @@ -2304,7 +2307,30 @@ public class AVMServiceTest extends AVMServiceTestBase setupBasicTree(); FileFolderService ffs = (FileFolderService)fContext.getBean("FileFolderService"); assertTrue(ffs.create(AVMNodeConverter.ToNodeRef(-1, "main:/a/b/c"), - "banana", ContentModel.TYPE_AVM_CONTENT) != null); + "banana", ContentModel.TYPE_AVM_PLAIN_CONTENT) != null); + assertTrue(ffs.create(AVMNodeConverter.ToNodeRef(-1, "main:/a/b/c"), + "apples", ContentModel.TYPE_AVM_PLAIN_FOLDER) != null); + NodeService ns = (NodeService)fContext.getBean("NodeService"); + Map properties = new HashMap(); + properties.put(ContentModel.PROP_AVM_DIR_INDIRECTION, + AVMNodeConverter.ToNodeRef(-1, "main:/a")); + assertTrue(ns.createNode(AVMNodeConverter.ToNodeRef(-1, "main:/"), + ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "layer"), + ContentModel.TYPE_AVM_LAYERED_FOLDER, + properties) != null); + assertTrue(ns.getProperty(AVMNodeConverter.ToNodeRef(-1, "main:/layer"), + ContentModel.PROP_AVM_DIR_INDIRECTION) != null); + properties.clear(); + properties.put(ContentModel.PROP_AVM_FILE_INDIRECTION, + AVMNodeConverter.ToNodeRef(-1, "main:/a/b/c/foo")); + assertTrue(ns.createNode(AVMNodeConverter.ToNodeRef(-1, "main:/"), + ContentModel.ASSOC_CONTAINS, + QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "foo"), + ContentModel.TYPE_AVM_LAYERED_CONTENT, + properties) != null); + assertTrue(ns.getProperty(AVMNodeConverter.ToNodeRef(-1, "main:/foo"), + ContentModel.PROP_AVM_FILE_INDIRECTION) != null); fService.createSnapshot("main"); System.out.println(recursiveList("main", -1, true)); } diff --git a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java index ca5706fc2d..92a4abbf4f 100644 --- a/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java @@ -31,7 +31,6 @@ import java.util.Stack; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; -import org.alfresco.repo.avm.AVMContext; import org.alfresco.repo.domain.ChildAssoc; import org.alfresco.repo.domain.Node; import org.alfresco.repo.domain.NodeAssoc; @@ -253,20 +252,6 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl Assert.notNull(assocTypeQName); Assert.notNull(assocQName); - // get the parent node - Node parentNode = getNodeNotNull(parentRef); - - if (parentNode.getAspects().contains(ContentModel.ASPECT_MOUNTED)) - { - NodeRef mounted = (NodeRef)parentNode.getProperties().get(ContentModel.PROP_MOUNTPOINT). - getValue(DataTypeDefinition.NODE_REF); - return AVMContext.fgInstance.getNodeService().createNode(mounted, - assocTypeQName, - assocQName, - nodeTypeQName, - properties); - } - // null property map is allowed if (properties == null) { @@ -317,6 +302,9 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl propertiesAfter = setPropertiesImpl(childNode, properties); } + // get the parent node + Node parentNode = getNodeNotNull(parentRef); + // create the association ChildAssoc childAssoc = nodeDaoService.newChildAssoc( parentNode, @@ -724,15 +712,6 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl { Node parentNode = getNodeNotNull(parentRef); - if (parentNode.getAspects().contains(ContentModel.ASPECT_MOUNTED)) - { - NodeRef mounted = - (NodeRef)parentNode.getProperties().get(ContentModel.PROP_MOUNTPOINT). - getValue(DataTypeDefinition.NODE_REF); - AVMContext.fgInstance.getNodeService().removeChild(mounted, childRef); - return; - } - Node childNode = getNodeNotNull(childRef); Long childNodeId = childNode.getId(); @@ -1017,14 +996,6 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl public List getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern, QNamePattern qnamePattern) { Node node = getNodeNotNull(nodeRef); - if (node.getAspects().contains(ContentModel.ASPECT_MOUNTED)) - { - NodeRef mounted = (NodeRef)node.getProperties().get(ContentModel.PROP_MOUNTPOINT). - getValue(DataTypeDefinition.NODE_REF); - return AVMContext.fgInstance.getNodeService().getChildAssocs(mounted, - typeQNamePattern, - qnamePattern); - } // get the assocs pointing from it Collection childAssocRefs = nodeDaoService.getChildAssocRefs(node); // shortcut if there are no assocs @@ -1061,14 +1032,6 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl public NodeRef getChildByName(NodeRef nodeRef, QName assocTypeQName, String childName) { Node node = getNodeNotNull(nodeRef); - if (node.getAspects().contains(ContentModel.ASPECT_MOUNTED)) - { - NodeRef mounted = (NodeRef)node.getProperties().get(ContentModel.PROP_MOUNTPOINT). - getValue(DataTypeDefinition.NODE_REF); - return AVMContext.fgInstance.getNodeService().getChildByName(mounted, - assocTypeQName, - childName); - } ChildAssoc childAssoc = nodeDaoService.getChildAssoc(node, assocTypeQName, childName); if (childAssoc != null) { diff --git a/source/java/org/alfresco/service/cmr/avmsync/AVMDifference.java b/source/java/org/alfresco/service/cmr/avmsync/AVMDifference.java new file mode 100644 index 0000000000..2e3acf20e1 --- /dev/null +++ b/source/java/org/alfresco/service/cmr/avmsync/AVMDifference.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ + +package org.alfresco.service.cmr.avmsync; + +/** + * Represents the difference between corresponding nodes + * in parallel avm node trees. It it indicates for the difference + * whether the source is older, newer, or in conflict with the destination. + * @author britt + */ +public class AVMDifference +{ +} diff --git a/source/java/org/alfresco/service/cmr/avmsync/AvmSyncService.java b/source/java/org/alfresco/service/cmr/avmsync/AvmSyncService.java new file mode 100644 index 0000000000..0f91cc96ea --- /dev/null +++ b/source/java/org/alfresco/service/cmr/avmsync/AvmSyncService.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ + +package org.alfresco.service.cmr.avmsync; + +import java.util.List; + +/** + * This service handles comparisons and synchronizations between + * corresponding avm node trees. + * @author britt + */ +public interface AvmSyncService +{ + /** + * Get a difference list between two corresponding node trees. + * @param srcVersion The version id for the source tree. + * @param srcPath The avm path to the source tree. + * @param dstVersion The version id for the destination tree. + * @param dstPath The avm path to the destination tree. + * @return A List of AVMDifference structs which can be used for + * the update operation. + */ + public List compare(int srcVersion, String srcPath, + int dstVersion, String dstPath); + + /** + * Updates the destination nodes in the AVMDifferences + * with the source nodes. Normally any conflicts or cases in + * which the source of an AVMDifference is older than the destination + * will cause the transaction to roll back. + * @param diffList A List of AVMDifference structs. + * @param ignoreConflicts If this is true the update will skip those + * AVMDifferences which are in conflict or for which the source is older than + * the destination. + * @param overrideConflicts If this is true the update will override conflicting + * AVMDifferences and replace the destination with the conflicting source. + * @param overrideOlder If this is true the update will override AVMDifferences + * in which the source is older than the destination and overwrite the destination. + */ + public void update(List diffList, boolean ignoreConflicts, + boolean overrideConflicts, boolean overrideOlder); + + /** + * Flattens a layer so that all all nodes under and including + * layerPath become translucent to any nodes in the + * corresponding location under and including underlyingPath + * that are the same version. + * @param layerPath The overlying layer path. + * @param underlyingPath The underlying path. + */ + public void flatten(String layerPath, String underlyingPath); + + /** + * Takes a layer, deletes it and recreates it pointing at the same underlying + * node. Any changes in the layer are lost (except to history if the layer has been + * snapshotted.) + * @param layerPath + */ + public void resetLayer(String layerPath); +}