From 8a95b09b986bdb7c6993026238b05d998f15d0c2 Mon Sep 17 00:00:00 2001 From: Britt Park Date: Sun, 10 Sep 2006 17:20:35 +0000 Subject: [PATCH] Added new AVM node type DeletedNode (aka, ghost, tombstone), a marker node for a node that has been deleted in a version. This makes tree comparisons easier by resolving the cases in which one wants to know whether a deletions is more or less recent than another version of a node. Along the way got rid of DeletedChild and friends including a table in the schema, since DeletedNode takes on all the work that it performed. Deleted two illegally named files in Virgin content. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3748 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/avm-services-context.xml | 9 - .../org/alfresco/repo/avm/AVMContext.java | 13 -- .../org/alfresco/repo/avm/AVMNodeImpl.java | 3 - .../org/alfresco/repo/avm/AVMNodeService.java | 30 +++- .../org/alfresco/repo/avm/AVMNodeType.java | 1 + .../org/alfresco/repo/avm/AVMRepository.java | 2 +- .../org/alfresco/repo/avm/AVMServiceImpl.java | 1 - .../org/alfresco/repo/avm/AVMServiceTest.java | 88 +++++++++ .../org/alfresco/repo/avm/AVMStoreImpl.java | 2 +- .../java/org/alfresco/repo/avm/AVMTester.java | 5 - .../alfresco/repo/avm/DeletedChildDAO.java | 60 ------- .../alfresco/repo/avm/DeletedChildImpl.java | 147 --------------- .../{DeletedChild.java => DeletedNode.java} | 15 +- .../alfresco/repo/avm/DeletedNodeImpl.java | 167 ++++++++++++++++++ .../org/alfresco/repo/avm/DirectoryNode.java | 3 +- .../repo/avm/LayeredDirectoryNode.java | 8 - .../repo/avm/LayeredDirectoryNodeImpl.java | 138 +++++++-------- .../org/alfresco/repo/avm/OrphanReaper.java | 5 - .../repo/avm/PlainDirectoryNodeImpl.java | 30 +++- .../alfresco/repo/avm/hibernate/AVM.hbm.xml | 35 +--- .../hibernate/DeletedChildDAOHibernate.java | 103 ----------- 21 files changed, 382 insertions(+), 483 deletions(-) delete mode 100644 source/java/org/alfresco/repo/avm/DeletedChildDAO.java delete mode 100644 source/java/org/alfresco/repo/avm/DeletedChildImpl.java rename source/java/org/alfresco/repo/avm/{DeletedChild.java => DeletedNode.java} (64%) create mode 100644 source/java/org/alfresco/repo/avm/DeletedNodeImpl.java delete mode 100644 source/java/org/alfresco/repo/avm/hibernate/DeletedChildDAOHibernate.java diff --git a/config/alfresco/avm-services-context.xml b/config/alfresco/avm-services-context.xml index 24ae6c6266..d597028a3a 100644 --- a/config/alfresco/avm-services-context.xml +++ b/config/alfresco/avm-services-context.xml @@ -72,12 +72,6 @@ - - - - - - @@ -118,9 +112,6 @@ - - - diff --git a/source/java/org/alfresco/repo/avm/AVMContext.java b/source/java/org/alfresco/repo/avm/AVMContext.java index 39e572e102..355b61f6f0 100644 --- a/source/java/org/alfresco/repo/avm/AVMContext.java +++ b/source/java/org/alfresco/repo/avm/AVMContext.java @@ -65,11 +65,6 @@ public class AVMContext implements ApplicationContextAware */ public MergeLinkDAO fMergeLinkDAO; - /** - * The DeletedChildDAO. - */ - public DeletedChildDAO fDeletedChildDAO; - /** * The AVMNodePropertyDAO */ @@ -143,14 +138,6 @@ public class AVMContext implements ApplicationContextAware fChildEntryDAO = childEntryDAO; } - /** - * @param deletedChildDAO the fDeletedChildDAO to set - */ - public void setDeletedChildDAO(DeletedChildDAO deletedChildDAO) - { - fDeletedChildDAO = deletedChildDAO; - } - /** * @param historyLinkDAO the fHistoryLinkDAO to set */ diff --git a/source/java/org/alfresco/repo/avm/AVMNodeImpl.java b/source/java/org/alfresco/repo/avm/AVMNodeImpl.java index 526cfafe83..077250713d 100644 --- a/source/java/org/alfresco/repo/avm/AVMNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMNodeImpl.java @@ -21,12 +21,9 @@ import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; -import org.alfresco.repo.domain.DbAccessControlEntry; import org.alfresco.repo.domain.DbAccessControlList; import org.alfresco.repo.domain.PropertyValue; -import org.alfresco.repo.domain.hibernate.DbAccessControlListImpl; import org.alfresco.service.namespace.QName; /** diff --git a/source/java/org/alfresco/repo/avm/AVMNodeService.java b/source/java/org/alfresco/repo/avm/AVMNodeService.java index 38a0527395..41ea718498 100644 --- a/source/java/org/alfresco/repo/avm/AVMNodeService.java +++ b/source/java/org/alfresco/repo/avm/AVMNodeService.java @@ -567,7 +567,7 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi for (AspectDefinition def : defaultAspectDefs) { invokeBeforeAddAspect(nodeRef, def.getName()); - fAVMService.addAspect(path, def.getName()); + addAspect(nodeRef, def.getName(), Collections.emptyMap()); addDefaultPropertyValues(def, properties); invokeOnAddAspect(nodeRef, def.getName()); // recurse @@ -659,7 +659,7 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi } } - private static QName [] fgBuiltinAspects = new QName[] { ContentModel.ASPECT_AUDITABLE, + private static QName [] fgBuiltinAspects = new QName[] { ContentModel.ASPECT_AUDITABLE, ContentModel.ASPECT_REFERENCEABLE }; private boolean isBuiltinAspect(QName aspectQName) @@ -841,6 +841,10 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi result.put(ContentModel.PROP_MODIFIER, desc.getLastModifier()); result.put(ContentModel.PROP_OWNER, desc.getOwner()); result.put(ContentModel.PROP_NAME, desc.getName()); + result.put(ContentModel.PROP_NODE_UUID, "UNKNOWN"); + result.put(ContentModel.PROP_NODE_DBID, new Long(desc.getId())); + result.put(ContentModel.PROP_STORE_PROTOCOL, "avm"); + result.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier()); if (desc.isFile()) { try @@ -949,6 +953,22 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi { return desc.getName(); } + else if (qName.equals(ContentModel.PROP_NODE_UUID)) + { + return "UNKNOWN"; + } + else if (qName.equals(ContentModel.PROP_NODE_DBID)) + { + return new Long(desc.getId()); + } + else if (qName.equals(ContentModel.PROP_STORE_PROTOCOL)) + { + return "avm"; + } + else if (qName.equals(ContentModel.PROP_STORE_IDENTIFIER)) + { + return nodeRef.getStoreRef().getIdentifier(); + } else { fgLogger.error("Invalid Built In Property: " + qName); @@ -1012,7 +1032,11 @@ public class AVMNodeService extends AbstractNodeServiceImpl implements NodeServi ContentModel.PROP_MODIFIER, ContentModel.PROP_OWNER, ContentModel.PROP_CONTENT, - ContentModel.PROP_NAME + ContentModel.PROP_NAME, + ContentModel.PROP_NODE_UUID, + ContentModel.PROP_NODE_DBID, + ContentModel.PROP_STORE_PROTOCOL, + ContentModel.PROP_STORE_IDENTIFIER }; /** diff --git a/source/java/org/alfresco/repo/avm/AVMNodeType.java b/source/java/org/alfresco/repo/avm/AVMNodeType.java index 58444a3991..e8d3e64eb4 100644 --- a/source/java/org/alfresco/repo/avm/AVMNodeType.java +++ b/source/java/org/alfresco/repo/avm/AVMNodeType.java @@ -27,4 +27,5 @@ public interface AVMNodeType public static final int LAYERED_FILE = 1; public static final int PLAIN_DIRECTORY = 2; public static final int LAYERED_DIRECTORY = 3; + public static final int DELETED_NODE = 4; } diff --git a/source/java/org/alfresco/repo/avm/AVMRepository.java b/source/java/org/alfresco/repo/avm/AVMRepository.java index ec8212479d..4357c10459 100644 --- a/source/java/org/alfresco/repo/avm/AVMRepository.java +++ b/source/java/org/alfresco/repo/avm/AVMRepository.java @@ -369,7 +369,7 @@ public class AVMRepository { dstNode = new PlainFileNodeImpl((PlainFileNode)srcNode, dstRepo); } - srcDir.removeChild(srcName); + srcDir.removeChild(sPath, srcName); srcDir.updateModTime(); dstNode.setVersionID(dstRepo.getNextVersionID()); dstDir.putChild(dstName, dstNode); diff --git a/source/java/org/alfresco/repo/avm/AVMServiceImpl.java b/source/java/org/alfresco/repo/avm/AVMServiceImpl.java index 6da14357f3..b1aaadc620 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceImpl.java @@ -28,7 +28,6 @@ import java.util.Map; import java.util.SortedMap; import org.alfresco.repo.avm.AVMRepository; -import org.alfresco.repo.domain.DbAccessControlList; import org.alfresco.repo.domain.PropertyValue; import org.alfresco.service.cmr.avm.AVMBadArgumentException; import org.alfresco.service.cmr.avm.AVMException; diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTest.java b/source/java/org/alfresco/repo/avm/AVMServiceTest.java index 3b73a89a72..393a8a5978 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceTest.java @@ -32,8 +32,11 @@ import java.util.TreeMap; import org.alfresco.model.ContentModel; import org.alfresco.repo.avm.util.BulkLoader; import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.transaction.TransactionUtil; +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.AVMService; import org.alfresco.service.cmr.avm.AVMStoreDescriptor; import org.alfresco.service.cmr.avm.LayeringDescriptor; import org.alfresco.service.cmr.avm.VersionDescriptor; @@ -41,6 +44,7 @@ import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.security.AccessPermission; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; +import org.alfresco.service.transaction.TransactionService; /** * Big test of AVM behavior. @@ -2310,4 +2314,88 @@ public class AVMServiceTest extends AVMServiceTestBase fail(); } } + + /** + * Test overwriting without snapshots in between. + */ + public void testOverwrite() + { + try + { + setupBasicTree(); + class TxnWork implements TransactionUtil.TransactionWork + { + public Object doWork() throws Exception + { + AVMService service = (AVMService)fContext.getBean("avmService"); + service.createLayeredDirectory("main:/a", "main:/", "layer"); + // Modify something in an ordinary directory 3 times. + service.getFileOutputStream("main:/a/b/c/foo").close(); + service.getFileOutputStream("main:/a/b/c/foo").close(); + service.getFileOutputStream("main:/a/b/c/foo").close(); + service.createFile("main:/a/b/c", "pint").close(); + service.createFile("main:/a/b/c", "quart").close(); + // Modify another file in the same directory. + service.getFileOutputStream("main:/a/b/c/bar").close(); + service.getFileOutputStream("main:/a/b/c/bar").close(); + service.lookup(-1, "main:/a/b/c"); + service.createFile("main:/a/b/c", "figment").close(); + // Repeat in a layer. + service.getFileOutputStream("main:/layer/b/c/foo").close(); + service.getFileOutputStream("main:/layer/b/c/foo").close(); + service.getFileOutputStream("main:/layer/b/c/foo").close(); + service.createFile("main:/layer/b/c", "gallon").close(); + service.createFile("main:/layer/b/c", "dram").close(); + service.getFileOutputStream("main:/layer/b/c/bar").close(); + service.getFileOutputStream("main:/layer/b/c/bar").close(); + try + { + service.lookup(-1, "main:/a/b/c/froo"); + } + catch (AVMException ae) + { + // Do nothing. + } + service.createDirectory("main:/a/b/c", "froo"); + service.createFile("main:/a/b/c/froo", "franistan").close(); + try + { + service.lookup(-1, "main:/layer/b/c/groo"); + } + catch (AVMException ae) + { + // Do nothing. + } + service.createDirectory("main:/layer/b/c", "groo"); + service.createFile("main:/layer/b/c/groo", "granistan").close(); + return null; + } + } + TransactionUtil.executeInUserTransaction((TransactionService)fContext.getBean("transactionComponent"), + new TxnWork()); + } + catch (Exception e) + { + e.printStackTrace(System.err); + fail(); + } + } + + /** + * Test creating a file over a ghost. + */ + public void testCreateOverDeleted() + { + try + { + setupBasicTree(); + fService.removeNode("main:/a/b/c", "foo"); + fService.createFile("main:/a/b/c", "foo").close(); + } + catch (Exception e) + { + e.printStackTrace(System.err); + fail(); + } + } } diff --git a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java index 7e93c87443..3ba980b97b 100644 --- a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java @@ -446,7 +446,7 @@ public class AVMStoreImpl implements AVMStore, Serializable { throw new AVMNotFoundException("Does not exist: " + name); } - dir.removeChild(name); + dir.removeChild(lPath, name); dir.updateModTime(); } diff --git a/source/java/org/alfresco/repo/avm/AVMTester.java b/source/java/org/alfresco/repo/avm/AVMTester.java index 5422e66817..023e8d4248 100644 --- a/source/java/org/alfresco/repo/avm/AVMTester.java +++ b/source/java/org/alfresco/repo/avm/AVMTester.java @@ -18,7 +18,6 @@ package org.alfresco.repo.avm; import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.util.ArrayList; @@ -29,13 +28,9 @@ import java.util.Random; import java.util.Set; import org.alfresco.error.AlfrescoRuntimeException; -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.AVMService; -import org.alfresco.service.cmr.avm.AVMWrongTypeException; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.hibernate.HibernateException; import org.springframework.dao.ConcurrencyFailureException; diff --git a/source/java/org/alfresco/repo/avm/DeletedChildDAO.java b/source/java/org/alfresco/repo/avm/DeletedChildDAO.java deleted file mode 100644 index 635aa83cc6..0000000000 --- a/source/java/org/alfresco/repo/avm/DeletedChildDAO.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2006 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ - -package org.alfresco.repo.avm; - -import java.util.List; - -/** - * DAO for DeletedChildren. - * @author britt - */ -public interface DeletedChildDAO -{ - /** - * Save an unsaved DeletedChild. - * @param child The DeletedChild to be saved. - */ - public void save(DeletedChild child); - - /** - * Delete one. - * @param child The one to delete. - */ - public void delete(DeletedChild child); - - /** - * Delete all belonging to the given parent. - * @param parent The parent. - */ - public void deleteByParent(AVMNode parent); - - /** - * Get by name and parent. - * @param name The name of the deleted entry. - * @param parent The parent. - * @return A DeletedChild or null if not found. - */ - public DeletedChild getByNameParent(String name, LayeredDirectoryNode parent); - - /** - * Get all the deleted children of a given parent. - * @param parent The parent. - * @return A List of DeletedChildren. - */ - public List getByParent(LayeredDirectoryNode parent); -} diff --git a/source/java/org/alfresco/repo/avm/DeletedChildImpl.java b/source/java/org/alfresco/repo/avm/DeletedChildImpl.java deleted file mode 100644 index 84c9770b63..0000000000 --- a/source/java/org/alfresco/repo/avm/DeletedChildImpl.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2006 Alfresco, Inc. - * - * Licensed under the Mozilla Public License version 1.1 - * with a permitted attribution clause. You may obtain a - * copy of the License at - * - * http://www.alfresco.org/legal/license.txt - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the - * License. - */ - -package org.alfresco.repo.avm; - -import java.io.Serializable; - -/** - * Represents a deleted child in a layered directory. - * @author britt - */ -class DeletedChildImpl implements DeletedChild, Serializable -{ - private static final long serialVersionUID = 4997060636280774719L; - - /** - * The Primary Key. - */ - private Long fID; - - /** - * The name of the deleted child. - */ - private String fName; - - /** - * The parent directory. - */ - private LayeredDirectoryNode fParent; - - /** - * Default constructor. For Hibernate. - */ - protected DeletedChildImpl() - { - } - - /** - * Create a new one. - * @param name - * @param parent - */ - public DeletedChildImpl(String name, - LayeredDirectoryNode parent) - { - fName = name; - fParent = parent; - } - - /** - * Set the name of the deleted child. For Hibernate. - * @param name - */ - protected void setName(String name) - { - fName = name; - } - - /** - * Get the name of the deleted child. - * @return The name. - */ - public String getName() - { - return fName; - } - - /** - * Set the parent directory. - * @param parent - */ - protected void setParent(LayeredDirectoryNode parent) - { - fParent = parent; - } - - /** - * Get the parent of the deleted child. - * @return The parent. - */ - public LayeredDirectoryNode getParent() - { - return fParent; - } - - /** - * Equality in the database entity sense. - * @param obj - * @return Equality. - */ - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (!(obj instanceof DeletedChild)) - { - return false; - } - DeletedChild dc = (DeletedChild)obj; - return fParent.equals(dc.getParent()) && fName.equals(dc.getName()); - } - - /** - * Get a hash code. - * @return A hash code. - */ - @Override - public int hashCode() - { - return fParent.hashCode() + fName.hashCode(); - } - - /** - * Set the primary key. (For Hibernate) - * @param id The primary key. - */ - protected void setId(Long id) - { - fID = id; - } - - /** - * Get the primary key. (For Hibernate) - * @return The primary key. - */ - protected Long getId() - { - return fID; - } -} diff --git a/source/java/org/alfresco/repo/avm/DeletedChild.java b/source/java/org/alfresco/repo/avm/DeletedNode.java similarity index 64% rename from source/java/org/alfresco/repo/avm/DeletedChild.java rename to source/java/org/alfresco/repo/avm/DeletedNode.java index 73e8206a7d..c18e563442 100644 --- a/source/java/org/alfresco/repo/avm/DeletedChild.java +++ b/source/java/org/alfresco/repo/avm/DeletedNode.java @@ -18,20 +18,9 @@ package org.alfresco.repo.avm; /** - * Interface to a deleted directory entry in a layered directory. + * Represents a node that has been deleted. * @author britt */ -public interface DeletedChild +public interface DeletedNode extends AVMNode { - /** - * Get the name of the deleted child. - * @return The name. - */ - public String getName(); - - /** - * Get the parent of this deleted child - * @return The parent. - */ - public LayeredDirectoryNode getParent(); } diff --git a/source/java/org/alfresco/repo/avm/DeletedNodeImpl.java b/source/java/org/alfresco/repo/avm/DeletedNodeImpl.java new file mode 100644 index 0000000000..39658e8c2e --- /dev/null +++ b/source/java/org/alfresco/repo/avm/DeletedNodeImpl.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2006 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ + +package org.alfresco.repo.avm; + +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; + +/** + * Place holder for a deleted node. + * @author britt + */ +public class DeletedNodeImpl extends AVMNodeImpl implements DeletedNode +{ + private static final long serialVersionUID = 7283526790174482993L; + + /** + * For Hibernate's use. + */ + protected DeletedNodeImpl() + { + } + + /** + * Create a new one from scratch. + * @param id The node id. + * @param store The store it's being created in. + */ + public DeletedNodeImpl(long id, + AVMStore store) + { + super(id, store); + } + + /** + * This should never be called. + */ + public AVMNode copy(Lookup lPath) + { + assert false; + return null; + } + + /** + * Get a descriptor. + * @param lPath The Lookup to this node's parent. + * @param name The name of this node. + * @return An AVMNodeDescriptor + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath, String name) + { + BasicAttributes attrs = getBasicAttributes(); + String path = lPath.getRepresentedPath(); + if (path.endsWith("/")) + { + path = path + name; + } + else + { + path = path + "/" + name; + } + return new AVMNodeDescriptor(path, + name, + AVMNodeType.DELETED_NODE, + attrs.getCreator(), + attrs.getOwner(), + attrs.getLastModifier(), + attrs.getCreateDate(), + attrs.getModDate(), + attrs.getAccessDate(), + getId(), + getVersionID(), + null, + false, + -1, + false, + -1); + } + + /** + * Get a descriptor. + * @param lPath The full Lookup to this. + * @return An AVMNodeDescriptor. + */ + public AVMNodeDescriptor getDescriptor(Lookup lPath) + { + BasicAttributes attrs = getBasicAttributes(); + String path = lPath.getRepresentedPath(); + return new AVMNodeDescriptor(path, + path.substring(path.lastIndexOf("/") + 1), + AVMNodeType.DELETED_NODE, + attrs.getCreator(), + attrs.getOwner(), + attrs.getLastModifier(), + attrs.getCreateDate(), + attrs.getModDate(), + attrs.getAccessDate(), + getId(), + getVersionID(), + null, + false, + -1, + false, + -1); + } + + /** + * Get a descriptor. + * @param parentPath + * @param name + * @param parentIndirection Ignored. + * @return An AVMNodeDescriptor. + */ + public AVMNodeDescriptor getDescriptor(String parentPath, String name, String parentIndirection) + { + BasicAttributes attrs = getBasicAttributes(); + String path = parentPath.endsWith("/") ? parentPath + name : parentPath + "/" + name; + return new AVMNodeDescriptor(path, + name, + AVMNodeType.DELETED_NODE, + attrs.getCreator(), + attrs.getOwner(), + attrs.getLastModifier(), + attrs.getCreateDate(), + attrs.getModDate(), + attrs.getAccessDate(), + getId(), + getVersionID(), + null, + false, + -1, + false, + -1); + } + + /** + * Get the type of this node. + * @return The AVMNodeType of this. + */ + public int getType() + { + return AVMNodeType.DELETED_NODE; + } + + /** + * Get a descriptive string representation. + * @param lPath The lookup we've been found through. + * @return A String representation. + */ + public String toString(Lookup lPath) + { + return "[DN:" + getId() + "]"; + } +} diff --git a/source/java/org/alfresco/repo/avm/DirectoryNode.java b/source/java/org/alfresco/repo/avm/DirectoryNode.java index a6558fdb8f..e7419d37a1 100644 --- a/source/java/org/alfresco/repo/avm/DirectoryNode.java +++ b/source/java/org/alfresco/repo/avm/DirectoryNode.java @@ -61,9 +61,10 @@ public interface DirectoryNode extends AVMNode /** * Remove a child directly. No copy is possible. + * @param lPath The lookup through which this node was reached. * @param name The name of the child to remove. */ - public void removeChild(String name); + public void removeChild(Lookup lPath, String name); /** * Get a directory listing. diff --git a/source/java/org/alfresco/repo/avm/LayeredDirectoryNode.java b/source/java/org/alfresco/repo/avm/LayeredDirectoryNode.java index 8176562d09..8f6b67882d 100644 --- a/source/java/org/alfresco/repo/avm/LayeredDirectoryNode.java +++ b/source/java/org/alfresco/repo/avm/LayeredDirectoryNode.java @@ -1,7 +1,5 @@ package org.alfresco.repo.avm; -import java.util.List; - /** * Interface for Layered Directories. * @author britt @@ -72,12 +70,6 @@ public interface LayeredDirectoryNode extends DirectoryNode, Layered */ public String getUnderlying(); - /** - * Get all deleted children for this directory. - * @return All deleted children. - */ - public List getDeleted(); - /** * Set the opacity of this. * @param opacity Whether this should be opaque, i.e. not see the things it diff --git a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java index 60aacf8e63..bc87b0a870 100644 --- a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java @@ -106,12 +106,6 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec child.getChild()); AVMContext.fgInstance.fChildEntryDAO.save(newChild); } - for (DeletedChild dc : other.getDeleted()) - { - DeletedChild newDel = new DeletedChildImpl(dc.getName(), - this); - AVMContext.fgInstance.fDeletedChildDAO.save(newDel); - } AVMContext.fgInstance.fAVMNodeDAO.flush(); copyProperties(other); copyAspects(other); @@ -291,11 +285,6 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec AVMContext.fgInstance.fAVMNodeDAO.flush(); AVMContext.fgInstance.fChildEntryDAO.save(entry); } - DeletedChild dc = getDeleted(name); - if (dc != null) - { - AVMContext.fgInstance.fDeletedChildDAO.delete(dc); - } } @@ -318,10 +307,10 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec public Map getListing(Lookup lPath) { // Get the base listing from the thing we indirect to. - Map baseListing = null; + Map listing = null; if (fOpacity) { - baseListing = new HashMap(); + listing = new HashMap(); } else { @@ -329,7 +318,7 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec { Lookup lookup = AVMRepository.GetInstance().lookupDirectory(-1, getUnderlying(lPath)); DirectoryNode dir = (DirectoryNode)lookup.getCurrentNode(); - baseListing = dir.getListing(lookup); + listing = dir.getListing(lookup); } catch (AVMException re) { @@ -338,22 +327,19 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec throw re; } // It's OK for an indirection to dangle. - baseListing = new HashMap(); + listing = new HashMap(); } } - // Filter the base listing by taking out anything in the deleted Set. - Map listing = new HashMap(); - for (String name : baseListing.keySet()) - { - if (getDeleted(name) != null) - { - continue; - } - listing.put(name, baseListing.get(name)); - } for (ChildEntry entry : AVMContext.fgInstance.fChildEntryDAO.getByParent(this)) { - listing.put(entry.getName(), entry.getChild()); + if (entry.getChild().getType() == AVMNodeType.DELETED_NODE) + { + listing.remove(entry.getName()); + } + else + { + listing.put(entry.getName(), entry.getChild()); + } } return listing; } @@ -368,7 +354,10 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec Map listing = new HashMap(); for (ChildEntry entry : AVMContext.fgInstance.fChildEntryDAO.getByParent(this)) { - listing.put(entry.getName(), entry.getChild()); + if (entry.getChild().getType() != AVMNodeType.DELETED_NODE) + { + listing.put(entry.getName(), entry.getChild()); + } } return listing; } @@ -408,19 +397,20 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec } } } - // Remove anything deleted in this layer. - List deleted = getDeleted(); - for (DeletedChild child : deleted) - { - baseListing.remove(child.getName()); - } List children = AVMContext.fgInstance.fChildEntryDAO.getByParent(this); for (ChildEntry child : children) { - baseListing.put(child.getName(), - child.getChild().getDescriptor(dir.getPath(), - child.getName(), - dir.getIndirection())); + if (child.getChild().getType() == AVMNodeType.DELETED_NODE) + { + baseListing.remove(child.getName()); + } + else + { + baseListing.put(child.getName(), + child.getChild().getDescriptor(dir.getPath(), + child.getName(), + dir.getIndirection())); + } } return baseListing; } @@ -431,11 +421,14 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec */ public List getDeletedNames() { - List deleted = getDeleted(); + List children = AVMContext.fgInstance.fChildEntryDAO.getByParent(this); List listing = new ArrayList(); - for (DeletedChild child : deleted) + for (ChildEntry entry : children) { - listing.add(child.getName()); + if (entry.getChild().getType() == AVMNodeType.DELETED_NODE) + { + listing.add(entry.getName()); + } } return listing; } @@ -451,14 +444,13 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec @SuppressWarnings("unchecked") public AVMNode lookupChild(Lookup lPath, String name, int version, boolean write) { - // If the name has been deleted quickly return. - if (getDeleted(name) != null) - { - return null; - } ChildEntry entry = AVMContext.fgInstance.fChildEntryDAO.getByNameParent(name, this); if (entry != null) { + if (entry.getChild().getType() == AVMNodeType.DELETED_NODE) + { + return null; + } return AVMNodeUnwrapper.Unwrap(entry.getChild()); } // Don't check our underlying directory if we are opaque. @@ -497,13 +489,13 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec { throw new AVMBadArgumentException("Illegal null argument."); } - if (getDeleted(name) != null) - { - return null; - } ChildEntry entry = AVMContext.fgInstance.fChildEntryDAO.getByNameParent(name, this); if (entry != null) { + if (entry.getChild().getType() == AVMNodeType.DELETED_NODE) + { + return null; + } return entry.getChild().getDescriptor(mine.getPath(), name, mine.getIndirection()); @@ -536,19 +528,33 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec /** * Directly remove a child. Do not COW. Do not pass go etc. + * @param lPath The lookup that arrived at this. * @param name The name of the child to remove. */ @SuppressWarnings("unchecked") - public void removeChild(String name) + public void removeChild(Lookup lPath, String name) { ChildEntry entry = AVMContext.fgInstance.fChildEntryDAO.getByNameParent(name, this); + AVMNode child = null; if (entry != null) { + child = entry.getChild(); + if (child.getType() == AVMNodeType.DELETED_NODE) + { + return; + } AVMContext.fgInstance.fChildEntryDAO.delete(entry); } - DeletedChild dc = new DeletedChildImpl(name, - this); - AVMContext.fgInstance.fDeletedChildDAO.save(dc); + else + { + child = lookupChild(lPath, name, -1, false); + } + AVMNode ghost = new DeletedNodeImpl(lPath.getAVMStore().getAVMRepository().issueID(), + lPath.getAVMStore()); + AVMContext.fgInstance.fAVMNodeDAO.save(ghost); + AVMContext.fgInstance.fAVMNodeDAO.flush(); + ghost.setAncestor(child); + this.putChild(name, ghost); } /** @@ -606,10 +612,10 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec */ public void uncover(Lookup lPath, String name) { - DeletedChild dc = getDeleted(name); - if (dc != null) + ChildEntry entry = AVMContext.fgInstance.fChildEntryDAO.getByNameParent(name, this); + if (entry != null) { - AVMContext.fgInstance.fDeletedChildDAO.delete(dc); + AVMContext.fgInstance.fChildEntryDAO.delete(entry); } } @@ -724,26 +730,6 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec fIndirection = indirection; } - /** - * Get the deleted child entry for a given name. - * @param name The name to look for. - * @return A DeletedChild object. - */ - @SuppressWarnings("unchecked") - private DeletedChild getDeleted(String name) - { - return AVMContext.fgInstance.fDeletedChildDAO.getByNameParent(name, this); - } - - /** - * Get all the deleted entries in this directory. - * @return A List of DeletedEntry objects. - */ - public List getDeleted() - { - return AVMContext.fgInstance.fDeletedChildDAO.getByParent(this); - } - /** * Does nothing because LayeredDirectoryNodes can't be roots. * @param isRoot diff --git a/source/java/org/alfresco/repo/avm/OrphanReaper.java b/source/java/org/alfresco/repo/avm/OrphanReaper.java index 716f83a972..e2707776da 100644 --- a/source/java/org/alfresco/repo/avm/OrphanReaper.java +++ b/source/java/org/alfresco/repo/avm/OrphanReaper.java @@ -313,11 +313,6 @@ public class OrphanReaper implements Runnable { // First get rid of all child entries for the node. AVMContext.fgInstance.fChildEntryDAO.deleteByParent(node); - if (node.getType() == AVMNodeType.LAYERED_DIRECTORY) - { - // More special work for layered directories. - AVMContext.fgInstance.fDeletedChildDAO.deleteByParent(node); - } } else if (node.getType() == AVMNodeType.PLAIN_FILE) { diff --git a/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java index 1b82300129..d255969eb0 100644 --- a/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java @@ -99,6 +99,10 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory List children = AVMContext.fgInstance.fChildEntryDAO.getByParent(this); for (ChildEntry child : children) { + if (child.getChild().getType() == AVMNodeType.DELETED_NODE) + { + continue; + } result.put(child.getName(), child.getChild()); } return result; @@ -129,6 +133,10 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory List children = AVMContext.fgInstance.fChildEntryDAO.getByParent(this); for (ChildEntry child : children) { + if (child.getChild().getType() == AVMNodeType.DELETED_NODE) + { + continue; + } result.put(child.getName(), child.getChild().getDescriptor(dir.getPath(), child.getName(), dir.getIndirection())); } @@ -155,13 +163,13 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory @SuppressWarnings("unchecked") public AVMNode lookupChild(Lookup lPath, String name, int version, boolean write) { - // We're doing the hand unrolling of the proxy because - // Hibernate/CGLIB proxies are broken. ChildEntry entry = AVMContext.fgInstance.fChildEntryDAO.getByNameParent(name, this); - if (entry == null) + if (entry == null || entry.getChild().getType() == AVMNodeType.DELETED_NODE) { return null; } + // We're doing the hand unrolling of the proxy because + // Hibernate/CGLIB proxies are broken. return AVMNodeUnwrapper.Unwrap(entry.getChild()); } @@ -178,7 +186,7 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory throw new AVMBadArgumentException("Path is null."); } ChildEntry entry = AVMContext.fgInstance.fChildEntryDAO.getByNameParent(name, this); - if (entry == null) + if (entry == null || entry.getChild().getType() == AVMNodeType.DELETED_NODE) { return null; } @@ -187,15 +195,27 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory /** * Remove a child, no copying. + * @param lPath The path by which this was found. * @param name The name of the child to remove. */ @SuppressWarnings("unchecked") - public void removeChild(String name) + public void removeChild(Lookup lPath, String name) { ChildEntry entry = AVMContext.fgInstance.fChildEntryDAO.getByNameParent(name, this); if (entry != null) { + AVMNode child = entry.getChild(); + if (child.getType() == AVMNodeType.DELETED_NODE) + { + return; + } + AVMNode ghost = new DeletedNodeImpl(lPath.getAVMStore().getAVMRepository().issueID(), + lPath.getAVMStore()); AVMContext.fgInstance.fChildEntryDAO.delete(entry); + AVMContext.fgInstance.fAVMNodeDAO.save(ghost); + AVMContext.fgInstance.fAVMNodeDAO.flush(); + ghost.setAncestor(child); + putChild(name, ghost); } } diff --git a/source/java/org/alfresco/repo/avm/hibernate/AVM.hbm.xml b/source/java/org/alfresco/repo/avm/hibernate/AVM.hbm.xml index 3fc8f8b30c..957100ef7d 100644 --- a/source/java/org/alfresco/repo/avm/hibernate/AVM.hbm.xml +++ b/source/java/org/alfresco/repo/avm/hibernate/AVM.hbm.xml @@ -45,6 +45,12 @@ + + + - - - - - - - - @@ -280,26 +277,6 @@ v.avmStore = :store and v.versionID = :version ]]> - - - - - - - - - getByParent(LayeredDirectoryNode parent) - { - Query query = getSession().getNamedQuery("DeletedChild.ByParent"); - query.setEntity("parent", parent); - query.setCacheable(true); - query.setCacheRegion("DeletedChild.ByParent"); - return (List)query.list(); - } -}