Merged DEV/SWIFT to HEAD

27125: Subtasks of ALF-7072: RSOLR 013: Remote API to get ACLs and readers
          - ALF-8334: RSOLR 013: Modify ACL schema to record change times
          - ALF-8336: RSOLR 013: DB upgrade scripts for ACL changes
          - TODO: Query APIs
   27128: Added TooManyResultsException as a concurrency detection trigger
          - Usually too many results indicates that the DB table key is not as specific as it should be,
            but it's AVM that showed this up.
   27132: Clean up: javadocs; non-javadocs; uncommented fields; @since tags; etc.
   27134: Removed empty directory
   27135: Fix for ALF-8333: CMIS query: JOIN on an aspect results in CmisInvalidArgumentException
          - incorrect scope used when building orderings
   27139: Fixed SORL transaction tracking queries
          - Queries were using incompatible boolean comparisons
          - Added SOLRDAO to test suite
          - Cleaned up code and reformatted code
   27141: Minor additions to CannedQuery interface
          - get parameter bean
          - construct sort details from a list
          - ALF-7167: Canned queries
   27146: RINF 09 / RINF 10: DB-based paged query for get children (DocLib & CMIS) 
          - milestone check-in for sprint demo & review (WIP)
          - added new FileFolderService (paged) list query (public API is subject to change)
          - moved temp JavaScript sorting to Java
          - example usage by DocLib (via ScriptNode) and CMIS (via AlfrescoCmisService)
          - implemented as demo "canned query" including embedded use of "list" permission interceptor
          - ALF-7402 / ALF-7168
   27150: RINF 09 / RINF 10: DB-based paged query for get children (DocLib & CMIS) 
          - missed file (follow-on to r27146)
   27158: ALF-7070, ALF-7072: SOLR tracking (node and changeset)
          - Pulled non-DAO code into SOLRTrackingComponent
          - DAO code and related tests just test basic CRUD
          - SOLRTrackingComponent does complex cross-schema manipulation
   27159: Fixed line ending and removed svn:eol-style
   27160: ALF-8334: RSOLR 013: Fixed SQL Server syntax
   27165: RINF 09 / RINF 10: DB-based paged query for get children (DocLib & CMIS) 
          - fix listDeepFolders (causing Imap*Test to fail) 
          - all private methods now order files followed by folders
		    (consistent with existing public APIs such as FileFolderService.search & ScriptNode.childFileFolders*)
          - follow-on to r27146
   28271: Consolidate diagnostic logging for max perm checks (ALF-8388 + ALF-8419)
          - note: this should be a trivial merge to HEAD

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@28292 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2011-06-08 17:29:54 +00:00
parent 2f697cebb9
commit efbd951a10
55 changed files with 4434 additions and 2609 deletions

View File

