Britt Park 0606fa3ab6 AVM Nodes are (theoretically) mostly aspect ready. AVMNodeService is
now derived from AbstractNodeServiceImpl to make policy awareness easier.
Moved addDefaultPropertyValues from DbNodeServiceImpl to 
AbstractNodeServiceImpl so AVMNodeService can use it.  A fix for an
NPE that showed up in stress test.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3603 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2006-08-24 18:36:59 +00:00

1135 lines
37 KiB
Java

/*
* 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.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.namespace.QName;
/**
* This or AVMStore are
* the implementors of the operations specified by AVMService.
* @author britt
*/
public class AVMRepository
{
/**
* The single instance of AVMRepository.
*/
private static AVMRepository fgInstance;
/**
* The current lookup count.
*/
private ThreadLocal<Integer> fLookupCount;
/**
* The node id issuer.
*/
private Issuer fNodeIssuer;
/**
* The layer id issuer.
*/
private Issuer fLayerIssuer;
/**
* Create a new one.
*/
public AVMRepository()
{
fLookupCount = new ThreadLocal<Integer>();
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;
}
/**
* 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);
String[] pathParts = SplitPath(path);
AVMStore rep = getAVMStoreByName(pathParts[0]);
return rep.createFile(pathParts[1], name);
}
/**
* 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)
{
fLookupCount.set(1);
String[] pathParts = SplitPath(path);
AVMStore rep = getAVMStoreByName(pathParts[0]);
rep.createFile(pathParts[1], name, data);
}
/**
* 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)
{
fLookupCount.set(1);
String[] pathParts = SplitPath(path);
AVMStore rep = getAVMStoreByName(pathParts[0]);
rep.createDirectory(pathParts[1], name);
}
/**
* 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);
String[] pathParts = SplitPath(dstPath);
AVMStore rep = getAVMStoreByName(pathParts[0]);
// fSession.get().lock(rep, LockMode.UPGRADE);
rep.createLayeredDirectory(srcPath, pathParts[1], name);
}
/**
* 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);
String[] pathParts = SplitPath(dstPath);
AVMStore rep = getAVMStoreByName(pathParts[0]);
rep.createLayeredFile(srcPath, pathParts[1], name);
}
/**
* Create a new AVMStore.
* @param name The name to give the new AVMStore.
*/
public void createAVMStore(String name)
{
try
{
getAVMStoreByName(name);
throw new AVMExistsException("AVMStore exists: " + name);
}
catch (AVMNotFoundException anf)
{
// Do nothing.
}
// 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.
NewInAVMStore newInRep = AVMContext.fgInstance.fNewInAVMStoreDAO.getByNode(rep.getRoot());
AVMContext.fgInstance.fNewInAVMStoreDAO.delete(newInRep);
}
/**
* 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 = SplitPath(srcPath);
AVMStore srcRepo = getAVMStoreByName(pathParts[0]);
Lookup sPath = srcRepo.lookup(version, pathParts[1], false);
// Lookup the destination directory.
fLookupCount.set(1);
pathParts = SplitPath(dstPath);
AVMStore dstRepo = getAVMStoreByName(pathParts[0]);
Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true);
DirectoryNode dirNode = (DirectoryNode)dPath.getCurrentNode();
AVMNode srcNode = sPath.getCurrentNode();
AVMNode dstNode = null;
// We do different things depending on what kind of thing we're
// branching from. I'd be considerably happier if we disallowed
// certain scenarios, but Jon won't let me :P (bhp).
if (srcNode.getType() == AVMNodeType.PLAIN_DIRECTORY)
{
dstNode = new PlainDirectoryNodeImpl((PlainDirectoryNode)srcNode, dstRepo);
}
else if (srcNode.getType() == AVMNodeType.LAYERED_DIRECTORY)
{
dstNode =
new LayeredDirectoryNodeImpl((LayeredDirectoryNode)srcNode, dstRepo);
((LayeredDirectoryNode)dstNode).setLayerID(issueLayerID());
}
else if (srcNode.getType() == AVMNodeType.LAYERED_FILE)
{
dstNode = new LayeredFileNodeImpl((LayeredFileNode)srcNode, dstRepo);
}
else // This is a plain file.
{
dstNode = new PlainFileNodeImpl((PlainFileNode)srcNode, dstRepo);
}
dstNode.setVersionID(dstRepo.getNextVersionID());
dstNode.setAncestor(srcNode);
dirNode.putChild(name, dstNode);
dirNode.updateModTime();
}
/**
* 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);
String [] pathParts = SplitPath(path);
AVMStore rep = getAVMStoreByName(pathParts[0]);
return rep.getOutputStream(pathParts[1]);
}
/**
* 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 = SplitPath(srcPath);
AVMStore srcRepo = getAVMStoreByName(pathParts[0]);
Lookup sPath = srcRepo.lookupDirectory(-1, pathParts[1], true);
DirectoryNode srcDir = (DirectoryNode)sPath.getCurrentNode();
AVMNode srcNode = srcDir.lookupChild(sPath, srcName, -1, true);
if (srcNode == null)
{
throw new AVMNotFoundException("Not found: " + srcName);
}
fLookupCount.set(1);
pathParts = SplitPath(dstPath);
AVMStore dstRepo = getAVMStoreByName(pathParts[0]);
Lookup dPath = dstRepo.lookupDirectory(-1, pathParts[1], true);
DirectoryNode dstDir = (DirectoryNode)dPath.getCurrentNode();
AVMNode dstNode = dstDir.lookupChild(dPath, dstName, -1, true);
if (dstNode != null)
{
throw new AVMExistsException("Node exists: " + dstName);
}
// 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, false);
((LayeredDirectoryNode)dstNode).setLayerID(sPath.getTopLayer().getLayerID());
}
else
{
dstNode = new LayeredDirectoryNodeImpl((DirectoryNode)srcNode, dstRepo, sPath, srcName);
((LayeredDirectoryNode)dstNode).setLayerID(issueLayerID());
}
}
else
{
dstNode = new PlainDirectoryNodeImpl((PlainDirectoryNode)srcNode, dstRepo);
}
}
else if (srcNode.getType() == AVMNodeType.LAYERED_DIRECTORY)
{
// TODO I think I need to subdivide this logic again.
// based on whether the destination is a layer or not.
if (!sPath.isLayered() || (sPath.isInThisLayer() &&
srcDir.getType() == AVMNodeType.LAYERED_DIRECTORY &&
((LayeredDirectoryNode)srcDir).directlyContains(srcNode)))
{
// Use the simple 'copy' constructor.
dstNode =
new LayeredDirectoryNodeImpl((LayeredDirectoryNode)srcNode, dstRepo);
((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())
{
dstNode =
new LayeredDirectoryNodeImpl((LayeredDirectoryNode)srcNode, dstRepo);
}
else
{
dstNode =
new LayeredDirectoryNodeImpl((DirectoryNode)srcNode, dstRepo, sPath, srcName);
}
// What needs to be done here is dependent on whether the
// rename is to a layered context. If so then it should get the layer id
// of its destination parent. Otherwise it should get a new layer
// id.
if (dPath.isLayered())
{
((LayeredDirectoryNode)dstNode).setLayerID(dPath.getTopLayer().getLayerID());
}
else
{
((LayeredDirectoryNode)dstNode).setLayerID(issueLayerID());
}
}
}
else if (srcNode.getType() == AVMNodeType.LAYERED_FILE)
{
dstNode = new LayeredFileNodeImpl((LayeredFileNode)srcNode, dstRepo);
}
else // This is a plain file node.
{
dstNode = new PlainFileNodeImpl((PlainFileNode)srcNode, dstRepo);
}
srcDir.removeChild(srcName);
srcDir.updateModTime();
dstNode.setVersionID(dstRepo.getNextVersionID());
dstDir.putChild(dstName, dstNode);
dstDir.updateModTime();
dstNode.setAncestor(srcNode);
}
/**
* 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);
String [] pathParts = SplitPath(dirPath);
AVMStore repo = getAVMStoreByName(pathParts[0]);
repo.uncover(pathParts[1], name);
}
/**
* Snapshot the given repositories.
* @param repositories The list of AVMStore name to snapshot.
* @return A List of version ids for each newly snapshotted AVMStore.
*/
public List<Integer> createSnapshot(List<String> repositories)
{
List<Integer> result = new ArrayList<Integer>();
for (String repName : repositories)
{
AVMStore repo = getAVMStoreByName(repName);
result.add(repo.createSnapshot());
}
return result;
}
/**
* Create a snapshot of a single AVMStore.
* @param store The name of the repository.
* @return The version id of the newly snapshotted repository.
*/
public int createSnapshot(String storeName)
{
AVMStore store = getAVMStoreByName(storeName);
return store.createSnapshot();
}
/**
* 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);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
store.removeNode(pathParts[1], name);
}
/**
* 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)
{
AVMStore store = getAVMStoreByName(name);
AVMNode root = store.getRoot();
root.setIsRoot(false);
VersionRootDAO vrDAO = AVMContext.fgInstance.fVersionRootDAO;
List<VersionRoot> vRoots = vrDAO.getAllInAVMStore(store);
for (VersionRoot vr : vRoots)
{
AVMNode node = vr.getRoot();
node.setIsRoot(false);
vrDAO.delete(vr);
}
List<NewInAVMStore> newGuys = AVMContext.fgInstance.fNewInAVMStoreDAO.getByAVMStore(store);
for (NewInAVMStore newGuy : newGuys)
{
AVMContext.fgInstance.fNewInAVMStoreDAO.delete(newGuy);
}
AVMContext.fgInstance.fAVMStorePropertyDAO.delete(store);
AVMContext.fgInstance.fAVMStoreDAO.delete(store);
}
/**
* 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)
{
AVMStore store = getAVMStoreByName(name);
store.purgeVersion(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);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
return store.getInputStream(version, pathParts[1]);
}
/**
* Get a listing of a directory.
* @param version The version to look under.
* @param path The path to the directory.
* @return A List of FolderEntries.
*/
public SortedMap<String, AVMNodeDescriptor> getListing(int version, String path)
{
fLookupCount.set(1);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
return store.getListing(version, pathParts[1]);
}
/**
* 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<String, AVMNodeDescriptor> getListingDirect(int version, String path)
{
fLookupCount.set(1);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
return store.getListingDirect(version, pathParts[1]);
}
/**
* Get a directory listing from a directory node descriptor.
* @param dir The directory node descriptor.
* @return A SortedMap listing.
*/
public SortedMap<String, AVMNodeDescriptor> getListing(AVMNodeDescriptor dir)
{
fLookupCount.set(1);
AVMNode node = AVMContext.fgInstance.fAVMNodeDAO.getByID(dir.getId());
if (node.getType() != AVMNodeType.LAYERED_DIRECTORY &&
node.getType() != AVMNodeType.PLAIN_DIRECTORY)
{
throw new AVMWrongTypeException("Not a directory.");
}
DirectoryNode dirNode = (DirectoryNode)node;
return dirNode.getListing(dir);
}
/**
* 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<String> getDeleted(int version, String path)
{
fLookupCount.set(1);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
return store.getDeleted(version, pathParts[1]);
}
/**
* Get descriptors of all AVMStores.
* @return A list of all descriptors.
*/
@SuppressWarnings("unchecked")
public List<AVMStoreDescriptor> getAVMStores()
{
List<AVMStore> l = AVMContext.fgInstance.fAVMStoreDAO.getAll();
List<AVMStoreDescriptor> result = new ArrayList<AVMStoreDescriptor>();
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);
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<VersionDescriptor> getAVMStoreVersions(String name)
{
AVMStore store = getAVMStoreByName(name);
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<VersionDescriptor> getAVMStoreVersions(String name, Date from, Date to)
{
AVMStore store = getAVMStoreByName(name);
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);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
return store.getIndirectionPath(version, pathParts[1]);
}
/**
* 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);
return store.getNextVersionID();
}
/**
* Get an AVMStore by name.
* @param name The name of the AVMStore.
* @return The AVMStore.
*/
private AVMStore getAVMStoreByName(String name)
{
AVMStore store = AVMContext.fgInstance.fAVMStoreDAO.getByName(name);
if (store == null)
{
throw new AVMNotFoundException("AVMStore not found: " + 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.
* @return A lookup object.
*/
public Lookup lookup(int version, String path)
{
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]);
Lookup result = store.lookup(version, pathParts[1], false);
return result;
}
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)
{
fLookupCount.set(0);
AVMNode node = AVMContext.fgInstance.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;
return dirNode.lookupChild(dir, name);
}
/**
* 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);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
Lookup lookup = store.lookup(version, pathParts[1], false);
return new LayeringDescriptor(!lookup.getDirectlyContained(),
lookup.getAVMStore().getDescriptor(),
lookup.getFinalStore().getDescriptor());
}
/**
* 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)
{
if (fLookupCount.get() > 50)
{
throw new AVMCycleException("Cycle in lookup.");
}
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
return store.lookupDirectory(version, pathParts[1], false);
}
/**
* 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);
String[] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
store.makePrimary(pathParts[1]);
}
/**
* 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);
String[] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
store.retargetLayeredDirectory(pathParts[1], target);
}
/**
* 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<AVMNodeDescriptor> getHistory(AVMNodeDescriptor desc, int count)
{
AVMNode node = AVMContext.fgInstance.fAVMNodeDAO.getByID(desc.getId());
if (node == null)
{
throw new AVMNotFoundException("Not found.");
}
if (count < 0)
{
count = Integer.MAX_VALUE;
}
List<AVMNodeDescriptor> history = new ArrayList<AVMNodeDescriptor>();
for (int i = 0; i < count; i++)
{
node = node.getAncestor();
if (node == null)
{
break;
}
history.add(node.getDescriptor("UNKNOWN", "UNKNOWN", "UNKNOWN"));
}
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);
String[] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
store.setOpacity(pathParts[1], opacity);
}
/**
* 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);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
store.setNodeProperty(pathParts[1], name, value);
}
/**
* 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<QName, PropertyValue> properties)
{
fLookupCount.set(1);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
store.setNodeProperties(pathParts[1], properties);
}
/**
* 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);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
return store.getNodeProperty(version, pathParts[1], name);
}
/**
* 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<QName, PropertyValue> getNodeProperties(int version, String path)
{
fLookupCount.set(1);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
return store.getNodeProperties(version, pathParts[1]);
}
/**
* 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);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
store.deleteNodeProperty(pathParts[1], name);
}
/**
* Delete all properties on a node.
* @param path The path to the node.
*/
public void deleteNodeProperties(String path)
{
fLookupCount.set(1);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
store.deleteNodeProperties(pathParts[1]);
}
/**
* 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)
{
getAVMStoreByName(store).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<QName, PropertyValue> props)
{
getAVMStoreByName(store).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)
{
return getAVMStoreByName(store).getProperty(name);
}
/**
* Get all the properties for a store.
* @param store The name of the Store.
* @return A Map of all the properties.
*/
public Map<QName, PropertyValue> getStoreProperties(String store)
{
return getAVMStoreByName(store).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)
{
getAVMStoreByName(store).deleteProperty(name);
}
/**
* Get the AVMStoreDescriptor for an AVMStore.
* @param name The name of the AVMStore.
* @return The descriptor.
*/
public AVMStoreDescriptor getAVMStoreDescriptor(String name)
{
return getAVMStoreByName(name).getDescriptor();
}
/**
* 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 = AVMContext.fgInstance.fAVMNodeDAO.getByID(left.getId());
AVMNode rNode = AVMContext.fgInstance.fAVMNodeDAO.getByID(right.getId());
if (lNode == null || rNode == null)
{
throw new AVMNotFoundException("Node not found.");
}
List<AVMNode> leftHistory = new ArrayList<AVMNode>();
while (lNode != null)
{
leftHistory.add(lNode);
lNode = lNode.getAncestor();
}
List<AVMNode> rightHistory = new ArrayList<AVMNode>();
while (rNode != null)
{
rightHistory.add(rNode);
rNode = rNode.getAncestor();
}
for (AVMNode l : leftHistory)
{
for (AVMNode r : rightHistory)
{
if (l.equals(r))
{
return l.getDescriptor("", "", "");
}
}
}
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);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
return store.getContentDataForRead(version, pathParts[1]);
}
/**
* 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);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
return store.getContentDataForWrite(pathParts[1]);
}
/**
* 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);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
store.setContentData(pathParts[1], data);
}
/**
* Get the single instance of AVMRepository.
* @return The single instance.
*/
public static AVMRepository GetInstance()
{
return fgInstance;
}
/**
* 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);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
store.addAspect(pathParts[1], aspectName);
}
/**
* Get all the aspects on an AVM node.
* @param version The version to look under.
* @param path The path to the node.
* @return A List of the QNames of the Aspects.
*/
public List<QName> getAspects(int version, String path)
{
fLookupCount.set(1);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
return store.getAspects(version, pathParts[1]);
}
/**
* 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);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
store.removeAspect(pathParts[1], aspectName);
}
/**
* Does a node have a particular aspect.
* @param version The version to look under.
* @param path The path to the node.
* @param aspectName The name of the aspect.
* @return Whether the node has the aspect.
*/
public boolean hasAspect(int version, String path, QName aspectName)
{
fLookupCount.set(1);
String [] pathParts = SplitPath(path);
AVMStore store = getAVMStoreByName(pathParts[0]);
return store.hasAspect(version, pathParts[1], aspectName);
}
}