/* * 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.node.db; import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import org.alfresco.repo.domain.ChildAssoc; import org.alfresco.repo.domain.NodeAssoc; import org.alfresco.repo.domain.Transaction; import org.alfresco.repo.domain.hibernate.DirtySessionAnnotation; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.service.cmr.dictionary.InvalidTypeException; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreExistsException; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.namespace.QName; import org.alfresco.util.Pair; /** * Service layer accessing persistent node entities directly * * @author Derek Hulley */ public interface NodeDaoService { /** * Are there any pending changes which must be synchronized with the store? * * @return true => changes are pending */ public boolean isDirty(); /** * Flush the data changes to the persistence layer. */ public void flush(); /** * Fetch a list of all stores in the repository * * @return Returns a list of stores */ @DirtySessionAnnotation(markDirty=false) public List> getStores(); @DirtySessionAnnotation(markDirty=false) public Pair getRootNode(StoreRef storeRef); /** * Creates a unique store for the given protocol and identifier combination. * The root node is created with the "root" aspect. * @return Returns the root node, which is added automatically. * @throws StoreExistsException if the store already exists */ @DirtySessionAnnotation(markDirty=true) public Pair createStore(StoreRef storeRef); @DirtySessionAnnotation(markDirty=false) public NodeRef.Status getNodeRefStatus(NodeRef nodeRef); /** * Create a new node. Note that allowing the uuid to be assigned by passing in a null * is more efficient. * * @param storeRef the store to which the node must belong * @param uuid the node store-unique identifier, or null to assign a GUID * @param nodeTypeQName the type of the node * @return Returns a new node Id of the given type and attached to the store * @throws InvalidTypeException if the node type is invalid or if the node type * is not a valid real node */ @DirtySessionAnnotation(markDirty=true) public Pair newNode(StoreRef storeRef, String uuid, QName nodeTypeQName) throws InvalidTypeException; @DirtySessionAnnotation(markDirty=true) public Pair moveNodeToStore(Long nodeId, StoreRef storeRef); /** * @param nodeRef the node reference * @return Returns the node entity ID */ @DirtySessionAnnotation(markDirty=false) public Pair getNodePair(NodeRef nodeRef); @DirtySessionAnnotation(markDirty=false) public Pair getNodePair(Long nodeId); @DirtySessionAnnotation(markDirty=false) public QName getNodeType(Long nodeId); @DirtySessionAnnotation(markDirty=true) public void setNodeStatus(Long nodeId); @DirtySessionAnnotation(markDirty=false) public Long getNodeAccessControlList(Long nodeId); @DirtySessionAnnotation(markDirty=true) public void setNodeAccessControlList(Long nodeId, Long aclId); /** * @param storeRef the new store or null to keep the existing one * @param uuid the new UUID for the node or null to keep it the same * @param nodeTypeQName the new type QName for the node or null to keep the existing one */ @DirtySessionAnnotation(markDirty=true) public void updateNode(Long nodeId, StoreRef storeRef, String uuid, QName nodeTypeQName); @DirtySessionAnnotation(markDirty=false) public Serializable getNodeProperty(Long nodeId, QName propertyQName); @DirtySessionAnnotation(markDirty=false) public Map getNodeProperties(Long nodeId); @DirtySessionAnnotation(markDirty=true) public void addNodeProperty(Long nodeId, QName qname, Serializable value); @DirtySessionAnnotation(markDirty=true) public void addNodeProperties(Long nodeId, Map properties); @DirtySessionAnnotation(markDirty=true) public void removeNodeProperties(Long nodeId, Set propertyQNames); @DirtySessionAnnotation(markDirty=true) public void setNodeProperties(Long nodeId, Map properties); @DirtySessionAnnotation(markDirty=false) public Set getNodeAspects(Long nodeId); @DirtySessionAnnotation(markDirty=true) public void addNodeAspects(Long nodeId, Set aspectQNames); @DirtySessionAnnotation(markDirty=true) public void removeNodeAspects(Long nodeId, Set aspectQNames); @DirtySessionAnnotation(markDirty=false) public boolean hasNodeAspect(Long nodeId, QName aspectQName); /** * Deletes the node and all entities. Note that the node entry will still exist and be * associated with a live transaction. */ @DirtySessionAnnotation(markDirty=true) public void deleteNode(Long nodeId); /** * Remove all traces of the node. This assumes that the node has been marked * for deletion using {@link #deleteNode(Long)}. */ @DirtySessionAnnotation(markDirty=true) public void purgeNode(Long nodeId); /** * @param name the cm:name to apply to the association * @return Returns the persisted and filled association's ID * * @see ChildAssoc */ @DirtySessionAnnotation(markDirty=true) public Pair newChildAssoc( Long parentNodeId, Long childNodeId, boolean isPrimary, QName assocTypeQName, QName qname, String name); /** * Change the name of the child node. * * @param childId the child association to change * @param childName the name to put on the association */ @DirtySessionAnnotation(markDirty=false) public void setChildNameUnique(Long assocId, String childName); /** * @param index the association index. -1 to keep the existing value */ @DirtySessionAnnotation(markDirty=true) public Pair updateChildAssoc( Long childAssocId, Long parentNodeId, Long childNodeId, QName assocTypeQName, QName qname, int index, String childName); /** * Interface used to iterate over results from child association queries * @author Derek Hulley */ public interface ChildAssocRefQueryCallback { /** * * @return Return true if resursion into the child node * is required. */ boolean handle( Pair childAssocPair, Pair parentNodePair, Pair childNodePair ); } /** * Get a collection of all child association references for a given parent node. *

* WARNING: Be sure selective when doing this call recursively. * * @param parentNodeId the parent node * @param resultsCallback the callback that will be called with the results * @param recurse if true then iterate over the entire tree of nodes. * Resursion is done top-down i.e. the first level children are all * enumerated first, followed by all second level children and so on. */ @DirtySessionAnnotation(markDirty=false) public void getChildAssocs(Long parentNodeId, ChildAssocRefQueryCallback resultsCallback, boolean recurse); /** * Get a collection of all child association references for a given parent node. * * @param parentNodeId the parent node * @param resultsCallback the callback that will be called with the results */ @DirtySessionAnnotation(markDirty=false) public void getChildAssocs(Long parentNodeId, QName assocQName, ChildAssocRefQueryCallback resultsCallback); @DirtySessionAnnotation(markDirty=false) public void getChildAssocsByTypeQNames( Long parentNodeId, List assocTypeQNames, ChildAssocRefQueryCallback resultsCallback); @DirtySessionAnnotation(markDirty=false) public void getChildAssocsByTypeQNameAndQName( Long parentNodeId, QName assocTypeQName, QName assocQName, ChildAssocRefQueryCallback resultsCallback); @DirtySessionAnnotation(markDirty=false) public void getChildAssocsByChildTypes( Long parentNodeId, Set childNodeTypeQNames, ChildAssocRefQueryCallback resultsCallback); @DirtySessionAnnotation(markDirty=false) public void getPrimaryChildAssocs(Long parentNodeId, ChildAssocRefQueryCallback resultsCallback); @DirtySessionAnnotation(markDirty=false) public void getPrimaryChildAssocsNotInSameStore(Long parentNodeId, ChildAssocRefQueryCallback resultsCallback); /** * Interface used to iterate over pure node results * @author Derek Hulley */ public interface NodeRefQueryCallback { /** * * @param nodePair the node result * @return Returns true if more results are required */ boolean handle(Pair nodePair); } /** * Gets a set of nodes that have parents in the given store, but are themselves located in a different * store. * * @param storeId the store of the parent nodes * @param minNodeId the min node ID to return * @param count the maximum number of results * @param resultsCallback the node callback */ @DirtySessionAnnotation(markDirty=false) public void getNodesWithChildrenInDifferentStore( Long storeId, Long minNodeId, int count, NodeRefQueryCallback resultsCallback); @DirtySessionAnnotation(markDirty=false) public void getNodesWithAspect(QName aspectQName, Long minNodeId, int count, NodeRefQueryCallback resultsCallback); /** * @return Returns an association matching the given parent, type and child name - or null * if not found */ @DirtySessionAnnotation(markDirty=false) public Pair getChildAssoc(Long parentNodeId, QName assocTypeQName, String childName); /** * @return Returns a matching association or null if one was not found * * @see ChildAssoc */ @DirtySessionAnnotation(markDirty=false) public Pair getChildAssoc( Long parentNodeId, Long childNodeId, QName assocTypeQName, QName qname); /** * Deletes an explicit child association. * * @return Returns true if the association was deleted, otherwise false */ @DirtySessionAnnotation(markDirty=true) public boolean deleteChildAssoc( final Long parentNodeId, final Long childNodeId, final QName assocTypeQName, final QName qname); /** * @param assoc the child association to remove */ @DirtySessionAnnotation(markDirty=true) public void deleteChildAssoc(Long childAssocId); /** * Finds the association between the node's primary parent and the node itself */ @DirtySessionAnnotation(markDirty=false) public Pair getPrimaryParentAssoc(Long childNodeId); /** * Get all parent associations for the node. This methods includes a cache safety check. * @param childNode the child node * @return Returns all parent associations for the node. */ @DirtySessionAnnotation(markDirty=false) public Collection> getParentAssocs(final Long childNodeId); /** * @return Returns the persisted and filled association * @see NodeAssoc */ @DirtySessionAnnotation(markDirty=true) public Pair newNodeAssoc( Long sourceNodeId, Long targetNodeId, QName assocTypeQName); /** * @return Returns a list of all node associations associated with the given node */ @DirtySessionAnnotation(markDirty=false) public Collection> getNodeAssocsToAndFrom(final Long nodeId); /** * @return Returns the node association or null if not found */ @DirtySessionAnnotation(markDirty=false) public Pair getNodeAssoc(Long sourceNodeId, Long targetNodeId, QName assocTypeQName); /** * @return Returns all the node associations where the node is the source */ @DirtySessionAnnotation(markDirty=false) public Collection> getTargetNodeAssocs(Long sourceNodeId); /** * @return Returns all the node associations where the node is the target */ @DirtySessionAnnotation(markDirty=false) public Collection> getSourceNodeAssocs(Long targetNodeId); /** * @param assoc the node association to remove */ @DirtySessionAnnotation(markDirty=true) public void deleteNodeAssoc(Long assocId); /** * Iterate over all nodes that have a given property type with a given string value. * * @param storeRef the store to search in * @param propertyQName the qualified name of the property * @param value the string value to match * @param handler the callback to use while iterating over the URLs * @return Returns the values for the given type definition */ @DirtySessionAnnotation(markDirty=true) public void getPropertyValuesByPropertyAndValue( StoreRef storeRef, QName propertyQName, String value, NodePropertyHandler handler); /** * Interface used to iterate over object array results */ public interface ObjectArrayQueryCallback { boolean handle(Object[] array); } /** * Iterate over all content nodes to get owner/creator and content url (in order to extract content size) * * @param storeRef the store to search in * @param handler the callback to use while iterating over the URLs * @return Returns the values for the given owner, creator and content url */ @DirtySessionAnnotation(markDirty=true) public void getContentUrlsForStore( StoreRef storeRef, ObjectArrayQueryCallback resultsCallback); /** * Iterate over all person nodes to get users without a calculated usage * * @param storeRef the store to search in * @param handler the callback to use while iterating over the people * @return Returns the values for username and person node uuid (excluding System) */ @DirtySessionAnnotation(markDirty=true) public void getUsersWithoutUsage( StoreRef storeRef, ObjectArrayQueryCallback resultsCallback); /** * Iterate over all person nodes to get users with a calculated usage * * @param storeRef the store to search in * @param handler the callback to use while iterating over the people * @return Returns the values for the username and person node uuid (excluding System) */ @DirtySessionAnnotation(markDirty=true) public void getUsersWithUsage( StoreRef storeRef, ObjectArrayQueryCallback resultsCallback); /** * Iterate over all property values for the given type definition. This will also dig out values that * were persisted as type d:any. * * @param actualDataTypeDefinition the persisted type to retrieve * @param handler the callback to use while iterating over the URLs * @return Returns the values for the given type definition */ @DirtySessionAnnotation(markDirty=true) public void getPropertyValuesByActualType(DataTypeDefinition actualDataTypeDefinition, NodePropertyHandler handler); /** * Gets a batch of deleted nodes in old transactions. * * @param minNodeId the minimum node ID * @param maxCommitTime the maximum commit time (to set a minimum transaction age) * @param count the maximum number of results (for batching) * @param resultsCallback the callback to pass results back */ @DirtySessionAnnotation(markDirty=false) public void getNodesDeletedInOldTxns(Long minNodeId, long maxCommitTime, int count, NodeRefQueryCallback resultsCallback); /** * Iterface to handle callbacks when iterating over properties * * @author Derek Hulley * @since 2.0 */ public interface NodePropertyHandler { void handle(NodeRef nodeRef, QName nodeTypeQName, QName propertyQName, Serializable value); } /** * Retrieves the maximum transaction ID for which the commit time is less than the given time. * * @param maxCommitTime the max commit time (ms) * @return the last transaction on or before the given time */ @DirtySessionAnnotation(markDirty=true) public Long getMaxTxnIdByCommitTime(final long maxCommitTime); /** * Retrieves a specific transaction. * * @param txnId the unique transaction ID. * @return the requested transaction or null */ @DirtySessionAnnotation(markDirty=true) public Transaction getTxnById(long txnId); /** * Get all transactions in a given time range. Since time-based retrieval doesn't guarantee uniqueness * for any given millisecond, a list of optional exclusions may be provided. * * @param excludeTxnIds a list of txn IDs to ignore. null is allowed. * @param remoteOnly true if locally-written transactions must be ignored */ @DirtySessionAnnotation(markDirty=true) public List getTxnsByCommitTimeAscending( long fromTimeInclusive, long toTimeExclusive, int count, List excludeTxnIds, boolean remoteOnly); /** * Get all transactions in a given time range. Since time-based retrieval doesn't guarantee uniqueness * for any given millisecond, a list of optional exclusions may be provided. * * @param excludeTxnIds a list of txn IDs to ignore. null is allowed. * @param remoteOnly true if locally-written transactions must be ignored */ @DirtySessionAnnotation(markDirty=true) public List getTxnsByCommitTimeDescending( long fromTimeInclusive, long toTimeExclusive, int count, List excludeTxnIds, boolean remoteOnly); /** * Get the lowest commit time for a set of transactions * * @param includeTxnIds a list of transaction IDs to search for * @return Returns the transactions by commit time for the given IDs */ @DirtySessionAnnotation(markDirty=true) public List getTxnsByMinCommitTime(List includeTxnIds); @DirtySessionAnnotation(markDirty=false) public int getTxnUpdateCount(final long txnId); @DirtySessionAnnotation(markDirty=false) public int getTxnDeleteCount(final long txnId); @DirtySessionAnnotation(markDirty=false) public int getTransactionCount(); @DirtySessionAnnotation(markDirty=false) public List getTxnChangesForStore(final StoreRef storeRef, final long txnId); @DirtySessionAnnotation(markDirty=false) public List getTxnChanges(final long txnId); @DirtySessionAnnotation(markDirty=false) public List getTxnsUnused(Long minTxnId, long maxCommitTime, int count); @DirtySessionAnnotation(markDirty=true) public void purgeTxn(Long txnId); }