@@ -0,0 +1,112 @@
/*
* Copyright (C) 2005-2011 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.solr;
/**
* Filters for node metadata results e.g. include properties, aspect, ... or not
*
* @since 4.0
*
*/
public class MetaDataResultsFilter
{
private boolean includeProperties = true;
private boolean includeAspects = true;
private boolean includeType = true;
private boolean includeAclId = true;
private boolean includeOwner = true;
private boolean includePaths = true;
private boolean includeAssociations = false;
private boolean includeChildAssociations = true;
private boolean includeNodeRef = true;
public boolean getIncludeChildAssociations()
{
return includeChildAssociations;
}
public void setIncludeChildAssociations(boolean includeChildAssociations)
{
this.includeChildAssociations = includeChildAssociations;
}
public boolean getIncludeNodeRef()
{
return includeNodeRef;
}
public void setIncludeNodeRef(boolean includeNodeRef)
{
this.includeNodeRef = includeNodeRef;
}
public boolean getIncludeAssociations()
{
return includeAssociations;
}
public void setIncludeAssociations(boolean includeAssociations)
{
this.includeAssociations = includeAssociations;
}
public boolean getIncludeProperties()
{
return includeProperties;
}
public void setIncludeProperties(boolean includeProperties)
{
this.includeProperties = includeProperties;
}
public boolean getIncludeAspects()
{
return includeAspects;
}
public void setIncludeAspects(boolean includeAspects)
{
this.includeAspects = includeAspects;
}
public boolean getIncludeType()
{
return includeType;
}
public void setIncludeType(boolean includeType)
{
this.includeType = includeType;
}
public boolean getIncludeAclId()
{
return includeAclId;
}
public void setIncludeAclId(boolean includeAclId)
{
this.includeAclId = includeAclId;
}
public boolean getIncludeOwner()
{
return includeOwner;
}
public void setIncludeOwner(boolean includeOwner)
{
this.includeOwner = includeOwner;
}
public boolean getIncludePaths()
{
return includePaths;
}
public void setIncludePaths(boolean includePaths)
{
this.includePaths = includePaths;
}
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright (C) 2005-2011 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.solr;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
/**
*
* @since 4.0
*/
public class NodeMetaData
{
private Long nodeId;
private NodeRef nodeRef;
private String owner;
private QName nodeType;
private Long aclId;
private Map<QName, Serializable> properties;
private Set<QName> aspects;
// private List<Path> paths;
private Collection<Pair<Path, QName>> paths;
private List<ChildAssociationRef> childAssocs;
public String getOwner()
{
return owner;
}
public void setOwner(String owner)
{
this.owner = owner;
}
public NodeRef getNodeRef()
{
return nodeRef;
}
public void setNodeRef(NodeRef nodeRef)
{
this.nodeRef = nodeRef;
}
public Collection<Pair<Path, QName>> getPaths()
{
return paths;
}
public void setPaths(Collection<Pair<Path, QName>> paths)
{
this.paths = paths;
}
public QName getNodeType()
{
return nodeType;
}
public void setNodeType(QName nodeType)
{
this.nodeType = nodeType;
}
public Long getNodeId()
{
return nodeId;
}
public void setNodeId(Long nodeId)
{
this.nodeId = nodeId;
}
public Long getAclId()
{
return aclId;
}
public void setAclId(Long aclId)
{
this.aclId = aclId;
}
public Map<QName, Serializable> getProperties()
{
return properties;
}
public void setProperties(Map<QName, Serializable> properties)
{
this.properties = properties;
}
public Set<QName> getAspects()
{
return aspects;
}
public void setAspects(Set<QName> aspects)
{
this.aspects = aspects;
}
public List<ChildAssociationRef> getChildAssocs()
{
return childAssocs;
}
public void setChildAssocs(List<ChildAssociationRef> childAssocs)
{
this.childAssocs = childAssocs;
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2005-2011 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.solr;
import java.util.List;
/**
* Stores node meta data query parameters for use in SOLR DAO queries
*
* @since 4.0
*/
public class NodeMetaDataParameters
{
private List<Long> transactionIds;
private Long fromTxnId;
private Long toTxnId;
// default is 'all' results
private int maxResults = 0;
private Long fromNodeId;
private Long toNodeId;
private List<Long> nodeIds;
public int getMaxResults()
{
return maxResults;
}
public void setMaxResults(int maxResults)
{
this.maxResults = maxResults;
}
public List<Long> getNodeIds()
{
return nodeIds;
}
public void setNodeIds(List<Long> nodeIds)
{
this.nodeIds = nodeIds;
}
public void setTransactionIds(List<Long> txnIds)
{
this.transactionIds = txnIds;
}
public List<Long> getTransactionIds()
{
return transactionIds;
}
public Long getFromTxnId()
{
return fromTxnId;
}
public void setFromTxnId(Long fromTxnId)
{
this.fromTxnId = fromTxnId;
}
public Long getToTxnId()
{
return toTxnId;
}
public void setToTxnId(Long toTxnId)
{
this.toTxnId = toTxnId;
}
public Long getFromNodeId()
{
return fromNodeId;
}
public void setFromNodeId(Long fromNodeId)
{
this.fromNodeId = fromNodeId;
}
public Long getToNodeId()
{
return toNodeId;
}
public void setToNodeId(Long toNodeId)
{
this.toNodeId = toNodeId;
}
}

View File

@@ -0,0 +1,176 @@
/*
* Copyright (C) 2005-2011 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.solr;
import java.util.List;
import java.util.Set;
import org.alfresco.service.namespace.QName;
/**
* Stores node query parameters for use in SOLR DAO queries
*
* @since 4.0
*/
public class NodeParameters
{
private List<Long> transactionIds;
private Long fromTxnId;
private Long toTxnId;
private Long fromNodeId;
private Long toNodeId;
// default is 'all' results
private int maxResults = 0;
private String storeProtocol;
private String storeIdentifier;
private Set<QName> includeNodeTypes;
private Set<QName> excludeNodeTypes;
private Set<QName> includeAspects;
private Set<QName> excludeAspects;
public int getMaxResults()
{
return maxResults;
}
public void setMaxResults(int maxResults)
{
this.maxResults = maxResults;
}
public boolean getStoreFilter()
{
return (storeProtocol != null || storeIdentifier != null);
}
public void setStoreProtocol(String storeProtocol)
{
this.storeProtocol = storeProtocol;
}
public String getStoreProtocol()
{
return storeProtocol;
}
public void setStoreIdentifier(String storeIdentifier)
{
this.storeIdentifier = storeIdentifier;
}
public String getStoreIdentifier()
{
return storeIdentifier;
}
public void setTransactionIds(List<Long> txnIds)
{
this.transactionIds = txnIds;
}
public List<Long> getTransactionIds()
{
return transactionIds;
}
public Long getFromTxnId()
{
return fromTxnId;
}
public void setFromTxnId(Long fromTxnId)
{
this.fromTxnId = fromTxnId;
}
public Long getToTxnId()
{
return toTxnId;
}
public void setToTxnId(Long toTxnId)
{
this.toTxnId = toTxnId;
}
public Long getFromNodeId()
{
return fromNodeId;
}
public void setFromNodeId(Long fromNodeId)
{
this.fromNodeId = fromNodeId;
}
public Long getToNodeId()
{
return toNodeId;
}
public void setToNodeId(Long toNodeId)
{
this.toNodeId = toNodeId;
}
public Set<QName> getIncludeNodeTypes()
{
return includeNodeTypes;
}
public Set<QName> getExcludeNodeTypes()
{
return excludeNodeTypes;
}
public Set<QName> getIncludeAspects()
{
return includeAspects;
}
public Set<QName> getExcludeAspects()
{
return excludeAspects;
}
public void setIncludeNodeTypes(Set<QName> includeNodeTypes)
{
this.includeNodeTypes = includeNodeTypes;
}
public void setExcludeNodeTypes(Set<QName> excludeNodeTypes)
{
this.excludeNodeTypes = excludeNodeTypes;
}
public void setIncludeAspects(Set<QName> includeAspects)
{
this.includeAspects = includeAspects;
}
public void setExcludeAspects(Set<QName> excludeAspects)
{
this.excludeAspects = excludeAspects;
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2005-2011 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.solr;
import java.util.List;
import org.alfresco.repo.domain.node.Node;
import org.alfresco.repo.domain.solr.AclChangeSet;
import org.alfresco.repo.domain.solr.Transaction;
/**
* Interface for component to provide tracking data for SOLR.
*
* @since 4.0
*/
public interface SOLRTrackingComponent
{
/**
* Get the ACL changesets for given range parameters
*
* @param minAclChangeSetId minimum ACL changeset ID - (inclusive and optional)
* @param fromCommitTime minimum ACL commit time - (inclusive and optional)
* @param maxResults limit the results. 0 or Integer.MAX_VALUE does not limit the results
* @return list of ACL changesets
*/
public List<AclChangeSet> getAclChangeSets(Long minAclChangeSetId, Long fromCommitTime, int maxResults);
/**
* Get the transactions from either minTxnId or fromCommitTime, optionally limited to maxResults
*
* @param minTxnId greater than or equal to minTxnId
* @param fromCommitTime greater than or equal to transaction commit time
* @param maxResults limit the results. 0 or Integer.MAX_VALUE does not limit the results
* @return list of transactions
*/
public List<Transaction> getTransactions(Long minTxnId, Long fromCommitTime, int maxResults);
/**
* Get the nodes satisfying the constraints in nodeParameters
*
* @param nodeParameters set of constraints for which nodes to return
* @param maxResults limit the results. 0 or Integer.MAX_VALUE does not limit the results
* @param callback a callback to receive the results
*/
public void getNodes(NodeParameters nodeParameters, NodeQueryCallback callback);
/**
* Returns metadata for a set of node ids
*
* @param nodeIds a set of nodeIds for which to return node metadata
* @param maxResults limit the results. 0 or Integer.MAX_VALUE does not limit the results
* @param callback a callback to receive the results
*/
public void getNodesMetadata(NodeMetaDataParameters nodeMetaDataParameters, MetaDataResultsFilter resultFilter, NodeMetaDataQueryCallback callback);
/**
* The interface that will be used to give query results to the calling code.
*/
public interface NodeQueryCallback
{
/**
* Handle a node.
*
* @param node the node
* @return Return <tt>true</tt> to continue processing rows or <tt>false</tt> to stop
*/
boolean handleNode(Node node);
}
/**
* The interface that will be used to give query results to the calling code.
*/
public interface NodeMetaDataQueryCallback
{
/**
* Handle a node.
*
* @param node the node meta data
* @return Return <tt>true</tt> to continue processing rows or <tt>false</tt> to stop
*/
boolean handleNodeMetaData(NodeMetaData nodeMetaData);
}
}

View File

@@ -0,0 +1,546 @@
/*
* Copyright (C) 2005-2011 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.solr;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.node.Node;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.node.NodeDAO.ChildAssocRefQueryCallback;
import org.alfresco.repo.domain.qname.QNameDAO;
import org.alfresco.repo.domain.solr.AclChangeSet;
import org.alfresco.repo.domain.solr.SOLRDAO;
import org.alfresco.repo.domain.solr.Transaction;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyCheck;
/**
* Component providing data for SOLR tracking
*
* @since 4.0
*/
public class SOLRTrackingComponentImpl implements SOLRTrackingComponent
{
private NodeDAO nodeDAO;
private QNameDAO qnameDAO;
private SOLRDAO solrDAO;
private OwnableService ownableService;
private TenantService tenantService;
private DictionaryService dictionaryService;
public void setSolrDAO(SOLRDAO solrDAO)
{
this.solrDAO = solrDAO;
}
public void setNodeDAO(NodeDAO nodeDAO)
{
this.nodeDAO = nodeDAO;
}
public void setQnameDAO(QNameDAO qnameDAO)
{
this.qnameDAO = qnameDAO;
}
public void setOwnableService(OwnableService ownableService)
{
this.ownableService = ownableService;
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* Initialize
*/
public void init()
{
PropertyCheck.mandatory(this, "solrDAO", solrDAO);
PropertyCheck.mandatory(this, "nodeDAO", nodeDAO);
PropertyCheck.mandatory(this, "qnameDAO", qnameDAO);
PropertyCheck.mandatory(this, "ownableService", ownableService);
PropertyCheck.mandatory(this, "tenantService", tenantService);
PropertyCheck.mandatory(this, "dictionaryService", dictionaryService);
}
@Override
public List<AclChangeSet> getAclChangeSets(Long minAclChangeSetId, Long fromCommitTime, int maxResults)
{
List<AclChangeSet> changesets = solrDAO.getAclChangeSets(minAclChangeSetId, fromCommitTime, maxResults);
return changesets;
}
@Override
public List<Transaction> getTransactions(Long minTxnId, Long fromCommitTime, int maxResults)
{
List<Transaction> txns = solrDAO.getTransactions(minTxnId, fromCommitTime, maxResults);
return txns;
}
/**
* {@inheritDoc}
*/
public void getNodes(NodeParameters nodeParameters, NodeQueryCallback callback)
{
List<Node> nodes = solrDAO.getNodes(nodeParameters);
for (Node node : nodes)
{
callback.handleNode(node);
}
}
/**
* A dumb iterator that iterates over longs in sequence.
*/
private static class SequenceIterator implements Iterable<Long>, Iterator<Long>
{
private long fromId;
private long toId;
private long counter;
private int maxResults;
private boolean inUse = false;
SequenceIterator(Long fromId, Long toId, int maxResults)
{
this.fromId = (fromId == null ? 1 : fromId.longValue());
this.toId = (toId == null ? Long.MAX_VALUE : toId.longValue());
this.maxResults = maxResults;
this.counter = this.fromId;
}
@Override
public Iterator<Long> iterator()
{
if(inUse)
{
throw new IllegalStateException("Already in use");
}
this.counter = this.fromId;
this.inUse = true;
return this;
}
@Override
public boolean hasNext()
{
return ((counter - this.fromId) < maxResults) && counter <= toId;
}
@Override
public Long next()
{
return counter++;
}
@Override
public void remove()
{
throw new UnsupportedOperationException();
}
}
private boolean isCategorised(AspectDefinition aspDef)
{
if(aspDef == null)
{
return false;
}
AspectDefinition current = aspDef;
while (current != null)
{
if (current.getName().equals(ContentModel.ASPECT_CLASSIFIABLE))
{
return true;
}
else
{
QName parentName = current.getParentName();
if (parentName == null)
{
break;
}
current = dictionaryService.getAspect(parentName);
}
}
return false;
}
private Collection<Pair<Path, QName>> getCategoryPaths(NodeRef nodeRef, Set<QName> aspects, Map<QName, Serializable> properties)
{
ArrayList<Pair<Path, QName>> categoryPaths = new ArrayList<Pair<Path, QName>>();
for (QName classRef : aspects)
{
AspectDefinition aspDef = dictionaryService.getAspect(classRef);
if (!isCategorised(aspDef))
{
continue;
}
LinkedList<Pair<Path, QName>> aspectPaths = new LinkedList<Pair<Path, QName>>();
for (PropertyDefinition propDef : aspDef.getProperties().values())
{
if (propDef.getDataType().getName().equals(DataTypeDefinition.CATEGORY))
{
for (NodeRef catRef : DefaultTypeConverter.INSTANCE.getCollection(NodeRef.class, properties.get(propDef.getName())))
{
if (catRef == null)
{
continue;
}
// can be running in context of System user, hence use input nodeRef
catRef = tenantService.getName(nodeRef, catRef);
try
{
Pair<Long, NodeRef> pair = nodeDAO.getNodePair(catRef);
for (Path path : nodeDAO.getPaths(pair, false))
{
if ((path.size() > 1) && (path.get(1) instanceof Path.ChildAssocElement))
{
Path.ChildAssocElement cae = (Path.ChildAssocElement) path.get(1);
boolean isFakeRoot = true;
final List<ChildAssociationRef> results = new ArrayList<ChildAssociationRef>(10);
// We have a callback handler to filter results
ChildAssocRefQueryCallback callback = new ChildAssocRefQueryCallback()
{
public boolean preLoadNodes()
{
return false;
}
public boolean handle(
Pair<Long, ChildAssociationRef> childAssocPair,
Pair<Long, NodeRef> parentNodePair,
Pair<Long, NodeRef> childNodePair)
{
results.add(childAssocPair.getSecond());
return true;
}
public void done()
{
}
};
Pair<Long, NodeRef> caePair = nodeDAO.getNodePair(cae.getRef().getChildRef());
nodeDAO.getParentAssocs(caePair.getFirst(), null, null, false, callback);
for (ChildAssociationRef car : results)
{
if (cae.getRef().equals(car))
{
isFakeRoot = false;
break;
}
}
if (isFakeRoot)
{
if (path.toString().indexOf(aspDef.getName().toString()) != -1)
{
aspectPaths.add(new Pair<Path, QName>(path, aspDef.getName()));
}
}
}
}
}
catch (InvalidNodeRefException e)
{
// If the category does not exists we move on the next
}
}
}
}
categoryPaths.addAll(aspectPaths);
}
// Add member final element
for (Pair<Path, QName> pair : categoryPaths)
{
if (pair.getFirst().last() instanceof Path.ChildAssocElement)
{
Path.ChildAssocElement cae = (Path.ChildAssocElement) pair.getFirst().last();
ChildAssociationRef assocRef = cae.getRef();
pair.getFirst().append(new Path.ChildAssocElement(new ChildAssociationRef(assocRef.getTypeQName(), assocRef.getChildRef(), QName.createQName("member"), nodeRef)));
}
}
return categoryPaths;
}
private List<Long> preCacheNodes(NodeMetaDataParameters nodeMetaDataParameters)
{
int maxResults = nodeMetaDataParameters.getMaxResults();
boolean isLimitSet = (maxResults != 0 && maxResults != Integer.MAX_VALUE);
List<Long> nodeIds = null;
Iterable<Long> iterable = null;
List<Long> allNodeIds = nodeMetaDataParameters.getNodeIds();
if(allNodeIds != null)
{
int toIndex = (maxResults > allNodeIds.size() ? allNodeIds.size() : maxResults);
nodeIds = isLimitSet ? allNodeIds.subList(0, toIndex) : nodeMetaDataParameters.getNodeIds();
iterable = nodeMetaDataParameters.getNodeIds();
}
else
{
Long fromNodeId = nodeMetaDataParameters.getFromNodeId();
Long toNodeId = nodeMetaDataParameters.getToNodeId();
nodeIds = new ArrayList<Long>(isLimitSet ? maxResults : 100); // TODO better default here?
iterable = new SequenceIterator(fromNodeId, toNodeId, maxResults);
int counter = 1;
for(Long nodeId : iterable)
{
if(isLimitSet && counter++ > maxResults)
{
break;
}
nodeIds.add(nodeId);
}
}
// pre-cache nodes
nodeDAO.cacheNodesById(nodeIds);
return nodeIds;
}
/**
* {@inheritDoc}
*/
public void getNodesMetadata(
NodeMetaDataParameters nodeMetaDataParameters,
MetaDataResultsFilter resultFilter,
NodeMetaDataQueryCallback callback)
{
NodeMetaDataQueryRowHandler rowHandler = new NodeMetaDataQueryRowHandler(callback);
boolean includeType = (resultFilter == null ? true : resultFilter.getIncludeType());
boolean includeProperties = (resultFilter == null ? true : resultFilter.getIncludeProperties());
boolean includeAspects = (resultFilter == null ? true : resultFilter.getIncludeAspects());
boolean includePaths = (resultFilter == null ? true : resultFilter.getIncludePaths());
boolean includeNodeRef = (resultFilter == null ? true : resultFilter.getIncludeNodeRef());
boolean includeAssociations = (resultFilter == null ? true : resultFilter.getIncludeAssociations());
boolean includeChildAssociations = (resultFilter == null ? true : resultFilter.getIncludeChildAssociations());
boolean includeOwner = (resultFilter == null ? true : resultFilter.getIncludeOwner());
List<Long> nodeIds = preCacheNodes(nodeMetaDataParameters);
for(Long nodeId : nodeIds)
{
Map<QName, Serializable> props = null;
Set<QName> aspects = null;
if (!nodeDAO.exists(nodeId))
{
// Deleted nodes have no metadata
continue;
}
NodeMetaData nodeMetaData = new NodeMetaData();
nodeMetaData.setNodeId(nodeId);
Pair<Long, NodeRef> pair = nodeDAO.getNodePair(nodeId);
nodeMetaData.setAclId(nodeDAO.getNodeAclId(nodeId));
if(includeType)
{
QName nodeType = nodeDAO.getNodeType(nodeId);
nodeMetaData.setNodeType(nodeType);
}
if(includePaths || includeProperties)
{
props = nodeDAO.getNodeProperties(nodeId);
}
nodeMetaData.setProperties(props);
if(includePaths || includeAspects)
{
aspects = nodeDAO.getNodeAspects(nodeId);
}
nodeMetaData.setAspects(aspects);
// TODO paths may change during get i.e. node moved around in the graph
if(includePaths)
{
Collection<Pair<Path, QName>> categoryPaths = getCategoryPaths(pair.getSecond(), aspects, props);
List<Path> directPaths = nodeDAO.getPaths(pair, false);
Collection<Pair<Path, QName>> paths = new ArrayList<Pair<Path, QName>>(directPaths.size() + categoryPaths.size());
for (Path path : directPaths)
{
paths.add(new Pair<Path, QName>(path, null));
}
paths.addAll(categoryPaths);
nodeMetaData.setPaths(paths);
}
if(includeNodeRef)
{
nodeMetaData.setNodeRef(pair.getSecond());
}
if(includeChildAssociations)
{
final List<ChildAssociationRef> childAssocs = new ArrayList<ChildAssociationRef>(100);
nodeDAO.getChildAssocs(nodeId, null, null, null, null, null, new ChildAssocRefQueryCallback()
{
@Override
public boolean preLoadNodes()
{
return false;
}
@Override
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair, Pair<Long, NodeRef> parentNodePair,
Pair<Long, NodeRef> childNodePair)
{
childAssocs.add(childAssocPair.getSecond());
return true;
}
@Override
public void done()
{
}
});
nodeMetaData.setChildAssocs(childAssocs);
}
if(includeAssociations)
{
final List<ChildAssociationRef> parentAssocs = new ArrayList<ChildAssociationRef>(100);
nodeDAO.getParentAssocs(nodeId, null, null, null, new ChildAssocRefQueryCallback()
{
@Override
public boolean handle(Pair<Long, ChildAssociationRef> childAssocPair,
Pair<Long, NodeRef> parentNodePair, Pair<Long, NodeRef> childNodePair)
{
parentAssocs.add(childAssocPair.getSecond());
return true;
}
@Override
public boolean preLoadNodes()
{
return false;
}
@Override
public void done()
{
}
});
// TODO non-child associations
// Collection<Pair<Long, AssociationRef>> sourceAssocs = nodeDAO.getSourceNodeAssocs(nodeId);
// Collection<Pair<Long, AssociationRef>> targetAssocs = nodeDAO.getTargetNodeAssocs(nodeId);
//
// nodeMetaData.setAssocs();
}
if(includeOwner)
{
// cached in OwnableService
nodeMetaData.setOwner(ownableService.getOwner(pair.getSecond()));
}
rowHandler.processResult(nodeMetaData);
}
}
/**
* Class that passes results from a result entity into the client callback
*/
protected class NodeQueryRowHandler
{
private final NodeQueryCallback callback;
private boolean more;
private NodeQueryRowHandler(NodeQueryCallback callback)
{
this.callback = callback;
this.more = true;
}
public void processResult(Node row)
{
if (!more)
{
// No more results required
return;
}
more = callback.handleNode(row);
}
}
/**
* Class that passes results from a result entity into the client callback
*/
protected class NodeMetaDataQueryRowHandler
{
private final NodeMetaDataQueryCallback callback;
private boolean more;
private NodeMetaDataQueryRowHandler(NodeMetaDataQueryCallback callback)
{
this.callback = callback;
this.more = true;
}
public void processResult(NodeMetaData row)
{
if (!more)
{
// No more results required
return;
}
more = callback.handleNodeMetaData(row);
}
}
}

File diff suppressed because it is too large Load Diff