Derek Hulley a49bfd311d Merged V2.2 to HEAD
7575: Permission changes for AVM.
   7577: Incorporated most of the feedback provided by Kevin C earlier today
   7578: Removed directory not removed by patch
   7579: EmailServer bug fixes
         AR-1902:  Double posts when emailing to a document
         AR-1904:  Attachments via email should be allowed on forum posts
         AR-1903:  (Partial Fix) Text attachments should be treated the same way as other attachments 
   7583: Fixed WCM-961 & WCM-962: Added confirm dialog for 'Delete All Deployment Reports' and 'Release Server' actions


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8434 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2008-03-06 14:43:55 +00:00

540 lines
17 KiB
Java

/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing" */
package org.alfresco.repo.avm;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.util.Pair;
/**
* This holds all the information necessary to perform operations
* on AVMNodes, and is structured internally as a list of path components
* from the root directory of a repository.
* @author britt
*/
class Lookup implements Serializable
{
private static final long serialVersionUID = -2844833688622561L;
/**
* Is this lookup valid?
*/
private boolean fValid;
/**
* The AVMStore.
*/
private AVMStore fAVMStore;
/**
* The name of the AVMStore.
*/
private String fStoreName;
/**
* The components that make up this path.
*/
private List<LookupComponent> fComponents;
/**
* The final store in resolving layers.
*/
private AVMStore fFinalStore;
/**
* Whether, at this point, a layered node has been hit.
* Used while building a Lookup.
*/
private boolean fLayeredYet;
/**
* Whether we are directly contained at this point.
*/
private boolean fDirectlyContained;
/**
* The first LayeredDirectoryNode in the path.
*/
private LayeredDirectoryNode fTopLayer;
/**
* The path index of the top LayeredDirectoryNode in the path.
*/
private int fTopLayerIndex;
/**
* The lowest layered directory node's index seen so far.
*/
private int fLowestLayerIndex;
/**
* The current component being looked at by this lookup.
*/
private int fPosition;
/**
* Whether a needs-to-be-copied component has been seen.
*/
private boolean fNeedsCopying;
/**
* The version that is being looked up.
*/
private int fVersion;
public Lookup(Lookup other, AVMNodeDAO nodeDAO, AVMStoreDAO storeDAO)
{
fValid = true;
fAVMStore = storeDAO.getByID(other.fAVMStore.getId());
fVersion = other.fVersion;
if (fAVMStore == null)
{
fValid = false;
return;
}
fStoreName = fAVMStore.getName();
fComponents = new ArrayList<LookupComponent>();
fLayeredYet = other.fLayeredYet;
if (other.fTopLayer != null)
{
fTopLayer = (LayeredDirectoryNode)nodeDAO.getByID(other.fTopLayer.getId());
if (fTopLayer == null)
{
fValid = false;
return;
}
}
fPosition = other.fPosition;
fTopLayerIndex = other.fTopLayerIndex;
fLowestLayerIndex = other.fLowestLayerIndex;
fNeedsCopying = other.fNeedsCopying;
fDirectlyContained = other.fDirectlyContained;
if (fLayeredYet)
{
for (LookupComponent comp : other.fComponents)
{
LookupComponent newComp = new LookupComponent();
newComp.setName(comp.getName());
newComp.setIndirection(comp.getIndirection());
newComp.setIndirectionVersion(comp.getIndirectionVersion());
newComp.setNode(nodeDAO.getByID(comp.getNode().getId()));
if (newComp.getNode() == null)
{
fValid = false;
return;
}
fComponents.add(newComp);
}
}
else
{
// If this is not a layered lookup then we do not
// need to reload any of the actual nodes except for
// the last.
int i = 0;
for (; i < fPosition; ++i)
{
LookupComponent comp = other.fComponents.get(i);
LookupComponent newComp = new LookupComponent();
newComp.setName(comp.getName());
fComponents.add(newComp);
}
LookupComponent comp = other.fComponents.get(i);
LookupComponent newComp = new LookupComponent();
newComp.setName(comp.getName());
newComp.setNode(nodeDAO.getByID(comp.getNode().getId()));
if (newComp.getNode() == null)
{
fValid = false;
return;
}
fComponents.add(newComp);
}
fFinalStore = storeDAO.getByID(other.fFinalStore.getId());
if (fFinalStore == null)
{
fValid = false;
}
}
/**
* Create a new one.
* @param store The AVMStore that's being looked in.
* @param storeName The name of that AVMStore.
*/
public Lookup(AVMStore store, String storeName, int version)
{
fValid = true;
fAVMStore = store;
fStoreName = storeName;
fVersion = version;
fComponents = new ArrayList<LookupComponent>();
fLayeredYet = false;
fTopLayer = null;
fPosition = -1;
fTopLayerIndex = -1;
fLowestLayerIndex = -1;
fNeedsCopying = false;
fDirectlyContained = true;
fFinalStore = store;
}
/**
* Is this a valid lookup?
*/
public boolean isValid()
{
return fValid;
}
// TODO This is badly in need of cleanup.
/**
* Add a new node to the lookup.
* @param node The node to add.
* @param name The name of the node in the path.
* @param write Whether this is in the context of
* a write operation.
*/
public void add(AVMNode node, String name, boolean directlyContained, boolean write)
{
LookupComponent comp = new LookupComponent();
comp.setName(name);
comp.setNode(node);
if (fPosition >= 0 && fDirectlyContained &&
fComponents.get(fPosition).getNode().getType() == AVMNodeType.LAYERED_DIRECTORY)
{
// if (directlyContained != ((DirectoryNode)fComponents.get(fPosition).getNode()).directlyContains(node))
// {
// System.err.println("Bloody Murder!");
// }
fDirectlyContained = directlyContained;
}
if (!write)
{
if (node.getType() == AVMNodeType.LAYERED_DIRECTORY)
{
LayeredDirectoryNode oNode = (LayeredDirectoryNode)node;
if (oNode.getPrimaryIndirection())
{
comp.setIndirection(oNode.getIndirection());
comp.setIndirectionVersion(oNode.getIndirectionVersion());
}
else
{
Pair<String, Integer> ind = computeIndirection(name);
comp.setIndirection(ind.getFirst());
comp.setIndirectionVersion(ind.getSecond());
}
fLayeredYet = true;
// Record the first layer seen.
if (fTopLayer == null)
{
fTopLayer = oNode;
fTopLayerIndex = fPosition + 1;
}
fLowestLayerIndex = fPosition + 1;
}
fComponents.add(comp);
fPosition++;
return;
}
if (!node.getIsNew())
{
fNeedsCopying = true;
}
else
{
if (fPosition >= 0 && !fDirectlyContained)
{
fNeedsCopying = true;
}
}
// Record various things if this is layered.
if (node.getType() == AVMNodeType.LAYERED_DIRECTORY)
{
LayeredDirectoryNode oNode = (LayeredDirectoryNode)node;
// Record the indirection path that should be used.
if (oNode.getPrimaryIndirection())
{
comp.setIndirection(oNode.getIndirection());
comp.setIndirectionVersion(-1);
}
else
{
Pair<String, Integer> ind = computeIndirection(name);
comp.setIndirection(ind.getFirst());
comp.setIndirectionVersion(-1);
}
fLayeredYet = true;
// Record the first layer seen.
if (fTopLayer == null)
{
fTopLayer = oNode;
fTopLayerIndex = fPosition + 1;
}
fLowestLayerIndex = fPosition + 1;
}
// In a write context a plain directory contained in a layer will
// be copied so we will need to compute an indirection path.
else if (fLayeredYet)
{
Pair<String, Integer> ind = computeIndirection(name);
comp.setIndirection(ind.getFirst());
comp.setIndirectionVersion(-1);
}
fComponents.add(comp);
fPosition++;
// If we are in a write context do copy on write.
if (fNeedsCopying)
{
node = node.copy(this);
// node.setVersionID(fAVMStore.getNextVersionID());
fComponents.get(fPosition).setNode(node);
if (fPosition == 0)
{
// Inform the store of a new root.
fAVMStore.setNewRoot((DirectoryNode)node);
AVMDAOs.Instance().fAVMStoreDAO.update(fAVMStore);
return;
}
// Not the root. Check if we are the top layer and insert this into it's parent.
if (fPosition == fTopLayerIndex)
{
fTopLayer = (LayeredDirectoryNode)node;
}
((DirectoryNode)fComponents.get(fPosition - 1).getNode()).putChild(name, node);
}
}
/**
* A helper for keeping track of indirection.
* @param name The name of the being added node.
* @return The indirection for the being added node.
*/
private Pair<String, Integer> computeIndirection(String name)
{
String parentIndirection = fComponents.get(fPosition).getIndirection();
int parentIndirectionVersion = fComponents.get(fPosition).getIndirectionVersion();
if (parentIndirection.endsWith("/"))
{
return new Pair<String, Integer>(parentIndirection + name, parentIndirectionVersion);
}
else
{
return new Pair<String, Integer>(parentIndirection + "/" + name, parentIndirectionVersion);
}
}
/**
* Return the parent node of the current node in the look up context or null if there is not one yet
* @return
*/
public DirectoryNode getCurrentNodeDirectory()
{
int position = fPosition -1;
if( (position >= 0) && (position < fComponents.size()))
{
return ((DirectoryNode)fComponents.get(fPosition - 1).getNode());
}
else
{
return null;
}
}
/**
* Get the current node we're looking at.
* @return The current node.
*/
public AVMNode getCurrentNode()
{
return fComponents.get(fPosition).getNode();
}
/**
* Is the current path layered.
* @return Whether the current position in the path is layered.
*/
public boolean isLayered()
{
return fLayeredYet;
}
/**
* Determine if a node is directly in this layer.
* @return Whether this node is directly in this layer.
*/
public boolean isInThisLayer()
{
return fLayeredYet && fDirectlyContained;
}
/**
* Get the number of nodes.
* @return The number of nodes.
*/
public int size()
{
return fComponents.size();
}
/**
* Calculate the indirection path at this node.
* @return The indirection path all the way down to the current node.
*/
public String getIndirectionPath()
{
// The path is the underlying path of the lowest layer (in the path sense)
// that is directly contained by the top layer and is a primary indirection node.
int pos = fLowestLayerIndex;
AVMNode node = fComponents.get(pos).getNode();
LayeredDirectoryNode oNode = null;
while (pos >= fTopLayerIndex && (node.getType() != AVMNodeType.LAYERED_DIRECTORY ||
(oNode = (LayeredDirectoryNode)node).getLayerID() != fTopLayer.getLayerID() ||
!oNode.getPrimaryIndirection()))
{
pos--;
node = fComponents.get(pos).getNode();
}
oNode = (LayeredDirectoryNode)node;
// We've found it.
StringBuilder builder = new StringBuilder();
builder.append(oNode.getIndirection());
for (int i = pos + 1; i <= fPosition; i++)
{
builder.append("/");
builder.append(fComponents.get(i).getName());
}
return builder.toString();
}
/**
* Get the computed indirection for the current node.
* @return The indirection.
*/
public String getCurrentIndirection()
{
String value = fComponents.get(fPosition).getIndirection();
return value;
}
/**
* Get the computed indirection version for the current node.
* @return The indirection version.
*/
public int getCurrentIndirectionVersion()
{
return fComponents.get(fPosition).getIndirectionVersion();
}
/**
* Get the topmost Layered directory node. Topmost in the
* path lookup sense.
* @return The topmost layered directory node.
*/
public LayeredDirectoryNode getTopLayer()
{
return fTopLayer;
}
/**
* Get the store that this path is in.
* @return The store.
*/
public AVMStore getAVMStore()
{
return fAVMStore;
}
/**
* Get the path represented by this lookup.
* @return The canonical path for this lookup.
*/
public String getRepresentedPath()
{
if (fComponents.size() == 1)
{
return fStoreName + ":/";
}
StringBuilder builder = new StringBuilder();
builder.append(fStoreName);
builder.append(':');
int count = fComponents.size();
for (int i = 1; i < count; i++)
{
builder.append('/');
builder.append(fComponents.get(i).getName());
}
return builder.toString();
}
/**
* Gets the final name in the lookup.
* @return The final name in the lookup.
*/
public String getBaseName()
{
return fComponents.get(fPosition).getName();
}
/**
* Set the final store the lookup occurred in.
* @param store The store to set.
*/
public void setFinalStore(AVMStore store)
{
fFinalStore = store;
}
/**
* Get the final store traversed during lookup.
* @return The final store traversed.
*/
public AVMStore getFinalStore()
{
return fFinalStore;
}
/**
* Get whether the node looked up is directly contained from the
* original root.
* @return Whether the node looked up is directly contained.
*/
public boolean getDirectlyContained()
{
return fDirectlyContained;
}
/**
* Get the version id that this is a lookup for.
* @return The version id.
*/
public int getVersion()
{
return fVersion;
}
}