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
This commit is contained in:
Britt Park
2006-09-10 17:20:35 +00:00
parent 11772e5796
commit 8a95b09b98
21 changed files with 382 additions and 483 deletions

View File

@@ -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
*/

View File

@@ -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;
/**

View File

@@ -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.<QName, Serializable>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
};
/**

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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<Object>
{
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();
}
}
}

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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<DeletedChild> getByParent(LayeredDirectoryNode parent);
}

View File

@@ -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;
}
}

View File

@@ -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();
}

View File

@@ -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() + "]";
}
}

View File

@@ -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.

View File

@@ -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<DeletedChild> getDeleted();
/**
* Set the opacity of this.
* @param opacity Whether this should be opaque, i.e. not see the things it

View File

@@ -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<String, AVMNode> getListing(Lookup lPath)
{
// Get the base listing from the thing we indirect to.
Map<String, AVMNode> baseListing = null;
Map<String, AVMNode> listing = null;
if (fOpacity)
{
baseListing = new HashMap<String, AVMNode>();
listing = new HashMap<String, AVMNode>();
}
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<String, AVMNode>();
listing = new HashMap<String, AVMNode>();
}
}
// Filter the base listing by taking out anything in the deleted Set.
Map<String, AVMNode> listing = new HashMap<String, AVMNode>();
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<String, AVMNode> listing = new HashMap<String, AVMNode>();
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<DeletedChild> deleted = getDeleted();
for (DeletedChild child : deleted)
{
baseListing.remove(child.getName());
}
List<ChildEntry> 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<String> getDeletedNames()
{
List<DeletedChild> deleted = getDeleted();
List<ChildEntry> children = AVMContext.fgInstance.fChildEntryDAO.getByParent(this);
List<String> listing = new ArrayList<String>();
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<DeletedChild> getDeleted()
{
return AVMContext.fgInstance.fDeletedChildDAO.getByParent(this);
}
/**
* Does nothing because LayeredDirectoryNodes can't be roots.
* @param isRoot

View File

@@ -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)
{

View File

@@ -99,6 +99,10 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory
List<ChildEntry> 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<ChildEntry> 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);
}
}

View File

@@ -45,6 +45,12 @@
<!-- ACL -->
<many-to-one name="acl" column="acl_id"
class="org.alfresco.repo.domain.hibernate.DbAccessControlListImpl"/>
<!-- Deleted nodes -->
<subclass name="DeletedNodeImpl"
proxy="DeletedNode"
lazy="true"
discriminator-value="deletednode">
</subclass>
<!-- Directories, two flavors. -->
<subclass name="DirectoryNodeImpl"
proxy="DirectoryNode"
@@ -141,15 +147,6 @@
<many-to-one name="child" column="child_id" class="AVMNodeImpl"
not-null="true"/>
</class>
<class table="avm_deleted_children" name="DeletedChildImpl" proxy="DeletedChild">
<cache usage="read-write"/>
<id name="id" column="id" type="long">
<generator class="native"/>
</id>
<property name="name" column="name" type="string" index="deleted_child_name_index"/>
<many-to-one name="parent" class="LayeredDirectoryNodeImpl"
column="parent_id"/>
</class>
<class name="HistoryLinkImpl" proxy="HistoryLink" table="avm_history_links">
<composite-id>
<key-many-to-one name="ancestor" class="AVMNodeImpl" column="ancestor"/>
@@ -280,26 +277,6 @@
v.avmStore = :store and v.versionID = :version
]]>
</query>
<query name="DeletedChild.ByNameParent">
<![CDATA[
from DeletedChildImpl dc
where
dc.parent = :parent and dc.name = :name
]]>
</query>
<query name="DeletedChild.ByParent">
<![CDATA[
from DeletedChildImpl dc
where
dc.parent = :parent
]]>
</query>
<query name="DeletedChild.DeleteByParent">
<![CDATA[
delete DeletedChildImpl dc
where dc.parent = :parent
]]>
</query>
<query name="FindOrphans">
<![CDATA[
from AVMNodeImpl an

View File

@@ -1,103 +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.hibernate;
import java.util.List;
import org.alfresco.repo.avm.AVMNode;
import org.alfresco.repo.avm.DeletedChild;
import org.alfresco.repo.avm.DeletedChildDAO;
import org.alfresco.repo.avm.LayeredDirectoryNode;
import org.hibernate.Query;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
/**
* Hibernate implementation of DAO for DeletedChildren.
* @author britt
*/
class DeletedChildDAOHibernate extends HibernateDaoSupport implements
DeletedChildDAO
{
/**
* Do nothing constructor.
*/
public DeletedChildDAOHibernate()
{
super();
}
/**
* Save an unsaved DeletedChild.
* @param child The DeletedChild to be saved.
*/
public void save(DeletedChild child)
{
getSession().save(child);
}
/**
* Delete one.
* @param child The one to delete.
*/
public void delete(DeletedChild child)
{
getSession().delete(child);
}
/**
* Delete all belonging to the given parent.
* @param parent The parent.
*/
public void deleteByParent(AVMNode parent)
{
Query delete = getSession().getNamedQuery("DeletedChild.DeleteByParent");
delete.setEntity("parent", parent);
delete.executeUpdate();
}
/**
* 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)
{
Query query = getSession().getNamedQuery("DeletedChild.ByNameParent");
query.setString("name", name);
query.setEntity("parent", parent);
query.setCacheable(true);
query.setCacheRegion("DeletedChild.ByNameParent");
return (DeletedChild)query.uniqueResult();
}
/**
* Get all the deleted children of a given parent.
* @param parent The parent.
* @return A List of DeletedChildren.
*/
@SuppressWarnings("unchecked")
public List<DeletedChild> getByParent(LayeredDirectoryNode parent)
{
Query query = getSession().getNamedQuery("DeletedChild.ByParent");
query.setEntity("parent", parent);
query.setCacheable(true);
query.setCacheRegion("DeletedChild.ByParent");
return (List<DeletedChild>)query.list();
}
}