mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
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:
112
source/java/org/alfresco/repo/solr/MetaDataResultsFilter.java
Normal file
112
source/java/org/alfresco/repo/solr/MetaDataResultsFilter.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
124
source/java/org/alfresco/repo/solr/NodeMetaData.java
Normal file
124
source/java/org/alfresco/repo/solr/NodeMetaData.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
111
source/java/org/alfresco/repo/solr/NodeMetaDataParameters.java
Normal file
111
source/java/org/alfresco/repo/solr/NodeMetaDataParameters.java
Normal 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;
|
||||
}
|
||||
}
|
176
source/java/org/alfresco/repo/solr/NodeParameters.java
Normal file
176
source/java/org/alfresco/repo/solr/NodeParameters.java
Normal 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;
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
1033
source/java/org/alfresco/repo/solr/SOLRTrackingComponentTest.java
Normal file
1033
source/java/org/alfresco/repo/solr/SOLRTrackingComponentTest.java
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user