mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-30 18:15:39 +00:00
19546: (RECORD ONLY) Merged V3.2 to PATCHES/V3.2.r 19432: Merged V3.1 to V3.2 19427: Merged V3.0 to V3.1 19423: Merged V2.2 to V3.0 19391: Fix for ALF-2076: AUTO does not work if a document has been added and deleted since the index backup 19419: V2.2 Build Fix 19421: Fix for ALF-2076: AUTO does not work if a document has been added and deleted since the index backup 19463: Merged V3.1 to V3.2 19459: Merged V3.0 to V3.1 19457: Merged V2.2 to V3.0 19449: Addition Fix for ALF-2076: AUTO does not work if a document has been added and deleted since the index backup 19493 Merged V3.1 to V3.2 19471: Build fix after changes for ALF-2076 were merged forward. Index checker correctly understands INDETERMINATE state of indexed transactions 19547: (RECORD ONLY) Incremented version label 19555: (RECORD ONLY) Merged V3.2 to PATCHES/V3.2.r 19552: Merged V3.1 to V3.2 19551: Further fix after changes for ALF-2076 were merged forward. Final fix to check for InIndex.No 19566: (RECORD ONLY) Merged V3.2 to PATCHES/V3.2.r 19539: Merged HEAD to V3.2 19538: ALF-2076: Build fix - fix build speed 19802: (RECORD ONLY) ALF-2382, ALF-2383: Merged V3.2 to PATCHES/V3.2.r 19647: ALF-2231: Merged DEV/BELARUS/V2.2-2009_12_01 to V3.2 17704: ENH-681: alfresco webdav does not respect webdav locks 19624: ALF-2231: Merged DEV/BELARUS/V2.2-2009_12_01 to V3.2 17704: ENH-681: alfresco webdav does not respect webdav locks 19623: ALF-1890: Correction to previous checkin to allow defaulting of request body charset 19617: ALF-1890: Improvements to make ALL WebDAV methods retryable - Solution from PutMethod promoted to request wrapper that will handle ALL calls to getInputStream and getReader 19614: ALF-1890: Merged V2.2 to V3.2 17709: Merged DEV_TEMPORARY to V2.2 17700: ETWOTWO-1393: concurrent writes to webdav lead to data loss (0kb resulting file) 19613: Merged DEV/BELARUS/V2.2-2010_02_03 to V2.2 19157: ALF-1890: concurrent writes to webdav lead to data loss (0kb resulting file) 19803: ALF-558: File servers (CIFS / FTP / NFS) can now handle concurrent write operations on Alfresco repository - ContentDiskDriver / AVMDiskDriver now use retrying transactions for write operations - Disable EagerContentStoreCleaner on ContentDiskDriver / AVMDiskDriver closeFile() operations so that they may be retried after rollback (Sony zero byte problem) - Allow manual association of AVM ContentData with nodes so that closeFile() may be retried - Propagation of new argument through AVM interfaces 19804: (RECORD ONLY) Merged PATCHES/V3.2.0 to PATCHES/V3.2.r Merged HEAD to V3.2.0 19786: Refactor of previous test fix. I have pushed down the OOo-specific parts of the change from AbstractContentTransformerTest to OpenOfficeContentTransformerTest leaving an extension point in the base class should other transformations need to be excluded in the future. 19785: Fix for failing test OpenOfficeContentTransformerTest.testAllConversions. Various OOo-related transformations are returned as available but fail on our test server with OOo on it. Pending further work on these failings, I am disabling those transformations in test code whilst leaving them available in the product code. This is because in the wild a different OOo version may succeed with these transformations. I had previously explicitly disabled 3 transformations in the product and I am moving that restriction from product to test code for the same reason. 19707: Return value from isTransformationBlocked was inverted. Fixed now. 19705: Refinement of previous check-in re OOo transformations. I have pulled up the code that handles blocked transformations into a superclass so that the JodConverter-based transformer worker can inherit the same list of blocked transformations. To reiterate, blocked transformations are those that the OOo integration code believes should work but which are broken in practice. These are blocked by the transformers and will always be unavailable regardless of the OOo connection state. 19702: Fix for HEAD builds running on panda build server. OOo was recently installed on panda which has activated various OOo-related transformations/extractions in the test code. It appears that OOo does not support some transformations from Office 97 to Office 2007. Specifically doc to docx and xls to xlsx. These transformations have now been marked as unavailable. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@20004 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2040 lines
71 KiB
Java
2040 lines
71 KiB
Java
/*
|
|
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
|
*
|
|
* This file is part of Alfresco
|
|
*
|
|
* Alfresco is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Alfresco is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
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.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.SortedMap;
|
|
import java.util.TreeMap;
|
|
|
|
import org.alfresco.model.ContentModel;
|
|
import org.alfresco.model.WCMModel;
|
|
import org.alfresco.repo.avm.util.AVMUtil;
|
|
import org.alfresco.repo.avm.util.RawServices;
|
|
import org.alfresco.repo.avm.util.SimplePath;
|
|
import org.alfresco.repo.domain.DbAccessControlList;
|
|
import org.alfresco.repo.domain.PropertyValue;
|
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
|
import org.alfresco.repo.security.permissions.ACLCopyMode;
|
|
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
|
import org.alfresco.service.cmr.avm.AVMBadArgumentException;
|
|
import org.alfresco.service.cmr.avm.AVMException;
|
|
import org.alfresco.service.cmr.avm.AVMExistsException;
|
|
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
|
|
import org.alfresco.service.cmr.avm.AVMNotFoundException;
|
|
import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
|
|
import org.alfresco.service.cmr.avm.AVMWrongTypeException;
|
|
import org.alfresco.service.cmr.avm.VersionDescriptor;
|
|
import org.alfresco.service.cmr.dictionary.AspectDefinition;
|
|
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
|
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
|
|
import org.alfresco.service.cmr.repository.ContentData;
|
|
import org.alfresco.service.cmr.repository.ContentReader;
|
|
import org.alfresco.service.cmr.repository.ContentWriter;
|
|
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
|
import org.alfresco.service.cmr.repository.NodeRef;
|
|
import org.alfresco.service.cmr.security.PermissionService;
|
|
import org.alfresco.service.namespace.QName;
|
|
import org.alfresco.util.GUID;
|
|
import org.alfresco.util.Pair;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
|
/**
|
|
* A Repository contains a current root directory and a list of
|
|
* root versions. Each root version corresponds to a separate snapshot
|
|
* operation.
|
|
* @author britt
|
|
*/
|
|
public class AVMStoreImpl implements AVMStore
|
|
{
|
|
private static Log logger = LogFactory.getLog(AVMStoreImpl.class);
|
|
/**
|
|
* The primary key.
|
|
*/
|
|
private long fID;
|
|
|
|
/**
|
|
* The name of this AVMStore.
|
|
*/
|
|
private String fName;
|
|
|
|
/**
|
|
* The current root directory.
|
|
*/
|
|
private DirectoryNode fRoot;
|
|
|
|
/**
|
|
* The next version id.
|
|
*/
|
|
private int fNextVersionID;
|
|
|
|
/**
|
|
* The version (for concurrency control).
|
|
*/
|
|
private long fVers;
|
|
|
|
/**
|
|
* Acl for this store.
|
|
*/
|
|
private DbAccessControlList fACL;
|
|
|
|
/**
|
|
* The AVMRepository.
|
|
*/
|
|
transient private AVMRepository fAVMRepository;
|
|
|
|
/**
|
|
* Default constructor.
|
|
*/
|
|
public AVMStoreImpl()
|
|
{
|
|
fAVMRepository = AVMRepository.GetInstance();
|
|
}
|
|
|
|
/**
|
|
* Make a brand new AVMStore.
|
|
* @param repo The AVMRepository.
|
|
* @param name The name of the AVMStore.
|
|
*/
|
|
public AVMStoreImpl(AVMRepository repo, String name)
|
|
{
|
|
// Make ourselves up and save.
|
|
fAVMRepository = repo;
|
|
|
|
setName(name);
|
|
setNextVersionID(0);
|
|
setRoot(null);
|
|
|
|
AVMDAOs.Instance().fAVMStoreDAO.save(this);
|
|
|
|
String creator = RawServices.Instance().getAuthenticationContext().getCurrentUserName();
|
|
if (creator == null)
|
|
{
|
|
creator = RawServices.Instance().getAuthenticationContext().getSystemUserName();
|
|
}
|
|
setProperty(ContentModel.PROP_CREATOR, new PropertyValue(null, creator));
|
|
setProperty(ContentModel.PROP_CREATED, new PropertyValue(null, new Date(System.currentTimeMillis())));
|
|
|
|
// Make up the initial version record and save.
|
|
long time = System.currentTimeMillis();
|
|
|
|
PlainDirectoryNode dir = new PlainDirectoryNodeImpl(this);
|
|
dir.setIsRoot(true);
|
|
AVMDAOs.Instance().fAVMNodeDAO.save(dir);
|
|
|
|
setRoot(dir);
|
|
|
|
VersionRoot versionRoot = new VersionRootImpl(this,
|
|
getRoot(),
|
|
getNextVersionID(),
|
|
time,
|
|
creator,
|
|
AVMUtil.INITIAL_SNAPSHOT,
|
|
AVMUtil.INITIAL_SNAPSHOT);
|
|
setNextVersionID(getNextVersionID()+1);
|
|
|
|
AVMDAOs.Instance().fAVMStoreDAO.update(this);
|
|
AVMDAOs.Instance().fVersionRootDAO.save(versionRoot);
|
|
}
|
|
|
|
/**
|
|
* Set the primary key
|
|
* @param id The primary key.
|
|
*/
|
|
public void setId(long id)
|
|
{
|
|
fID = id;
|
|
}
|
|
|
|
/**
|
|
* Get the primary key.
|
|
* @return The primary key.
|
|
*/
|
|
public long getId()
|
|
{
|
|
return fID;
|
|
}
|
|
|
|
/**
|
|
* Set a new root for this.
|
|
* @param root
|
|
*/
|
|
public void setNewRoot(DirectoryNode root)
|
|
{
|
|
fRoot = root;
|
|
}
|
|
|
|
/**
|
|
* Snapshot this store. This creates a new version record.
|
|
* @return The version id of the new snapshot.
|
|
*/
|
|
public Map<String, Integer> createSnapshot(String tag, String description, Map<String, Integer> snapShotMap)
|
|
{
|
|
long start = System.currentTimeMillis();
|
|
|
|
long rootID = getRoot().getId();
|
|
AVMStoreImpl me = (AVMStoreImpl)AVMDAOs.Instance().fAVMStoreDAO.getByID(getId());
|
|
VersionRoot lastVersion = AVMDAOs.Instance().fVersionRootDAO.getMaxVersion(me);
|
|
List<VersionLayeredNodeEntry> layeredEntries =
|
|
AVMDAOs.Instance().fVersionLayeredNodeEntryDAO.get(lastVersion);
|
|
// Is there no need for a snapshot?
|
|
DirectoryNode root = (DirectoryNode)AVMDAOs.Instance().fAVMNodeDAO.getByID(rootID);
|
|
if (!root.getIsNew() && layeredEntries.size() == 0)
|
|
{
|
|
if (logger.isTraceEnabled())
|
|
{
|
|
logger.trace("createSnapshot: no snapshot required: "+me.getName()+" ["+me.getId()+"] - lastVersion = "+lastVersion.getVersionID() + "("+tag+", "+description+")");
|
|
}
|
|
|
|
// So, we set the tag and description fields of the latest version.
|
|
if (tag != null || description != null)
|
|
{
|
|
lastVersion.setTag(tag);
|
|
lastVersion.setDescription(description);
|
|
|
|
AVMDAOs.Instance().fVersionRootDAO.update(lastVersion);
|
|
}
|
|
snapShotMap.put(getName(), lastVersion.getVersionID());
|
|
|
|
if (logger.isTraceEnabled())
|
|
{
|
|
logger.trace("createSnapshot: no snapshot required: "+me.getName()+(tag != null ? "("+tag+")" : "")+" [lastVersion = "+lastVersion.getVersionID()+"]");
|
|
}
|
|
|
|
return snapShotMap;
|
|
}
|
|
if (logger.isTraceEnabled())
|
|
{
|
|
logger.trace("createSnapshot: snapshot: "+me.getName()+" ["+me.getId()+"] - lastVersion="+lastVersion.getVersionID()+", layeredEntries="+layeredEntries.size());
|
|
}
|
|
|
|
snapShotMap.put(getName(), me.getNextVersionID());
|
|
// Force copies on all the layered nodes from last snapshot.
|
|
for (VersionLayeredNodeEntry entry : layeredEntries)
|
|
{
|
|
String[] pathParts = AVMUtil.splitPath(entry.getPath());
|
|
Lookup lookup = me.lookup(-1, pathParts[1], false, false);
|
|
if (lookup == null)
|
|
{
|
|
continue;
|
|
}
|
|
if (lookup.getCurrentNode().getType() != AVMNodeType.LAYERED_DIRECTORY &&
|
|
lookup.getCurrentNode().getType() != AVMNodeType.LAYERED_FILE)
|
|
{
|
|
continue;
|
|
}
|
|
if (lookup.getCurrentNode().getIsNew())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (lookup.getCurrentNode().getType() == AVMNodeType.LAYERED_DIRECTORY)
|
|
{
|
|
fAVMRepository.forceCopy(entry.getPath());
|
|
me = (AVMStoreImpl)AVMDAOs.Instance().fAVMStoreDAO.getByID(getId());
|
|
}
|
|
else if (lookup.getCurrentNode().getType() == AVMNodeType.LAYERED_FILE)
|
|
{
|
|
String parentName[] = AVMUtil.splitBase(entry.getPath());
|
|
AVMNode child = lookup.getCurrentNode();
|
|
DirectoryNode parent = lookup.getCurrentNodeDirectory();
|
|
|
|
AVMNode newChild = ((LayeredFileNode)child).copyLiterally(lookup);
|
|
newChild.setAncestor(child);
|
|
parent.putChild(parentName[1], newChild);
|
|
}
|
|
|
|
// TODO This leaves the behavior of LayeredFiles not quite
|
|
// right.
|
|
/*
|
|
String parentName[] = AVMNodeConverter.SplitBase(entry.getPath());
|
|
parentName[0] = parentName[0].substring(parentName[0].indexOf(':') + 1);
|
|
lookup = lookupDirectory(-1, parentName[0], true);
|
|
DirectoryNode parent = (DirectoryNode)lookup.getCurrentNode();
|
|
AVMNode child = parent.lookupChild(lookup, parentName[1], false);
|
|
// TODO For debugging.
|
|
if (child == null)
|
|
{
|
|
System.err.println("Yoiks!");
|
|
}
|
|
// TODO This is funky. Need to look carefully to see that this call
|
|
// does exactly what's needed.
|
|
lookup.add(child, parentName[1], false);
|
|
AVMNode newChild = null;
|
|
if (child.getType() == AVMNodeType.LAYERED_DIRECTORY)
|
|
{
|
|
newChild = child.copy(lookup);
|
|
}
|
|
else
|
|
{
|
|
newChild = ((LayeredFileNode)child).copyLiterally(lookup);
|
|
}
|
|
parent.putChild(parentName[1], newChild);
|
|
*/
|
|
}
|
|
|
|
if (logger.isTraceEnabled())
|
|
{
|
|
logger.trace("createSnapshot: force copy: "+me.getName()+(tag != null ? "("+tag+")" : "")+" [lastVersion="+lastVersion.getVersionID()+", layeredEntriesCnt="+layeredEntries.size()+"] in " + (System.currentTimeMillis() - start) + " msecs");
|
|
}
|
|
|
|
// Clear out the new nodes.
|
|
List<Long> allLayeredNodeIDs = AVMDAOs.Instance().fAVMNodeDAO.getNewLayeredInStoreIDs(me);
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.clearNewInStore(me);
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.clear();
|
|
List<Long> layeredNodeIDs = new ArrayList<Long>();
|
|
for (Long layeredID : allLayeredNodeIDs)
|
|
{
|
|
Layered layered = (Layered)AVMDAOs.Instance().fAVMNodeDAO.getByID(layeredID);
|
|
String indirection = layered.getIndirection();
|
|
if (indirection == null)
|
|
{
|
|
continue;
|
|
}
|
|
layeredNodeIDs.add(layeredID);
|
|
String storeName = AVMUtil.getStoreName(indirection);
|
|
if (!snapShotMap.containsKey(storeName))
|
|
{
|
|
AVMStore store = AVMDAOs.Instance().fAVMStoreDAO.getByName(storeName);
|
|
if (store == null)
|
|
{
|
|
layered.setIndirectionVersion(-1);
|
|
}
|
|
else
|
|
{
|
|
store.createSnapshot(null, null, snapShotMap);
|
|
layered = (Layered)AVMDAOs.Instance().fAVMNodeDAO.getByID(layeredID);
|
|
layered.setIndirectionVersion(snapShotMap.get(storeName));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
layered.setIndirectionVersion(snapShotMap.get(storeName));
|
|
}
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(layered);
|
|
}
|
|
|
|
// Make up a new version record.
|
|
String user = RawServices.Instance().getAuthenticationContext().getCurrentUserName();
|
|
if (user == null)
|
|
{
|
|
user = RawServices.Instance().getAuthenticationContext().getSystemUserName();
|
|
}
|
|
|
|
me = (AVMStoreImpl)AVMDAOs.Instance().fAVMStoreDAO.getByID(getId());
|
|
VersionRoot versionRoot = new VersionRootImpl(me,
|
|
me.getRoot(),
|
|
me.getNextVersionID(),
|
|
System.currentTimeMillis(),
|
|
user,
|
|
tag,
|
|
description);
|
|
|
|
me.setNextVersionID(me.getNextVersionID()+1);
|
|
|
|
AVMDAOs.Instance().fAVMStoreDAO.update(me);
|
|
|
|
AVMDAOs.Instance().fVersionRootDAO.save(versionRoot);
|
|
|
|
int vlneCnt = 0;
|
|
|
|
for (Long nodeID : layeredNodeIDs)
|
|
{
|
|
AVMNode node = AVMDAOs.Instance().fAVMNodeDAO.getByID(nodeID);
|
|
List<String> paths = fAVMRepository.getVersionPaths(versionRoot, node);
|
|
for (String path : paths)
|
|
{
|
|
VersionLayeredNodeEntry entry =
|
|
new VersionLayeredNodeEntryImpl(versionRoot, path);
|
|
AVMDAOs.Instance().fVersionLayeredNodeEntryDAO.save(entry);
|
|
}
|
|
|
|
vlneCnt = vlneCnt+paths.size();
|
|
}
|
|
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("Raw snapshot: "+me.getName()+(tag != null ? "("+tag+")" : "")+" [versionRootId="+versionRoot.getId()+", layeredNodeIDsCnt="+layeredNodeIDs.size()+", versionLayeredNodeEntriesCnt="+vlneCnt+"] in " + (System.currentTimeMillis() - start) + " msecs");
|
|
}
|
|
|
|
return snapShotMap;
|
|
}
|
|
|
|
/**
|
|
* Create a new directory.
|
|
* @param path The path to the containing directory.
|
|
* @param name The name of the new directory.
|
|
*/
|
|
public void createDirectory(String path, String name, List<QName> aspects, Map<QName, PropertyValue> properties)
|
|
{
|
|
Lookup lPath = lookupDirectory(-1, path, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, dir, PermissionService.ADD_CHILDREN, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write: " + path);
|
|
}
|
|
Pair<AVMNode, Boolean> temp = dir.lookupChild(lPath, name, true);
|
|
AVMNode child = (temp == null) ? null : temp.getFirst();
|
|
if (child != null && child.getType() != AVMNodeType.DELETED_NODE)
|
|
{
|
|
throw new AVMExistsException("Child exists: " + name);
|
|
}
|
|
DirectoryNode newDir = null;
|
|
if (lPath.isLayered()) // Creating a directory in a layered context creates
|
|
// a LayeredDirectoryNode that gets its indirection from
|
|
// its parent.
|
|
{
|
|
// TODO - collapse save/update
|
|
newDir = new LayeredDirectoryNodeImpl((String)null, this, null, null, ACLCopyMode.INHERIT);
|
|
((LayeredDirectoryNodeImpl)newDir).setPrimaryIndirection(false);
|
|
((LayeredDirectoryNodeImpl)newDir).setLayerID(lPath.getTopLayer().getLayerID());
|
|
|
|
DbAccessControlList acl = dir.getAcl();
|
|
newDir.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null);
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(newDir);
|
|
}
|
|
else
|
|
{
|
|
newDir = new PlainDirectoryNodeImpl(this);
|
|
|
|
DbAccessControlList acl = dir.getAcl();
|
|
newDir.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null);
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.save(newDir);
|
|
}
|
|
|
|
// newDir.setVersionID(getNextVersionID());
|
|
if (child != null)
|
|
{
|
|
newDir.setAncestor(child);
|
|
}
|
|
//dir.updateModTime();
|
|
dir.putChild(name, newDir);
|
|
if (aspects != null)
|
|
{
|
|
Set<QName> aspectQNames = new HashSet<QName>(newDir.getAspects());
|
|
aspectQNames.addAll(aspects);
|
|
((DirectoryNodeImpl)newDir).setAspects(aspectQNames);
|
|
}
|
|
if (properties != null)
|
|
{
|
|
Map<QName, PropertyValue> props = new HashMap<QName, PropertyValue>(newDir.getProperties());
|
|
props.putAll(properties);
|
|
((DirectoryNodeImpl)newDir).setProperties(props);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a new layered directory.
|
|
* @param srcPath The target indirection for a layered node.
|
|
* @param dstPath The containing directory for the new node.
|
|
* @param name The name of the new node.
|
|
*/
|
|
public void createLayeredDirectory(String srcPath, String dstPath,
|
|
String name)
|
|
{
|
|
Lookup lPath = lookupDirectory(-1, dstPath, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + dstPath + " not found.");
|
|
}
|
|
DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode();
|
|
Pair<AVMNode, Boolean> temp = dir.lookupChild(lPath, name, true);
|
|
AVMNode child = (temp == null) ? null : temp.getFirst();
|
|
if (child != null && child.getType() != AVMNodeType.DELETED_NODE)
|
|
{
|
|
throw new AVMExistsException("Child exists: " + name);
|
|
}
|
|
Long parentAcl = dir.getAcl() == null ? null : dir.getAcl().getId();
|
|
|
|
LayeredDirectoryNode newDir =
|
|
new LayeredDirectoryNodeImpl(srcPath, this, null, parentAcl, ACLCopyMode.INHERIT);
|
|
|
|
if (lPath.isLayered())
|
|
{
|
|
// When a layered directory is made inside of a layered context,
|
|
// it gets its layer id from the topmost layer in its lookup
|
|
// path.
|
|
LayeredDirectoryNode top = lPath.getTopLayer();
|
|
newDir.setLayerID(top.getLayerID());
|
|
}
|
|
else
|
|
{
|
|
// Otherwise we issue a brand new layer id.
|
|
|
|
// note: re-use generated node id as a layer id
|
|
newDir.setLayerID(newDir.getId());
|
|
}
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(newDir);
|
|
|
|
if (child != null)
|
|
{
|
|
newDir.setAncestor(child);
|
|
}
|
|
|
|
// newDir.setVersionID(getNextVersionID());
|
|
//dir.updateModTime();
|
|
dir.putChild(name, newDir);
|
|
}
|
|
|
|
/**
|
|
* Create a new file.
|
|
* @param path The path to the directory to contain the new file.
|
|
* @param name The name to give the new file.
|
|
* initial content.
|
|
*/
|
|
public OutputStream createFile(String path, String name)
|
|
{
|
|
return createFile(path, name, null, null).getContentOutputStream();
|
|
}
|
|
|
|
/**
|
|
* Create a file with the given contents.
|
|
* @param path The path to the containing directory.
|
|
* @param name The name to give the new file.
|
|
* @param data The contents.
|
|
*/
|
|
public void createFile(String path, String name, File data, List<QName> aspects, Map<QName, PropertyValue> properties)
|
|
{
|
|
createFile(path, name, aspects, properties).putContent(data);
|
|
}
|
|
|
|
private ContentWriter createFile(String path, String name, List<QName> aspects, Map<QName, PropertyValue> properties)
|
|
{
|
|
Lookup lPath = lookupDirectory(-1, path, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, dir, PermissionService.ADD_CHILDREN, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write: " + path);
|
|
}
|
|
Pair<AVMNode, Boolean> temp = dir.lookupChild(lPath, name, true);
|
|
AVMNode child = (temp == null) ? null : temp.getFirst();
|
|
if (child != null && child.getType() != AVMNodeType.DELETED_NODE)
|
|
{
|
|
throw new AVMExistsException("Child exists: " + name);
|
|
}
|
|
|
|
PlainFileNodeImpl file = new PlainFileNodeImpl(this);
|
|
|
|
file.setContentData(new ContentData(null,
|
|
RawServices.Instance().getMimetypeService().guessMimetype(name),
|
|
-1,
|
|
"UTF-8"));
|
|
|
|
DbAccessControlList acl = dir.getAcl();
|
|
file.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null);
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.save(file);
|
|
|
|
// file.setVersionID(getNextVersionID());
|
|
//dir.updateModTime();
|
|
dir.putChild(name, file);
|
|
if (child != null)
|
|
{
|
|
file.setAncestor(child);
|
|
}
|
|
|
|
if (aspects != null)
|
|
{
|
|
Set<QName> aspectQNames = new HashSet<QName>(aspects.size());
|
|
aspectQNames.addAll(aspects);
|
|
file.setAspects(aspectQNames);
|
|
}
|
|
if (properties != null)
|
|
{
|
|
Map<QName, PropertyValue> props = new HashMap<QName, PropertyValue>(properties.size());
|
|
props.putAll(properties);
|
|
file.setProperties(props);
|
|
}
|
|
|
|
return createContentWriter(AVMNodeConverter.ExtendAVMPath(path, name), true);
|
|
}
|
|
|
|
/**
|
|
* Create a new layered file.
|
|
* @param srcPath The target indirection for the layered file.
|
|
* @param dstPath The path to the directory to contain the new file.
|
|
* @param name The name of the new file.
|
|
*/
|
|
public void createLayeredFile(String srcPath, String dstPath, String name)
|
|
{
|
|
Lookup lPath = lookupDirectory(-1, dstPath, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + dstPath + " not found.");
|
|
}
|
|
DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, dir, PermissionService.ADD_CHILDREN, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write: " + dstPath);
|
|
}
|
|
Pair<AVMNode, Boolean> temp = dir.lookupChild(lPath, name, true);
|
|
AVMNode child = (temp == null) ? null : temp.getFirst();
|
|
if (child != null && child.getType() != AVMNodeType.DELETED_NODE)
|
|
{
|
|
throw new AVMExistsException("Child exists: " + name);
|
|
}
|
|
// TODO Reexamine decision to not check validity of srcPath. Warning for now.
|
|
String[] srcPathParts = srcPath.split(":");
|
|
String[] dstPathParts = dstPath.split(":");
|
|
|
|
Lookup lPathSrc = null;
|
|
if (srcPathParts[0].equals(dstPathParts[0]))
|
|
{
|
|
lPathSrc = lookup(-1, srcPathParts[1], false, false);
|
|
}
|
|
else
|
|
{
|
|
AVMStore srcStore = AVMDAOs.Instance().fAVMStoreDAO.getByName(srcPathParts[0]);
|
|
if (srcStore != null)
|
|
{
|
|
lPathSrc = srcStore.lookup(-1, srcPathParts[1], false, false);
|
|
}
|
|
}
|
|
|
|
AVMNode srcNode = null;
|
|
if (lPathSrc == null)
|
|
{
|
|
logger.warn("CreateLayeredFile: srcPath not found: "+srcPath);
|
|
}
|
|
else
|
|
{
|
|
srcNode = (AVMNode)lPathSrc.getCurrentNode();
|
|
if (! (srcNode instanceof FileNode))
|
|
{
|
|
logger.warn("CreateLayeredFile: srcPath is not a file: "+srcPath);
|
|
}
|
|
}
|
|
|
|
LayeredFileNodeImpl newFile =
|
|
new LayeredFileNodeImpl(srcPath, this, null);
|
|
|
|
DbAccessControlList acl = dir.getAcl();
|
|
newFile.setAcl(acl != null ? acl.getCopy(acl.getId(), ACLCopyMode.INHERIT) : null);
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.save(newFile);
|
|
|
|
if (child != null)
|
|
{
|
|
newFile.setAncestor(child);
|
|
}
|
|
else
|
|
{
|
|
if ((srcNode != null) && (srcNode instanceof FileNode))
|
|
{
|
|
newFile.setAncestor((FileNode)srcNode);
|
|
}
|
|
}
|
|
|
|
// newFile.setVersionID(getNextVersionID());
|
|
//dir.updateModTime();
|
|
dir.putChild(name, newFile);
|
|
}
|
|
|
|
/**
|
|
* Get an input stream from a file.
|
|
* @param version The version id to look under.
|
|
* @param path The path to the file.
|
|
* @return An InputStream.
|
|
*/
|
|
public InputStream getInputStream(int version, String path)
|
|
{
|
|
ContentReader reader = getContentReader(version, path);
|
|
if (reader == null)
|
|
{
|
|
// TODO This is wrong, wrong, wrong. Do something about it
|
|
// sooner rather than later.
|
|
throw new AVMNotFoundException(path + " has no content.");
|
|
}
|
|
return reader.getContentInputStream();
|
|
}
|
|
|
|
/**
|
|
* Get a ContentReader from a file.
|
|
* @param version The version to look under.
|
|
* @param path The path to the file.
|
|
* @return A ContentReader.
|
|
*/
|
|
public ContentReader getContentReader(int version, String path)
|
|
{
|
|
try
|
|
{
|
|
NodeRef nodeRef = AVMNodeConverter.ToNodeRef(version, getName() + ":" + path);
|
|
return RawServices.Instance().getContentService().getReader(nodeRef, ContentModel.PROP_CONTENT);
|
|
}
|
|
catch (InvalidNodeRefException inre)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a ContentWriter to a file.
|
|
* @param path The path to the file.
|
|
* @return A ContentWriter.
|
|
* @param update true if the property must be updated atomically when the content write
|
|
* stream is closed (attaches a listener to the stream); false if the client code
|
|
* will perform the updates itself.
|
|
*/
|
|
public ContentWriter createContentWriter(String path, boolean update)
|
|
{
|
|
try
|
|
{
|
|
NodeRef nodeRef = AVMNodeConverter.ToNodeRef(-1, getName() + ":" + path);
|
|
ContentWriter writer =
|
|
RawServices.Instance().getContentService().getWriter(nodeRef, ContentModel.PROP_CONTENT, update);
|
|
return writer;
|
|
}
|
|
catch (InvalidNodeRefException inre)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a listing from 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,
|
|
boolean includeDeleted)
|
|
{
|
|
Lookup lPath = lookupDirectory(version, path, false);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, dir, PermissionService.READ_CHILDREN, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to read: " + path);
|
|
}
|
|
Map<String, AVMNode> listing = dir.getListing(lPath, includeDeleted);
|
|
return translateListing(listing, lPath);
|
|
}
|
|
|
|
/**
|
|
* Get the list of nodes directly contained in a directory.
|
|
* @param version The version to look under.
|
|
* @param path The path to the directory.
|
|
* @return A Map of names to descriptors.
|
|
*/
|
|
public SortedMap<String, AVMNodeDescriptor> getListingDirect(int version, String path,
|
|
boolean includeDeleted)
|
|
{
|
|
Lookup lPath = lookupDirectory(version, path, false);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, dir, PermissionService.READ_CHILDREN, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to read: " + path);
|
|
}
|
|
if (lPath.isLayered() && dir.getType() != AVMNodeType.LAYERED_DIRECTORY)
|
|
{
|
|
return new TreeMap<String, AVMNodeDescriptor>();
|
|
}
|
|
Map<String, AVMNode> listing = dir.getListingDirect(lPath, includeDeleted);
|
|
return translateListing(listing, lPath);
|
|
}
|
|
|
|
/**
|
|
* Helper to convert an internal representation of a directory listing
|
|
* to an external representation.
|
|
* @param listing The internal listing, a Map of names to nodes.
|
|
* @param lPath The Lookup for the directory.
|
|
* @return A Map of names to descriptors.
|
|
*/
|
|
private SortedMap<String, AVMNodeDescriptor>
|
|
translateListing(Map<String, AVMNode> listing, Lookup lPath)
|
|
{
|
|
SortedMap<String, AVMNodeDescriptor> results = new TreeMap<String, AVMNodeDescriptor>(String.CASE_INSENSITIVE_ORDER);
|
|
for (String name : listing.keySet())
|
|
{
|
|
// TODO consider doing this at a lower level.
|
|
AVMNode child = listing.get(name);
|
|
AVMNodeDescriptor desc = child.getDescriptor(lPath, name);
|
|
results.put(name, desc);
|
|
}
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* Get the names of the 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)
|
|
{
|
|
Lookup lPath = lookupDirectory(version, path, false);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, dir, PermissionService.READ_CHILDREN, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to read: " + path);
|
|
}
|
|
List<String> deleted = dir.getDeletedNames();
|
|
return deleted;
|
|
}
|
|
|
|
/**
|
|
* Get an output stream to a file.
|
|
* @param path The path to the file.
|
|
* @return An OutputStream.
|
|
*/
|
|
public OutputStream getOutputStream(String path)
|
|
{
|
|
ContentWriter writer = createContentWriter(path, true);
|
|
return writer.getContentOutputStream();
|
|
}
|
|
|
|
/**
|
|
* 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 removeNode(String path, String name)
|
|
{
|
|
Lookup lPath = lookupDirectory(-1, path, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
|
|
DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode();
|
|
Pair<AVMNode, Boolean> temp = dir.lookupChild(lPath, name, false);
|
|
AVMNode child = (temp == null) ? null : temp.getFirst();
|
|
if (child == null)
|
|
{
|
|
Lookup lPathToChild = lookup(-1, path+"/"+name, true, false);
|
|
if (lPathToChild != null)
|
|
{
|
|
// ETHREEOH-2297
|
|
child = lPathToChild.getCurrentNode();
|
|
}
|
|
if (child == null)
|
|
{
|
|
throw new AVMNotFoundException("Does not exist: " + name);
|
|
}
|
|
|
|
dir = lPathToChild.getCurrentNodeDirectory();
|
|
}
|
|
|
|
if (!fAVMRepository.can(this, child, PermissionService.DELETE_NODE, false))
|
|
{
|
|
throw new AVMNotFoundException("Not allowed to delete in store : " + getName() +" at " + path);
|
|
}
|
|
|
|
dir.removeChild(lPath, name);
|
|
//dir.updateModTime();
|
|
}
|
|
|
|
/**
|
|
* Allow a name which has been deleted to be visible through that layer.
|
|
* @param dirPath The path to the containing directory.
|
|
* @param name The name to uncover.
|
|
*/
|
|
public void uncover(String dirPath, String name)
|
|
{
|
|
Lookup lPath = lookupDirectory(-1, dirPath, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Directory path " + dirPath + " not found.");
|
|
}
|
|
DirectoryNode node = (DirectoryNode)lPath.getCurrentNode();
|
|
if (node.getType() != AVMNodeType.LAYERED_DIRECTORY)
|
|
{
|
|
throw new AVMWrongTypeException("Not a layered directory: " + dirPath);
|
|
}
|
|
Pair<AVMNode, Boolean> temp = node.lookupChild(lPath, name, true);
|
|
AVMNode child = (temp == null) ? null : temp.getFirst();
|
|
if(child == null)
|
|
{
|
|
throw new AVMNotFoundException("No child to recover at "+dirPath+" called "+name);
|
|
}
|
|
if (!fAVMRepository.can(this, child, PermissionService.DELETE_NODE, false))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to uncover: " + dirPath + " -> "+name);
|
|
}
|
|
((LayeredDirectoryNode)node).uncover(lPath, name);
|
|
node.updateModTime();
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(node);
|
|
}
|
|
|
|
/**
|
|
* Get the set of all extant versions for this AVMStore.
|
|
* @return A Set of version ids.
|
|
*/
|
|
public List<VersionDescriptor> getVersions()
|
|
{
|
|
List<VersionRoot> versions = AVMDAOs.Instance().fVersionRootDAO.getAllInAVMStore(this);
|
|
List<VersionDescriptor> descs = new ArrayList<VersionDescriptor>();
|
|
for (VersionRoot vr : versions)
|
|
{
|
|
VersionDescriptor desc =
|
|
new VersionDescriptor(getName(),
|
|
vr.getVersionID(),
|
|
vr.getCreator(),
|
|
vr.getCreateDate(),
|
|
vr.getTag(),
|
|
vr.getDescription());
|
|
descs.add(desc);
|
|
}
|
|
return descs;
|
|
}
|
|
|
|
/**
|
|
* Get the versions between the given dates (inclusive). From or
|
|
* to may be null but not both.
|
|
* @param from The earliest date.
|
|
* @param to The latest date.
|
|
* @return The Set of matching version IDs.
|
|
*/
|
|
public List<VersionDescriptor> getVersions(Date from, Date to)
|
|
{
|
|
List<VersionRoot> versions = AVMDAOs.Instance().fVersionRootDAO.getByDates(this, from, to);
|
|
List<VersionDescriptor> descs = new ArrayList<VersionDescriptor>();
|
|
for (VersionRoot vr : versions)
|
|
{
|
|
VersionDescriptor desc =
|
|
new VersionDescriptor(getName(),
|
|
vr.getVersionID(),
|
|
vr.getCreator(),
|
|
vr.getCreateDate(),
|
|
vr.getTag(),
|
|
vr.getDescription());
|
|
descs.add(desc);
|
|
}
|
|
return descs;
|
|
}
|
|
|
|
|
|
|
|
public List<VersionDescriptor> getVersionsTo(int version)
|
|
{
|
|
List<VersionRoot> versions = AVMDAOs.Instance().fVersionRootDAO.getByVersionsTo(this, version);
|
|
List<VersionDescriptor> descs = new ArrayList<VersionDescriptor>();
|
|
for (VersionRoot vr : versions)
|
|
{
|
|
VersionDescriptor desc =
|
|
new VersionDescriptor(getName(),
|
|
vr.getVersionID(),
|
|
vr.getCreator(),
|
|
vr.getCreateDate(),
|
|
vr.getTag(),
|
|
vr.getDescription());
|
|
descs.add(desc);
|
|
}
|
|
return descs;
|
|
}
|
|
|
|
public List<VersionDescriptor> getVersionsFrom(int version)
|
|
{
|
|
List<VersionRoot> versions = AVMDAOs.Instance().fVersionRootDAO.getByVersionsFrom(this, version);
|
|
List<VersionDescriptor> descs = new ArrayList<VersionDescriptor>();
|
|
for (VersionRoot vr : versions)
|
|
{
|
|
VersionDescriptor desc =
|
|
new VersionDescriptor(getName(),
|
|
vr.getVersionID(),
|
|
vr.getCreator(),
|
|
vr.getCreateDate(),
|
|
vr.getTag(),
|
|
vr.getDescription());
|
|
descs.add(desc);
|
|
}
|
|
return descs;
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<VersionDescriptor> getVersionsBetween(int startVersion, int endVersion)
|
|
{
|
|
List<VersionRoot> versions = AVMDAOs.Instance().fVersionRootDAO.getByVersionsBetween(this, startVersion, endVersion);
|
|
List<VersionDescriptor> descs = new ArrayList<VersionDescriptor>();
|
|
for (VersionRoot vr : versions)
|
|
{
|
|
VersionDescriptor desc =
|
|
new VersionDescriptor(getName(),
|
|
vr.getVersionID(),
|
|
vr.getCreator(),
|
|
vr.getCreateDate(),
|
|
vr.getTag(),
|
|
vr.getDescription());
|
|
descs.add(desc);
|
|
}
|
|
return descs;
|
|
}
|
|
|
|
/**
|
|
* Get the AVMRepository.
|
|
* @return The AVMRepository
|
|
*/
|
|
public AVMRepository getAVMRepository()
|
|
{
|
|
return fAVMRepository;
|
|
}
|
|
|
|
/**
|
|
* Lookup up a path.
|
|
* @param version The version to look in.
|
|
* @param path The path to look up.
|
|
* @param write Whether this is in the context of a write.
|
|
* @return A Lookup object.
|
|
*/
|
|
public Lookup lookup(int version, String path, boolean write, boolean includeDeleted)
|
|
{
|
|
SimplePath sPath = new SimplePath(path);
|
|
return RawServices.Instance().getLookupCache().lookup(this, version, sPath, write, includeDeleted);
|
|
}
|
|
|
|
/**
|
|
* Get the root node descriptor.
|
|
* @param version The version to get.
|
|
* @return The descriptor.
|
|
*/
|
|
public AVMNodeDescriptor getRoot(int version)
|
|
{
|
|
AVMNode root = null;
|
|
if (version < 0)
|
|
{
|
|
root = getRoot();
|
|
}
|
|
else
|
|
{
|
|
root = AVMDAOs.Instance().fAVMNodeDAO.getAVMStoreRoot(this, version);
|
|
}
|
|
if (!fAVMRepository.can(this, root, PermissionService.READ_CHILDREN, true))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to read: " + getName() + "@" + version);
|
|
}
|
|
return root.getDescriptor(getName() + ":", "", null, -1);
|
|
}
|
|
|
|
/**
|
|
* Lookup a node and insist that it is a directory.
|
|
* @param version The version to look under.
|
|
* @param path The path to the directory.
|
|
* @param write Whether this is in a write context.
|
|
* @return A Lookup object.
|
|
*/
|
|
public Lookup lookupDirectory(int version, String path, boolean write)
|
|
{
|
|
// Just do a regular lookup and assert that the last element
|
|
// is a directory.
|
|
Lookup lPath = lookup(version, path, write, false);
|
|
if (lPath == null)
|
|
{
|
|
return null;
|
|
}
|
|
if (lPath.getCurrentNode().getType() != AVMNodeType.PLAIN_DIRECTORY &&
|
|
lPath.getCurrentNode().getType() != AVMNodeType.LAYERED_DIRECTORY)
|
|
{
|
|
return null;
|
|
}
|
|
return lPath;
|
|
}
|
|
|
|
/**
|
|
* Get the effective indirection path for a layered node.
|
|
* @param version The version to look under.
|
|
* @param path The path to the node.
|
|
* @return The effective indirection.
|
|
*/
|
|
public String getIndirectionPath(int version, String path)
|
|
{
|
|
Lookup lPath = lookup(version, path, false, false);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
if (!lPath.isLayered())
|
|
{
|
|
return null;
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to read: " + path);
|
|
}
|
|
if (node.getType() == AVMNodeType.LAYERED_DIRECTORY)
|
|
{
|
|
LayeredDirectoryNode dir = (LayeredDirectoryNode)node;
|
|
return dir.getUnderlying(lPath);
|
|
}
|
|
else if (node.getType() == AVMNodeType.LAYERED_FILE)
|
|
{
|
|
LayeredFileNode file = (LayeredFileNode)node;
|
|
return file.getUnderlying(lPath);
|
|
}
|
|
return lPath.getIndirectionPath();
|
|
}
|
|
|
|
/**
|
|
* Make the indicated node a primary indirection.
|
|
* @param path The path to the node.
|
|
*/
|
|
public void makePrimary(String path)
|
|
{
|
|
Lookup lPath = lookupDirectory(-1, path, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode();
|
|
if (!lPath.isLayered())
|
|
{
|
|
throw new AVMException("Not in a layered context: " + path);
|
|
}
|
|
if (!fAVMRepository.can(this, dir, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write: " + path);
|
|
}
|
|
dir.turnPrimary(lPath);
|
|
dir.updateModTime();
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(dir);
|
|
}
|
|
|
|
/**
|
|
* Change the indirection of a layered directory.
|
|
* @param path The path to the layered directory.
|
|
* @param target The target indirection to set.
|
|
*/
|
|
public void retargetLayeredDirectory(String path, String target)
|
|
{
|
|
Lookup lPath = lookupDirectory(-1, path, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode();
|
|
if (!lPath.isLayered())
|
|
{
|
|
throw new AVMException("Not in a layered context: " + path);
|
|
}
|
|
if (!fAVMRepository.can(this, dir, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write: " + path);
|
|
}
|
|
dir.retarget(lPath, target);
|
|
dir.updateModTime();
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(dir);
|
|
}
|
|
|
|
/**
|
|
* Set the name of this AVMStore.
|
|
* @param name
|
|
*/
|
|
public void setName(String name)
|
|
{
|
|
fName = name;
|
|
}
|
|
|
|
/**
|
|
* Get the name of this AVMStore.
|
|
* @return The name.
|
|
*/
|
|
public String getName()
|
|
{
|
|
return fName;
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.avm.AVMStore#getAcl()
|
|
*/
|
|
public DbAccessControlList getStoreAcl()
|
|
{
|
|
return fACL;
|
|
}
|
|
|
|
public void setStoreAcl(DbAccessControlList acl)
|
|
{
|
|
fACL = acl;
|
|
}
|
|
|
|
/**
|
|
* Set the next version id.
|
|
* @param nextVersionID
|
|
*/
|
|
public void setNextVersionID(int nextVersionID)
|
|
{
|
|
fNextVersionID = nextVersionID;
|
|
}
|
|
|
|
/**
|
|
* Get the next version id.
|
|
* @return The next version id.
|
|
*/
|
|
public int getNextVersionID()
|
|
{
|
|
return fNextVersionID;
|
|
}
|
|
|
|
/**
|
|
* This gets the last extant version id.
|
|
*/
|
|
public int getLastVersionID()
|
|
{
|
|
Integer lastVersionId = AVMDAOs.Instance().fVersionRootDAO.getMaxVersionID(this);
|
|
if (lastVersionId == null)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return lastVersionId.intValue();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the root directory.
|
|
* @param root
|
|
*/
|
|
public void setRoot(DirectoryNode root)
|
|
{
|
|
fRoot = root;
|
|
}
|
|
|
|
/**
|
|
* Get the root directory.
|
|
* @return The root directory.
|
|
*/
|
|
public DirectoryNode getRoot()
|
|
{
|
|
return fRoot;
|
|
}
|
|
|
|
/**
|
|
* Set the version (for concurrency control).
|
|
* @param vers The version for optimistic locks.
|
|
*/
|
|
public void setVers(long vers)
|
|
{
|
|
fVers = vers;
|
|
}
|
|
|
|
/**
|
|
* Get the version (for concurrency control).
|
|
* @return The version for optimistic locks.
|
|
*/
|
|
public long getVers()
|
|
{
|
|
return fVers;
|
|
}
|
|
|
|
/**
|
|
* Equals override.
|
|
* @param obj
|
|
* @return Equality.
|
|
*/
|
|
@Override
|
|
public boolean equals(Object obj)
|
|
{
|
|
if (this == obj)
|
|
{
|
|
return true;
|
|
}
|
|
if (!(obj instanceof AVMStore))
|
|
{
|
|
return false;
|
|
}
|
|
return getId() == ((AVMStore)obj).getId();
|
|
}
|
|
|
|
/**
|
|
* Get a hash code.
|
|
* @return The hash code.
|
|
*/
|
|
@Override
|
|
public int hashCode()
|
|
{
|
|
return (int)getId();
|
|
}
|
|
|
|
/**
|
|
* Purge all nodes reachable only via this version and repository.
|
|
* @param version
|
|
*/
|
|
public void purgeVersion(int version)
|
|
{
|
|
if (version == 0)
|
|
{
|
|
throw new AVMBadArgumentException("Cannot purge initial version");
|
|
}
|
|
VersionRoot vRoot = AVMDAOs.Instance().fVersionRootDAO.getByVersionID(this, version);
|
|
if (vRoot == null)
|
|
{
|
|
throw new AVMNotFoundException("Version not found.");
|
|
}
|
|
AVMDAOs.Instance().fVersionLayeredNodeEntryDAO.delete(vRoot);
|
|
AVMNode root = vRoot.getRoot();
|
|
if (!fAVMRepository.can(null, root, PermissionService.DELETE_CHILDREN, true))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to purge: " + getName() + "@" + version);
|
|
}
|
|
root.setIsRoot(false);
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(root);
|
|
AVMDAOs.Instance().fVersionRootDAO.delete(vRoot);
|
|
if (root.equals(getRoot()))
|
|
{
|
|
// We have to set a new current root.
|
|
vRoot = AVMDAOs.Instance().fVersionRootDAO.getMaxVersion(this);
|
|
setRoot(vRoot.getRoot());
|
|
AVMDAOs.Instance().fAVMStoreDAO.update(this);
|
|
}
|
|
}
|
|
|
|
// TODO permissions?
|
|
/**
|
|
* Get the descriptor for this.
|
|
* @return An AVMStoreDescriptor
|
|
*/
|
|
public AVMStoreDescriptor getDescriptor()
|
|
{
|
|
// Get the creator ensuring that nulls are not hit
|
|
PropertyValue creatorValue = getProperty(ContentModel.PROP_CREATOR);
|
|
String creator = (creatorValue == null ? AuthenticationUtil.SYSTEM_USER_NAME : (String) creatorValue.getValue(DataTypeDefinition.TEXT));
|
|
creator = (creator == null ? AuthenticationUtil.SYSTEM_USER_NAME : creator);
|
|
// Get the created date ensuring that nulls are not hit
|
|
PropertyValue createdValue = getProperty(ContentModel.PROP_CREATED);
|
|
Date created = createdValue == null ? (new Date()) : (Date) createdValue.getValue(DataTypeDefinition.DATE);
|
|
created = (created == null) ? (new Date()) : created;
|
|
return new AVMStoreDescriptor(getId(), getName(), creator, created.getTime());
|
|
}
|
|
|
|
/**
|
|
* Set the opacity of a layered directory. An opaque directory hides
|
|
* what is pointed at by its indirection.
|
|
* @param path The path to the layered directory.
|
|
* @param opacity True is opaque; false is not.
|
|
*/
|
|
public void setOpacity(String path, boolean opacity)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, false);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!(node instanceof LayeredDirectoryNode))
|
|
{
|
|
throw new AVMWrongTypeException("Not a LayeredDirectoryNode.");
|
|
}
|
|
if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write: " + path);
|
|
}
|
|
((LayeredDirectoryNode)node).setOpacity(opacity);
|
|
node.updateModTime();
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(node);
|
|
}
|
|
|
|
// TODO Does it make sense to set properties on DeletedNodes?
|
|
/**
|
|
* Set a property on a node.
|
|
* @param path The path to the node.
|
|
* @param name The name of the property.
|
|
* @param value The value to set.
|
|
*/
|
|
public void setNodeProperty(String path, QName name, PropertyValue value)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write: " + path);
|
|
}
|
|
|
|
node.setProperty(name, value);
|
|
|
|
node.setGuid(GUID.generate());
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(node); // guid and property
|
|
}
|
|
|
|
/**
|
|
* Set a collection of properties on a node.
|
|
* @param path The path to the node.
|
|
* @param properties The Map of QNames to PropertyValues.
|
|
*/
|
|
public void setNodeProperties(String path, Map<QName, PropertyValue> properties)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write: " + path);
|
|
}
|
|
if (properties != null)
|
|
{
|
|
Map<QName, PropertyValue> props = new HashMap<QName, PropertyValue>(properties.size());
|
|
props.putAll(properties);
|
|
node.addProperties(props);
|
|
}
|
|
node.setGuid(GUID.generate());
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(node);
|
|
}
|
|
|
|
/**
|
|
* Get a property by name.
|
|
* @param version The version to lookup.
|
|
* @param path The path to the node.
|
|
* @param name The name of the property.
|
|
* @return A PropertyValue or null if not found.
|
|
*/
|
|
public PropertyValue getNodeProperty(int version, String path, QName name)
|
|
{
|
|
Lookup lPath = lookup(version, path, false, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to read: " + path);
|
|
}
|
|
|
|
return node.getProperty(name);
|
|
}
|
|
|
|
/**
|
|
* Get all the properties associated with a node.
|
|
* @param version The version to lookup.
|
|
* @param path The path to the node.
|
|
* @return A Map of QNames to PropertyValues.
|
|
*/
|
|
public Map<QName, PropertyValue> getNodeProperties(int version, String path)
|
|
{
|
|
Lookup lPath = lookup(version, path, false, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to read: " + path);
|
|
}
|
|
|
|
return node.getProperties();
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write: " + path);
|
|
}
|
|
node.setGuid(GUID.generate());
|
|
|
|
node.deleteProperty(name);
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(node);
|
|
}
|
|
|
|
/**
|
|
* Delete all properties from a node.
|
|
* @param path The path to the node.
|
|
*/
|
|
public void deleteNodeProperties(String path)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write: " + path);
|
|
}
|
|
node.setGuid(GUID.generate());
|
|
node.deleteProperties();
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(node);
|
|
}
|
|
|
|
/**
|
|
* Set a property on this store. Replaces if property already exists.
|
|
* @param name The QName of the property.
|
|
* @param value The actual PropertyValue.
|
|
*/
|
|
public void setProperty(QName name, PropertyValue value)
|
|
{
|
|
AVMStoreProperty prop = new AVMStorePropertyImpl();
|
|
prop.setStore(this);
|
|
prop.setQname(name);
|
|
prop.setValue(value);
|
|
AVMDAOs.Instance().fAVMStorePropertyDAO.save(prop);
|
|
}
|
|
|
|
/**
|
|
* Set a group of properties on this store. Replaces any property that exists.
|
|
* @param properties A Map of QNames to PropertyValues to set.
|
|
*/
|
|
public void setProperties(Map<QName, PropertyValue> properties)
|
|
{
|
|
for (QName name : properties.keySet())
|
|
{
|
|
setProperty(name, properties.get(name));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a property by name.
|
|
* @param name The QName of the property to fetch.
|
|
* @return The PropertyValue or null if non-existent.
|
|
*/
|
|
public PropertyValue getProperty(QName name)
|
|
{
|
|
return AVMDAOs.Instance().fAVMStorePropertyDAO.get(this, name);
|
|
}
|
|
|
|
/**
|
|
* Get all the properties associated with this store.
|
|
* @return A Map of the properties.
|
|
*/
|
|
public Map<QName, PropertyValue> getProperties()
|
|
{
|
|
return AVMDAOs.Instance().fAVMStorePropertyDAO.get(this);
|
|
}
|
|
|
|
/**
|
|
* Delete a property.
|
|
* @param name The name of the property to delete.
|
|
*/
|
|
public void deleteProperty(QName name)
|
|
{
|
|
AVMDAOs.Instance().fAVMStorePropertyDAO.delete(this, name);
|
|
}
|
|
|
|
/**
|
|
* Get the ContentData on a file.
|
|
* @param version The version to look under.
|
|
* @param path The path to the file.
|
|
* @return The ContentData corresponding to the file.
|
|
*/
|
|
public ContentData getContentDataForRead(int version, String path)
|
|
{
|
|
Lookup lPath = lookup(version, path, false, false);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!(node instanceof FileNode))
|
|
{
|
|
throw new AVMWrongTypeException("File Expected.");
|
|
}
|
|
if (!fAVMRepository.can(this, node, PermissionService.READ_CONTENT, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to read: " + path);
|
|
}
|
|
ContentData content = ((FileNode)node).getContentData(lPath);
|
|
// AVMDAOs.Instance().fAVMNodeDAO.evict(node);
|
|
return content;
|
|
}
|
|
|
|
/**
|
|
* Get the ContentData on a file for writing.
|
|
* @param path The path to the file.
|
|
* @return The ContentData corresponding to the file.
|
|
*/
|
|
public ContentData getContentDataForWrite(String path)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, false);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!(node instanceof FileNode))
|
|
{
|
|
throw new AVMWrongTypeException("File Expected.");
|
|
}
|
|
if (!fAVMRepository.can(this, node, PermissionService.WRITE_CONTENT, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write content: " + path);
|
|
}
|
|
// TODO Set modifier.
|
|
node.updateModTime();
|
|
node.setGuid(GUID.generate());
|
|
|
|
//AVMDAOs.Instance().fAVMNodeDAO.update(node);
|
|
// TODO review 'optimisation'
|
|
AVMDAOs.Instance().fAVMNodeDAO.updateModTimeAndGuid(node);
|
|
|
|
ContentData content = ((FileNode)node).getContentData(lPath);
|
|
// AVMDAOs.Instance().fAVMNodeDAO.evict(node);
|
|
return content;
|
|
}
|
|
|
|
// Not doing permission checking because it will already have been done
|
|
// at the getContentDataForWrite point.
|
|
/**
|
|
* Set the ContentData for a file.
|
|
* @param path The path to the file.
|
|
* @param data The ContentData to set.
|
|
*/
|
|
public void setContentData(String path, ContentData data)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, false);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!(node instanceof FileNode))
|
|
{
|
|
throw new AVMWrongTypeException("File Expected.");
|
|
}
|
|
((FileNode)node).setContentData(data);
|
|
node.updateModTime();
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(node);
|
|
}
|
|
|
|
/**
|
|
* Set meta data, aspects, properties, acls, from another node.
|
|
* @param path The path to the node to set metadata on.
|
|
* @param from The node to get the metadata from.
|
|
*/
|
|
public void setMetaDataFrom(String path, AVMNode from)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path not found: " + path);
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write properties: " + path);
|
|
}
|
|
node.copyMetaDataFrom(from, node.getAcl() == null ? null : node.getAcl().getInheritsFrom());
|
|
node.setGuid(GUID.generate());
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(node);
|
|
}
|
|
|
|
/**
|
|
* Add an aspect to a node.
|
|
* @param path The path to the node.
|
|
* @param aspectName The name of the aspect.
|
|
*/
|
|
public void addAspect(String path, QName aspectName)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write: " + path);
|
|
}
|
|
|
|
node.addAspect(aspectName);
|
|
node.setGuid(GUID.generate());
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(node);
|
|
}
|
|
|
|
/**
|
|
* Get all aspects on a given node.
|
|
* @param version The version to look under.
|
|
* @param path The path to the node.
|
|
* @return A List of the QNames of the aspects.
|
|
*/
|
|
public Set<QName> getAspects(int version, String path)
|
|
{
|
|
Lookup lPath = lookup(version, path, false, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to read properties: " + path);
|
|
}
|
|
|
|
return node.getAspects();
|
|
}
|
|
|
|
/**
|
|
* Remove an aspect and all its 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)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write properties: " + path);
|
|
}
|
|
|
|
node.removeAspect(aspectName);
|
|
|
|
AspectDefinition def = RawServices.Instance().getDictionaryService().getAspect(aspectName);
|
|
Map<QName, PropertyDefinition> properties = def.getProperties();
|
|
|
|
for (QName propertyQName : properties.keySet())
|
|
{
|
|
node.deleteProperty(propertyQName);
|
|
}
|
|
|
|
node.setGuid(GUID.generate());
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(node);
|
|
}
|
|
|
|
/**
|
|
* Does a given node have a given 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)
|
|
{
|
|
Lookup lPath = lookup(version, path, false, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.READ_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to read properties: " + path);
|
|
}
|
|
|
|
return node.getAspects().contains(aspectName);
|
|
}
|
|
|
|
/**
|
|
* Set the ACL on a node.
|
|
* @param path The path to the node.
|
|
* @param acl The ACL to set.
|
|
*/
|
|
public void setACL(String path, DbAccessControlList acl)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.CHANGE_PERMISSIONS, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to change permissions: " + path);
|
|
}
|
|
node.setAcl(acl);
|
|
node.setGuid(GUID.generate());
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(node);
|
|
}
|
|
|
|
/**
|
|
* Get the ACL on a node.
|
|
* @param version The version to look under.
|
|
* @param path The path to the node.
|
|
* @return The ACL.
|
|
*/
|
|
public DbAccessControlList getACL(int version, String path)
|
|
{
|
|
Lookup lPath = lookup(version, path, false, false);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
if (!fAVMRepository.can(this, lPath.getCurrentNode(), PermissionService.READ_PERMISSIONS, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to read permissions: " + path + " in "+getName());
|
|
}
|
|
return lPath.getCurrentNode().getAcl();
|
|
}
|
|
|
|
/**
|
|
* Link a node into a directory, directly.
|
|
* @param parentPath The path to the directory.
|
|
* @param name The name to give the parent.
|
|
* @param toLink The node to link.
|
|
*/
|
|
public void link(String parentPath, String name, AVMNodeDescriptor toLink)
|
|
{
|
|
Lookup lPath = lookupDirectory(-1, parentPath, true);
|
|
if (lPath == null)
|
|
{
|
|
String pathParts[] = AVMUtil.splitBase(parentPath);
|
|
Lookup lPath2 = lookup(-1, pathParts[0], true, false);
|
|
if (lPath2 != null)
|
|
{
|
|
DirectoryNode parent = (DirectoryNode)lPath2.getCurrentNode();
|
|
Pair<AVMNode, Boolean> temp = parent.lookupChild(lPath2, pathParts[1], false);
|
|
if ((temp != null) && (temp.getFirst() != null))
|
|
{
|
|
DirectoryNode dir = (DirectoryNode)temp.getFirst();
|
|
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("Found: "+dir);
|
|
}
|
|
|
|
boolean directlyContained = false;
|
|
|
|
if (!fAVMRepository.can(null, dir, PermissionService.ADD_CHILDREN, directlyContained))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to add children: " + parentPath);
|
|
}
|
|
|
|
AVMNodeDescriptor desc = fAVMRepository.forceCopy(AVMUtil.buildAVMPath(this.getName(), parentPath));
|
|
fAVMRepository.link(desc, name, toLink);
|
|
return;
|
|
}
|
|
}
|
|
|
|
throw new AVMNotFoundException("Path " + parentPath + " not found.");
|
|
}
|
|
DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(null, dir, PermissionService.ADD_CHILDREN, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to add children: " + parentPath);
|
|
}
|
|
dir.link(lPath, name, toLink);
|
|
}
|
|
|
|
/**
|
|
* Update a link to a node in a directory, directly.
|
|
* @param parentPath The path to the directory.
|
|
* @param name The name to give the parent.
|
|
* @param toLink The node to link.
|
|
*/
|
|
public void updateLink(String parentPath, String name, AVMNodeDescriptor toLink)
|
|
{
|
|
Lookup lPath = lookupDirectory(-1, parentPath, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + parentPath + " not found.");
|
|
}
|
|
DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode();
|
|
|
|
Lookup cPath = new Lookup(lPath, AVMDAOs.Instance().fAVMNodeDAO, AVMDAOs.Instance().fAVMStoreDAO);
|
|
Pair<AVMNode, Boolean> result = dir.lookupChild(cPath, name, true);
|
|
if (result != null)
|
|
{
|
|
AVMNode child = result.getFirst();
|
|
if (!fAVMRepository.can(null, child, PermissionService.WRITE, cPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to update node: " + parentPath + "/" +name );
|
|
}
|
|
dir.removeChild(lPath, name);
|
|
}
|
|
dir.link(lPath, name, toLink);
|
|
}
|
|
|
|
/**
|
|
* Revert a head path to a given version. This works by cloning
|
|
* the version to revert to, and then linking that new version into head.
|
|
* The reverted version will have the previous head version as ancestor.
|
|
* @param path The path to the parent directory.
|
|
* @param name The name of the node to revert.
|
|
* @param toRevertTo The descriptor of the version to revert to.
|
|
*/
|
|
public void revert(String path, String name, AVMNodeDescriptor toRevertTo)
|
|
{
|
|
Lookup lPath = lookupDirectory(-1, path, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path " + path + " not found.");
|
|
}
|
|
DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode();
|
|
|
|
Pair<AVMNode, Boolean> temp = dir.lookupChild(lPath, name, true);
|
|
AVMNode child = (temp == null) ? null : temp.getFirst();
|
|
if (child == null)
|
|
{
|
|
throw new AVMNotFoundException("Node not found: " + name);
|
|
}
|
|
if (!fAVMRepository.can(null, child, PermissionService.WRITE, false))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to revert: " + path);
|
|
}
|
|
AVMNode revertNode = AVMDAOs.Instance().fAVMNodeDAO.getByID(toRevertTo.getId());
|
|
if (revertNode == null)
|
|
{
|
|
throw new AVMNotFoundException(toRevertTo.toString());
|
|
}
|
|
AVMNode toLink = revertNode.copy(lPath);
|
|
dir.putChild(name, toLink);
|
|
toLink.changeAncestor(child);
|
|
toLink.setVersionID(child.getVersionID() + 1);
|
|
|
|
toLink.addAspect(WCMModel.ASPECT_REVERTED);
|
|
|
|
PropertyValue value = new PropertyValue(null, toRevertTo.getId());
|
|
toLink.setProperty(WCMModel.PROP_REVERTED_ID, value);
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(toLink);
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.avm.AVMStore#setGuid(java.lang.String, java.lang.String)
|
|
*/
|
|
public void setGuid(String path, String guid)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, true);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path not found: " + path);
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write properties: " + path);
|
|
}
|
|
node.setGuid(guid);
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(node);
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.avm.AVMStore#setEncoding(java.lang.String, java.lang.String)
|
|
*/
|
|
public void setEncoding(String path, String encoding)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, false);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path not found: " + path);
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (node.getType() != AVMNodeType.PLAIN_FILE)
|
|
{
|
|
throw new AVMWrongTypeException("Not a File: " + path);
|
|
}
|
|
if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write properties: " + path);
|
|
}
|
|
PlainFileNode file = (PlainFileNode)node;
|
|
ContentData contentData = file.getContentData();
|
|
contentData = ContentData.setEncoding(contentData, encoding);
|
|
file.setContentData(contentData);
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(file);
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see org.alfresco.repo.avm.AVMStore#setMimeType(java.lang.String, java.lang.String)
|
|
*/
|
|
public void setMimeType(String path, String mimeType)
|
|
{
|
|
Lookup lPath = lookup(-1, path, true, false);
|
|
if (lPath == null)
|
|
{
|
|
throw new AVMNotFoundException("Path not found: " + path);
|
|
}
|
|
AVMNode node = lPath.getCurrentNode();
|
|
if (node.getType() != AVMNodeType.PLAIN_FILE)
|
|
{
|
|
throw new AVMWrongTypeException("Not a File: " + path);
|
|
}
|
|
if (!fAVMRepository.can(this, node, PermissionService.WRITE_PROPERTIES, lPath.getDirectlyContained()))
|
|
{
|
|
throw new AccessDeniedException("Not allowed to write properties: " + path);
|
|
}
|
|
PlainFileNode file = (PlainFileNode)node;
|
|
ContentData contentData = file.getContentData();
|
|
contentData = ContentData.setMimetype(contentData, mimeType);
|
|
file.setContentData(contentData);
|
|
|
|
AVMDAOs.Instance().fAVMNodeDAO.update(file);
|
|
}
|
|
|
|
// for debug
|
|
@Override
|
|
public String toString()
|
|
{
|
|
return getName();
|
|
}
|
|
}
|