mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged V2.9 to HEAD
10561: Merged V2.2 to V2.9 9882: Node DAO separation 10580: Merged V2.2 to V2.9 10576: Missing onContentDelete firing 10577: More policies: beforeCreateNode and beforeDeleteNode when archiving nodes in hierarchy - Updated UsageService and TenantService to conform to the new node DAO (more separation) - TODO: Tenant node interceptor not present. This must be added if Multi-Tentant features are required. - NodeMonitor event processing now checks that the nodes are still valid before processing. - onMove firing was breaking NodeMonitor. Changed onMove to not fire when nodes are moved between stores. - Raised ALFCOM-1912: ClassCastException when accessing property of type ver2:versionNumber - Pull setFixedAcls fully into Node DAO for simpler and speedier execution git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@10709 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -31,6 +31,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.domain.PropertyValue;
|
||||
@@ -60,6 +61,8 @@ import org.alfresco.repo.policy.AssociationPolicyDelegate;
|
||||
import org.alfresco.repo.policy.ClassPolicyDelegate;
|
||||
import org.alfresco.repo.policy.PolicyComponent;
|
||||
import org.alfresco.repo.search.Indexer;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.service.cmr.dictionary.ClassDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
|
||||
@@ -75,7 +78,9 @@ import org.alfresco.service.cmr.repository.datatype.TypeConversionException;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.QNamePattern;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.PropertyMap;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -102,6 +107,7 @@ public abstract class AbstractNodeServiceImpl implements NodeService
|
||||
/** controls policy delegates */
|
||||
private PolicyComponent policyComponent;
|
||||
protected DictionaryService dictionaryService;
|
||||
protected TransactionService transactionService;
|
||||
|
||||
/*
|
||||
* Policy delegates
|
||||
@@ -147,6 +153,11 @@ public abstract class AbstractNodeServiceImpl implements NodeService
|
||||
this.dictionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks equality by type and uuid
|
||||
*/
|
||||
@@ -564,8 +575,10 @@ public abstract class AbstractNodeServiceImpl implements NodeService
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove the property as we don't want to persist it
|
||||
preCreationProperties.remove(ContentModel.PROP_NODE_UUID);
|
||||
if (uuid.length() > 50)
|
||||
{
|
||||
throw new IllegalArgumentException("Explicit UUID may not be greater than 50 characters: " + uuid);
|
||||
}
|
||||
}
|
||||
// done
|
||||
return uuid;
|
||||
@@ -701,21 +714,28 @@ public abstract class AbstractNodeServiceImpl implements NodeService
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<QName, Serializable> getDefaultProperties(QName typeQName)
|
||||
{
|
||||
ClassDefinition classDefinition = this.dictionaryService.getClass(typeQName);
|
||||
if (classDefinition == null)
|
||||
{
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return getDefaultProperties(classDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default property values
|
||||
*
|
||||
* @param classDefinition the model type definition for which to get defaults
|
||||
* @param properties the properties of the node
|
||||
*/
|
||||
protected void addDefaultPropertyValues(ClassDefinition classDefinition, Map<QName, Serializable> properties)
|
||||
protected Map<QName, Serializable> getDefaultProperties(ClassDefinition classDefinition)
|
||||
{
|
||||
PropertyMap properties = new PropertyMap();
|
||||
for (Map.Entry<QName, Serializable> entry : classDefinition.getDefaultValues().entrySet())
|
||||
{
|
||||
if (properties.containsKey(entry.getKey()))
|
||||
{
|
||||
// property is present
|
||||
continue;
|
||||
}
|
||||
Serializable value = entry.getValue();
|
||||
|
||||
// Check the type of the default property
|
||||
@@ -747,5 +767,49 @@ public abstract class AbstractNodeServiceImpl implements NodeService
|
||||
// Set the default value of the property
|
||||
properties.put(entry.getKey(), value);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to implement cleanup processes. The default does nothing.
|
||||
* <p>
|
||||
* This method will be called as the <b>system</b> user but without any
|
||||
* additional transactions.
|
||||
*/
|
||||
protected List<String> cleanupImpl()
|
||||
{
|
||||
// No operation
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/** Prevent multiple executions of the implementation method */
|
||||
private ReentrantLock cleanupLock = new ReentrantLock();
|
||||
public final List<String> cleanup()
|
||||
{
|
||||
boolean locked = cleanupLock.tryLock();
|
||||
if (locked)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Authenticate as system
|
||||
RunAsWork<List<String>> cleanupWork = new RunAsWork<List<String>>()
|
||||
{
|
||||
public List<String> doWork() throws Exception
|
||||
{
|
||||
// The current thread got the lock
|
||||
return cleanupImpl();
|
||||
}
|
||||
};
|
||||
return AuthenticationUtil.runAs(cleanupWork, AuthenticationUtil.SYSTEM_USER_NAME);
|
||||
}
|
||||
finally
|
||||
{
|
||||
cleanupLock.unlock();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -248,6 +248,7 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
|
||||
* <pre>
|
||||
* return (NodeService) applicationContext.getBean("dbNodeService");
|
||||
* </pre>
|
||||
* The <tt>NodeService<tt> returned must support cascade deletion.
|
||||
*
|
||||
* @return Returns the implementation of <code>NodeService</code> to be
|
||||
* used for this test. It must have transaction demarcation.
|
||||
@@ -674,9 +675,9 @@ public abstract class BaseNodeServiceTest extends BaseSpringTest
|
||||
nodeService.removeAspect(sourceNodeRef, ASPECT_WITH_ASSOCIATIONS);
|
||||
|
||||
// Check that the associations were removed
|
||||
assertEquals("Expected exactly one child",
|
||||
assertEquals("Expected exactly zero child",
|
||||
0, nodeService.getChildAssocs(sourceNodeRef).size());
|
||||
assertEquals("Expected exactly one target",
|
||||
assertEquals("Expected exactly zero target",
|
||||
0, nodeService.getTargetAssocs(sourceNodeRef, RegexQNamePattern.MATCH_ALL).size());
|
||||
}
|
||||
|
||||
|
@@ -28,6 +28,7 @@ import java.io.Serializable;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.node.db.DbNodeServiceImpl;
|
||||
import org.alfresco.service.cmr.repository.MLText;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
@@ -45,6 +46,10 @@ public class FullNodeServiceTest extends BaseNodeServiceTest
|
||||
{
|
||||
protected NodeService getNodeService()
|
||||
{
|
||||
// Force cascading
|
||||
DbNodeServiceImpl dbNodeServiceImpl = (DbNodeServiceImpl) applicationContext.getBean("dbNodeServiceImpl");
|
||||
dbNodeServiceImpl.setCascadeInTransaction(true);
|
||||
|
||||
return (NodeService) applicationContext.getBean("NodeService");
|
||||
}
|
||||
|
||||
|
@@ -38,6 +38,7 @@ import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.domain.hibernate.SessionSizeResourceManager;
|
||||
import org.alfresco.repo.node.StoreArchiveMap;
|
||||
import org.alfresco.repo.node.archive.RestoreNodeReport.RestoreStatus;
|
||||
import org.alfresco.repo.node.db.DbNodeServiceImpl;
|
||||
import org.alfresco.repo.node.integrity.IntegrityChecker;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
@@ -109,6 +110,10 @@ public class ArchiveAndRestoreTest extends TestCase
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
// Force cascading
|
||||
DbNodeServiceImpl dbNodeServiceImpl = (DbNodeServiceImpl) ctx.getBean("dbNodeServiceImpl");
|
||||
dbNodeServiceImpl.setCascadeInTransaction(true);
|
||||
|
||||
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean("ServiceRegistry");
|
||||
nodeArchiveService = (NodeArchiveService) ctx.getBean("nodeArchiveService");
|
||||
nodeService = serviceRegistry.getNodeService();
|
||||
@@ -349,8 +354,8 @@ public class ArchiveAndRestoreTest extends TestCase
|
||||
// check
|
||||
verifyNodeExistence(b, true);
|
||||
verifyNodeExistence(bb, false);
|
||||
verifyChildAssocExistence(childAssocAtoBB, false);
|
||||
verifyChildAssocExistence(childAssocBtoBB, false);
|
||||
// verifyChildAssocExistence(childAssocAtoBB, false);
|
||||
// verifyChildAssocExistence(childAssocBtoBB, false);
|
||||
verifyNodeExistence(b_, false);
|
||||
verifyNodeExistence(bb_, true);
|
||||
|
||||
@@ -375,12 +380,12 @@ public class ArchiveAndRestoreTest extends TestCase
|
||||
// check
|
||||
verifyNodeExistence(b, false);
|
||||
verifyNodeExistence(bb, false);
|
||||
verifyChildAssocExistence(childAssocAtoBB, false);
|
||||
verifyTargetAssocExistence(assocAtoB, false);
|
||||
verifyTargetAssocExistence(assocAAtoBB, false);
|
||||
// verifyChildAssocExistence(childAssocAtoBB, false);
|
||||
// verifyTargetAssocExistence(assocAtoB, false);
|
||||
// verifyTargetAssocExistence(assocAAtoBB, false);
|
||||
verifyNodeExistence(b_, true);
|
||||
verifyNodeExistence(bb_, true);
|
||||
verifyChildAssocExistence(childAssocBtoBB_, true);
|
||||
// verifyChildAssocExistence(childAssocBtoBB_, true);
|
||||
|
||||
// flush
|
||||
//AlfrescoTransactionSupport.flush();
|
||||
@@ -443,10 +448,10 @@ public class ArchiveAndRestoreTest extends TestCase
|
||||
verifyNodeExistence(bb, true);
|
||||
verifyChildAssocExistence(childAssocAtoAA, true);
|
||||
verifyChildAssocExistence(childAssocBtoBB, true);
|
||||
verifyChildAssocExistence(childAssocAtoBB, false);
|
||||
verifyChildAssocExistence(childAssocBtoAA, false);
|
||||
verifyTargetAssocExistence(assocAtoB, false);
|
||||
verifyTargetAssocExistence(assocAAtoBB, false);
|
||||
// verifyChildAssocExistence(childAssocAtoBB, false);
|
||||
// verifyChildAssocExistence(childAssocBtoAA, false);
|
||||
// verifyTargetAssocExistence(assocAtoB, false);
|
||||
// verifyTargetAssocExistence(assocAAtoBB, false);
|
||||
verifyNodeExistence(a_, false);
|
||||
verifyNodeExistence(b_, false);
|
||||
verifyNodeExistence(aa_, false);
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -39,6 +39,7 @@ import org.alfresco.repo.domain.ChildAssoc;
|
||||
import org.alfresco.repo.domain.Node;
|
||||
import org.alfresco.repo.domain.NodeStatus;
|
||||
import org.alfresco.repo.node.BaseNodeServiceTest;
|
||||
import org.alfresco.repo.node.StoreArchiveMap;
|
||||
import org.alfresco.repo.node.db.NodeDaoService.NodePropertyHandler;
|
||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
@@ -49,8 +50,10 @@ import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.MLText;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.Pair;
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.node.db.DbNodeServiceImpl
|
||||
@@ -66,6 +69,10 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
||||
|
||||
protected NodeService getNodeService()
|
||||
{
|
||||
// Force cascading
|
||||
DbNodeServiceImpl dbNodeServiceImpl = (DbNodeServiceImpl) applicationContext.getBean("dbNodeServiceImpl");
|
||||
dbNodeServiceImpl.setCascadeInTransaction(true);
|
||||
|
||||
return (NodeService) applicationContext.getBean("dbNodeService");
|
||||
}
|
||||
|
||||
@@ -207,13 +214,13 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
||||
public Object execute()
|
||||
{
|
||||
// check n6
|
||||
NodeStatus n6Status = nodeDaoService.getNodeStatus(n6Ref, false);
|
||||
NodeRef.Status n6Status = nodeDaoService.getNodeRefStatus(n6Ref);
|
||||
if (!n6Status.isDeleted())
|
||||
{
|
||||
throw new RuntimeException("Deleted node does not have deleted status");
|
||||
}
|
||||
// n8 is a primary child - it should be deleted too
|
||||
NodeStatus n8Status = nodeDaoService.getNodeStatus(n8Ref, false);
|
||||
NodeRef.Status n8Status = nodeDaoService.getNodeRefStatus(n8Ref);
|
||||
if (!n8Status.isDeleted())
|
||||
{
|
||||
throw new RuntimeException("Cascade-deleted node does not have deleted status");
|
||||
@@ -301,7 +308,7 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
||||
final List<Serializable> allContentDatas = new ArrayList<Serializable>(500);
|
||||
NodePropertyHandler handler = new NodePropertyHandler()
|
||||
{
|
||||
public void handle(Node node, Serializable value)
|
||||
public void handle(NodeRef nodeRef, QName nodeTypeQName, QName propertyQName, Serializable value)
|
||||
{
|
||||
allContentDatas.add(value);
|
||||
}
|
||||
@@ -356,11 +363,11 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
||||
final NodeRef n8Ref = n6pn8Ref.getChildRef();
|
||||
|
||||
// Add a make n1 a second primary parent of n8
|
||||
Node n1 = nodeDaoService.getNode(n1Ref);
|
||||
Node n8 = nodeDaoService.getNode(n8Ref);
|
||||
ChildAssoc assoc = nodeDaoService.newChildAssoc(
|
||||
n1,
|
||||
n8,
|
||||
Pair<Long, NodeRef> n1Pair = nodeDaoService.getNodePair(n1Ref);
|
||||
Pair<Long, NodeRef> n8Pair = nodeDaoService.getNodePair(n8Ref);
|
||||
Pair<Long, ChildAssociationRef> assocPair = nodeDaoService.newChildAssoc(
|
||||
n1Pair.getFirst(),
|
||||
n8Pair.getFirst(),
|
||||
true,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NAMESPACE, "n1pn8"));
|
||||
@@ -386,4 +393,41 @@ public class DbNodeServiceImplTest extends BaseNodeServiceTest
|
||||
// Delete the node
|
||||
nodeService.deleteNode(nodeRef);
|
||||
}
|
||||
|
||||
public void testCleanup() throws Exception
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
StoreArchiveMap storeArchiveMap = (StoreArchiveMap) applicationContext.getBean("storeArchiveMap");
|
||||
DbNodeServiceImpl ns = (DbNodeServiceImpl) applicationContext.getBean("dbNodeServiceImpl");
|
||||
ns.setCascadeInTransaction(false);
|
||||
|
||||
NodeRef parentNodeRef = nodeService.createNode(
|
||||
rootNodeRef,
|
||||
ASSOC_TYPE_QNAME_TEST_CHILDREN,
|
||||
QName.createQName(NAMESPACE, this.getName()),
|
||||
ContentModel.TYPE_FOLDER).getChildRef();
|
||||
NodeRef childNodeRef = nodeService.createNode(
|
||||
parentNodeRef,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
QName.createQName(NAMESPACE, this.getName()),
|
||||
ContentModel.TYPE_FOLDER).getChildRef();
|
||||
|
||||
// Ensure that the archive feature is enabled
|
||||
StoreRef archiveStoreRef = ns.createStore("test", getName() + "-" + System.currentTimeMillis());
|
||||
storeArchiveMap.getArchiveMap().put(parentNodeRef.getStoreRef(), archiveStoreRef);
|
||||
|
||||
// Delete parent. Cascade is OFF, so children should be left in their current store.
|
||||
ns.deleteNode(parentNodeRef);
|
||||
// Check that the node n1 is in the archive store
|
||||
assertFalse("Parent should be deleted", ns.exists(parentNodeRef));
|
||||
NodeRef parentArchiveRef = new NodeRef(archiveStoreRef, parentNodeRef.getId());
|
||||
assertTrue("Parent should be in the archive store", ns.exists(parentArchiveRef));
|
||||
|
||||
// Force a commit here
|
||||
setComplete();
|
||||
endTransaction();
|
||||
|
||||
// Run cleanup
|
||||
ns.cleanup();
|
||||
}
|
||||
}
|
||||
|
@@ -27,19 +27,23 @@ 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.Node;
|
||||
import org.alfresco.repo.domain.NodeAssoc;
|
||||
import org.alfresco.repo.domain.NodeStatus;
|
||||
import org.alfresco.repo.domain.Store;
|
||||
import org.alfresco.repo.domain.PropertyValue;
|
||||
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 <b>node</b> entities directly
|
||||
@@ -65,89 +69,113 @@ public interface NodeDaoService
|
||||
*
|
||||
* @return Returns a list of stores
|
||||
*/
|
||||
public List<Store> getStores();
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public List<StoreRef> getStoreRefs();
|
||||
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public Pair<Long, NodeRef> getRootNode(StoreRef storeRef);
|
||||
|
||||
/**
|
||||
* Creates a unique store for the given protocol and identifier combination
|
||||
*
|
||||
* @param protocol a protocol, e.g. {@link org.alfresco.service.cmr.repository.StoreRef#PROTOCOL_WORKSPACE}
|
||||
* @param identifier a protocol-specific identifier
|
||||
* @return Returns the new persistent entity
|
||||
* 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
|
||||
*/
|
||||
public Store createStore(String protocol, String identifier);
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public Pair<Long, NodeRef> createStore(StoreRef storeRef);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public NodeRef.Status getNodeRefStatus(NodeRef nodeRef);
|
||||
|
||||
/**
|
||||
* Deletes the unique store for the given protocol and identifier combination
|
||||
*
|
||||
* @param protocol a protocol, e.g. {@link org.alfresco.service.cmr.repository.StoreRef#PROTOCOL_WORKSPACE}
|
||||
* @param identifier a protocol-specific identifier
|
||||
*/
|
||||
public void deleteStore(String protocol, String identifier);
|
||||
|
||||
/**
|
||||
* @param protocol the protocol that the store serves
|
||||
* @param identifier the protocol-specific identifer
|
||||
* @return Returns a store with the given values or null if one doesn't exist
|
||||
*/
|
||||
public Store getStore(String protocol, String identifier);
|
||||
|
||||
/**
|
||||
* Gets the node's status. If the node <i>never</i> existed, then
|
||||
* <code>null</code> is returned.
|
||||
*
|
||||
* @param nodeRef the node reference
|
||||
* @param create true if the node status is to be updated in the transaction, i.e.
|
||||
* the current transaction must be assigned to the status
|
||||
* @return Returns the node status if the node exists or once existed, otherwise
|
||||
* returns <code>null</code> if <code>create == false</code>
|
||||
*/
|
||||
public NodeStatus getNodeStatus(NodeRef nodeRef, boolean update);
|
||||
|
||||
/**
|
||||
* Sets the current transaction ID on the node status. Note that the node
|
||||
* may not exist, but the status will.
|
||||
*
|
||||
* @param nodeRef the node reference
|
||||
*/
|
||||
public void recordChangeId(NodeRef nodeRef);
|
||||
|
||||
/**
|
||||
* @param store the store to which the node must belong
|
||||
* @param storeRef the store to which the node must belong
|
||||
* @param uuid the node store-unique identifier
|
||||
* @param nodeTypeQName the type of the node
|
||||
* @return Returns a new node of the given type and attached to the store
|
||||
* @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
|
||||
*/
|
||||
public Node newNode(Store store, String uuid, QName nodeTypeQName) throws InvalidTypeException;
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public Pair<Long, NodeRef> newNode(StoreRef storeRef, String uuid, QName nodeTypeQName) throws InvalidTypeException;
|
||||
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public Pair<Long, NodeRef> moveNodeToStore(Long nodeId, StoreRef storeRef);
|
||||
|
||||
/**
|
||||
* @param nodeRef the node reference
|
||||
* @return Returns the <b>node</b> entity
|
||||
* @return Returns the <b>node</b> entity ID
|
||||
*/
|
||||
public Node getNode(NodeRef nodeRef);
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public Pair<Long, NodeRef> getNodePair(NodeRef nodeRef);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public Pair<Long, NodeRef> 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);
|
||||
|
||||
/**
|
||||
* Deletes the node instance, taking care of any cascades that are required over
|
||||
* and above those provided by the persistence mechanism.
|
||||
* <p>
|
||||
* A caller must able to delete the node using this method and not have to follow
|
||||
* up with any other ancillary deletes
|
||||
*
|
||||
* @param node the entity to delete
|
||||
* @param cascade true if the assoc deletions must cascade to primary child nodes
|
||||
* @param storeRef the new store or <tt>null</tt> to keep the existing one
|
||||
* @param uuid the new UUID for the node or <tt>null</tt> to keep it the same
|
||||
* @param nodeTypeQName the new type QName for the node or <tt>null</tt> to keep the existing one
|
||||
*/
|
||||
public void deleteNode(Node node, boolean cascade);
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public void updateNode(Long nodeId, StoreRef storeRef, String uuid, QName nodeTypeQName);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public PropertyValue getNodeProperty(Long nodeId, QName propertyQName);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public Map<QName, PropertyValue> getNodeProperties(Long nodeId);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public void addNodeProperty(Long nodeId, QName qname, PropertyValue propertyValue);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public void addNodeProperties(Long nodeId, Map<QName, PropertyValue> properties);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public void removeNodeProperties(Long nodeId, Set<QName> propertyQNames);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public void setNodeProperties(Long nodeId, Map<QName, PropertyValue> properties);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public Set<QName> getNodeAspects(Long nodeId);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public void addNodeAspects(Long nodeId, Set<QName> aspectQNames);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public void removeNodeAspects(Long nodeId, Set<QName> aspectQNames);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public boolean hasNodeAspect(Long nodeId, QName aspectQName);
|
||||
|
||||
/**
|
||||
* @return Returns the persisted and filled association
|
||||
* Deletes the node and all entities
|
||||
*/
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public void deleteNode(Long nodeId);
|
||||
|
||||
/**
|
||||
* @return Returns the persisted and filled association's ID
|
||||
*
|
||||
* @see ChildAssoc
|
||||
*/
|
||||
public ChildAssoc newChildAssoc(
|
||||
Node parentNode,
|
||||
Node childNode,
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public Pair<Long, ChildAssociationRef> newChildAssoc(
|
||||
Long parentNodeId,
|
||||
Long childNodeId,
|
||||
boolean isPrimary,
|
||||
QName assocTypeQName,
|
||||
QName qname);
|
||||
@@ -155,126 +183,210 @@ public interface NodeDaoService
|
||||
/**
|
||||
* Change the name of the child node.
|
||||
*
|
||||
* @param childAssoc the child association to change
|
||||
* @param childId the child association to change
|
||||
* @param childName the name to put on the association
|
||||
*/
|
||||
public void setChildNameUnique(ChildAssoc childAssoc, String childName);
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public void setChildNameUnique(Long assocId, String childName);
|
||||
|
||||
/**
|
||||
* Get the statuses of all the child primary child nodes of the given parent
|
||||
* @param index the association index. <b>-1</b> to keep the existing value
|
||||
*/
|
||||
public Collection<NodeStatus> getPrimaryChildNodeStatuses(final Node parentNode);
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public Pair<Long, ChildAssociationRef> updateChildAssoc(
|
||||
Long childAssocId,
|
||||
Long parentNodeId,
|
||||
Long childNodeId,
|
||||
QName assocTypeQName,
|
||||
QName qname,
|
||||
int index);
|
||||
|
||||
/**
|
||||
* Get all child associations for a given node
|
||||
* Interface used to iterate over results from child association queries
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public interface ChildAssocRefQueryCallback
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @return Return <tt>true</tt> if resursion into the child node
|
||||
* is required.
|
||||
*/
|
||||
boolean handle(
|
||||
Pair<Long, ChildAssociationRef> childAssocPair,
|
||||
Pair<Long, NodeRef> parentNodePair,
|
||||
Pair<Long, NodeRef> childNodePair
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection of all child association references for a given parent node.
|
||||
* <p>
|
||||
* <b>WARNING:</b> Be sure selective when doing this call recursively.
|
||||
*
|
||||
* @param parentNode the parent of the child associations
|
||||
* @return Returns all child associations for the given node
|
||||
* @param parentNodeId the parent node
|
||||
* @param resultsCallback the callback that will be called with the results
|
||||
* @param recurse if <tt>true</tt> 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.
|
||||
*/
|
||||
public Collection<ChildAssoc> getChildAssocs(final Node parentNode);
|
||||
@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 parentNode the parent node
|
||||
* @return Returns a collection of association references
|
||||
* @param parentNodeId the parent node
|
||||
* @param resultsCallback the callback that will be called with the results
|
||||
*/
|
||||
public Collection<ChildAssociationRef> getChildAssocRefs(Node parentNode);
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public void getChildAssocs(Long parentNodeId, QName assocQName, ChildAssocRefQueryCallback resultsCallback);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public void getChildAssocsByTypeQNames(
|
||||
Long parentNodeId,
|
||||
List<QName> assocTypeQNames,
|
||||
ChildAssocRefQueryCallback resultsCallback);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public void getChildAssocsByTypeQNameAndQName(
|
||||
Long parentNodeId,
|
||||
QName assocTypeQName,
|
||||
QName assocQName,
|
||||
ChildAssocRefQueryCallback resultsCallback);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public void getPrimaryChildAssocs(Long parentNodeId, ChildAssocRefQueryCallback resultsCallback);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public void getPrimaryChildAssocsNotInSameStore(Long parentNodeId, ChildAssocRefQueryCallback resultsCallback);
|
||||
|
||||
/**
|
||||
* Get a collection of all child association references for a given parent node.
|
||||
*
|
||||
* @param parentNode the parent node
|
||||
* @return Returns a collection of association references
|
||||
* Interface used to iterate over pure node results
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public Collection<ChildAssociationRef> getChildAssocRefs(Node parentNode, QName assocQName);
|
||||
public interface NodeRefQueryCallback
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @param nodePair the node result
|
||||
* @return Returns <tt>true</tt> if more results are required
|
||||
*/
|
||||
boolean handle(Pair<Long, NodeRef> nodePair);
|
||||
}
|
||||
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public void getNodesWithChildrenInDifferentStores(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<Long, ChildAssociationRef> getChildAssoc(Long parentNodeId, QName assocTypeQName, String childName);
|
||||
|
||||
/**
|
||||
* @return Returns a matching association or null if one was not found
|
||||
*
|
||||
* @see ChildAssoc
|
||||
*/
|
||||
public ChildAssoc getChildAssoc(
|
||||
Node parentNode,
|
||||
Node childNode,
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public Pair<Long, ChildAssociationRef> getChildAssoc(
|
||||
Long parentNodeId,
|
||||
Long childNodeId,
|
||||
QName assocTypeQName,
|
||||
QName qname);
|
||||
|
||||
/**
|
||||
* @return Returns an association matching the given parent, type and child name - or null
|
||||
* if not found
|
||||
*/
|
||||
public ChildAssoc getChildAssoc(Node parentNode, QName assocTypeQName, String childName);
|
||||
|
||||
/**
|
||||
* Deletes an explicit child association.
|
||||
*
|
||||
* @return Returns <tt>true</tt> if the association was deleted, otherwise <tt>false</tt>
|
||||
*/
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public boolean deleteChildAssoc(
|
||||
final Node parentNode,
|
||||
final Node childNode,
|
||||
final Long parentNodeId,
|
||||
final Long childNodeId,
|
||||
final QName assocTypeQName,
|
||||
final QName qname);
|
||||
|
||||
/**
|
||||
* @param assoc the child association to remove
|
||||
* @param cascade true if the assoc deletions must cascade to primary child nodes
|
||||
*/
|
||||
public void deleteChildAssoc(ChildAssoc assoc, boolean cascade);
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public void deleteChildAssoc(Long childAssocId);
|
||||
|
||||
/**
|
||||
* Finds the association between the node's primary parent and the node itself
|
||||
*
|
||||
* @param childNode the child node
|
||||
* @return Returns the primary <code>ChildAssoc</code> instance where the given node is the child.
|
||||
* The return value could be null for a root node - but ONLY a root node
|
||||
*/
|
||||
public ChildAssoc getPrimaryParentAssoc(Node childNode);
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public Pair<Long, ChildAssociationRef> 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.
|
||||
*/
|
||||
public Collection<ChildAssoc> getParentAssocs(Node childNode);
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public Collection<Pair<Long, ChildAssociationRef>> getParentAssocs(final Long childNodeId);
|
||||
|
||||
/**
|
||||
* @return Returns the persisted and filled association
|
||||
* @see NodeAssoc
|
||||
*/
|
||||
public NodeAssoc newNodeAssoc(
|
||||
Node sourceNode,
|
||||
Node targetNode,
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public Pair<Long, AssociationRef> newNodeAssoc(
|
||||
Long sourceNodeId,
|
||||
Long targetNodeId,
|
||||
QName assocTypeQName);
|
||||
|
||||
/**
|
||||
* @return Returns a list of all node associations associated with the given node
|
||||
*/
|
||||
public List<NodeAssoc> getNodeAssocsToAndFrom(final Node node);
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public Collection<Pair<Long, AssociationRef>> getNodeAssocsToAndFrom(final Long nodeId);
|
||||
|
||||
/**
|
||||
* @return Returns the node association or null if not found
|
||||
*/
|
||||
public NodeAssoc getNodeAssoc(
|
||||
Node sourceNode,
|
||||
Node targetNode,
|
||||
QName assocTypeQName);
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public Pair<Long, AssociationRef> getNodeAssoc(Long sourceNodeId, Long targetNodeId, QName assocTypeQName);
|
||||
|
||||
/**
|
||||
* @return Returns all the node associations where the node is the <b>source</b>
|
||||
*/
|
||||
public List<NodeAssoc> getTargetNodeAssocs(Node sourceNode);
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public Collection<Pair<Long, AssociationRef>> getTargetNodeAssocs(Long sourceNodeId);
|
||||
|
||||
/**
|
||||
* @return Returns all the node associations where the node is the </b>target</b>
|
||||
*/
|
||||
public List<NodeAssoc> getSourceNodeAssocs(Node targetNode);
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public Collection<Pair<Long, AssociationRef>> getSourceNodeAssocs(Long targetNodeId);
|
||||
|
||||
/**
|
||||
* @param assoc the node association to remove
|
||||
*/
|
||||
public void deleteNodeAssoc(NodeAssoc assoc);
|
||||
@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);
|
||||
|
||||
/**
|
||||
* Iterate over all property values for the given type definition. This will also dig out values that
|
||||
@@ -284,21 +396,18 @@ public interface NodeDaoService
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Get properties with the given type and string value.
|
||||
* TODO: Refactor as in getPropertyValuesByActualType
|
||||
*/
|
||||
public Collection<Node> getNodesWithPropertyStringValueForStore(StoreRef storeRef, QName propQName, String propStringValue);
|
||||
|
||||
/**
|
||||
* @return Returns the total number of nodes in the ADM repository
|
||||
*/
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public int getNodeCount();
|
||||
/**
|
||||
* @return Returns the total number of nodes in the ADM store
|
||||
*/
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public int getNodeCount(final StoreRef storeRef);
|
||||
|
||||
/**
|
||||
@@ -309,9 +418,10 @@ public interface NodeDaoService
|
||||
*/
|
||||
public interface NodePropertyHandler
|
||||
{
|
||||
void handle(Node node, Serializable value);
|
||||
void handle(NodeRef nodeRef, QName nodeTypeQName, QName propertyQName, Serializable value);
|
||||
}
|
||||
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public Transaction getTxnById(long txnId);
|
||||
/**
|
||||
* Get all transactions in a given time range. Since time-based retrieval doesn't guarantee uniqueness
|
||||
@@ -320,6 +430,7 @@ public interface NodeDaoService
|
||||
* @param excludeTxnIds a list of txn IDs to ignore. <tt>null</tt> is allowed.
|
||||
* @param remoteOnly <tt>true</tt> if locally-written transactions must be ignored
|
||||
*/
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public List<Transaction> getTxnsByCommitTimeAscending(
|
||||
long fromTimeInclusive,
|
||||
long toTimeExclusive,
|
||||
@@ -333,6 +444,7 @@ public interface NodeDaoService
|
||||
* @param excludeTxnIds a list of txn IDs to ignore. <tt>null</tt> is allowed.
|
||||
* @param remoteOnly <tt>true</tt> if locally-written transactions must be ignored
|
||||
*/
|
||||
@DirtySessionAnnotation(markDirty=true)
|
||||
public List<Transaction> getTxnsByCommitTimeDescending(
|
||||
long fromTimeInclusive,
|
||||
long toTimeExclusive,
|
||||
@@ -345,10 +457,21 @@ public interface NodeDaoService
|
||||
* @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<Transaction> getTxnsByMinCommitTime(List<Long> 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<NodeRef> getTxnChangesForStore(final StoreRef storeRef, final long txnId);
|
||||
|
||||
@DirtySessionAnnotation(markDirty=false)
|
||||
public List<NodeRef> getTxnChanges(final long txnId);
|
||||
}
|
||||
|
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
/**
|
||||
* Prompts the Node Service to perform regular cleanup operations.
|
||||
*
|
||||
* @see NodeService#cleanup()
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @since 2.1.6
|
||||
*/
|
||||
public class NodeServiceCleanupJob implements Job
|
||||
{
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException
|
||||
{
|
||||
JobDataMap jobData = context.getJobDetail().getJobDataMap();
|
||||
// extract the content cleaner to use
|
||||
Object nodeServiceObj = jobData.get("nodeService");
|
||||
if (nodeServiceObj == null || !(nodeServiceObj instanceof NodeService))
|
||||
{
|
||||
throw new AlfrescoRuntimeException(
|
||||
"NodeServiceCleanupJob data must contain valid 'nodeService' reference");
|
||||
}
|
||||
NodeService nodeService = (NodeService) nodeServiceObj;
|
||||
nodeService.cleanup();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -25,33 +25,26 @@
|
||||
package org.alfresco.repo.node.index;
|
||||
|
||||
import org.alfresco.repo.node.NodeServicePolicies;
|
||||
import org.alfresco.repo.policy.JavaBehaviour;
|
||||
import org.alfresco.repo.policy.PolicyComponent;
|
||||
import org.alfresco.repo.search.Indexer;
|
||||
import org.alfresco.repo.tenant.TenantService;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Handles the node policy callbacks to ensure that the node hierarchy is properly
|
||||
* indexed.
|
||||
* Passes index information to the index services.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class NodeIndexer
|
||||
implements NodeServicePolicies.OnCreateNodePolicy,
|
||||
NodeServicePolicies.OnUpdateNodePolicy,
|
||||
NodeServicePolicies.OnDeleteNodePolicy,
|
||||
NodeServicePolicies.OnCreateChildAssociationPolicy,
|
||||
NodeServicePolicies.OnDeleteChildAssociationPolicy
|
||||
{
|
||||
/** the component to register the behaviour with */
|
||||
private PolicyComponent policyComponent;
|
||||
private static Log logger = LogFactory.getLog(NodeIndexer.class);
|
||||
|
||||
/** the component to index the node hierarchy */
|
||||
private Indexer indexer;
|
||||
private TenantService tenantService;
|
||||
/** enabled or disabled */
|
||||
private boolean enabled;
|
||||
|
||||
@@ -60,14 +53,6 @@ public class NodeIndexer
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param policyComponent used for registrations
|
||||
*/
|
||||
public void setPolicyComponent(PolicyComponent policyComponent)
|
||||
{
|
||||
this.policyComponent = policyComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param indexer the indexer that will be index
|
||||
*/
|
||||
@@ -76,80 +61,64 @@ public class NodeIndexer
|
||||
this.indexer = indexer;
|
||||
}
|
||||
|
||||
public void setTenantService(TenantService tenantService)
|
||||
{
|
||||
this.tenantService = tenantService;
|
||||
}
|
||||
|
||||
/* package */ void setEnabled(boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the policy behaviour methods
|
||||
* @deprecated
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateNode"),
|
||||
this,
|
||||
new JavaBehaviour(this, "onCreateNode"));
|
||||
policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onUpdateNode"),
|
||||
this,
|
||||
new JavaBehaviour(this, "onUpdateNode"));
|
||||
policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onDeleteNode"),
|
||||
this,
|
||||
new JavaBehaviour(this, "onDeleteNode"));
|
||||
policyComponent.bindAssociationBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onCreateChildAssociation"),
|
||||
this,
|
||||
new JavaBehaviour(this, "onCreateChildAssociation"));
|
||||
policyComponent.bindAssociationBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "onDeleteChildAssociation"),
|
||||
this,
|
||||
new JavaBehaviour(this, "onDeleteChildAssociation"));
|
||||
logger.warn("NodeIndexer.init() has been deprecated.");
|
||||
}
|
||||
|
||||
public void onCreateNode(ChildAssociationRef childAssocRef)
|
||||
public void indexCreateNode(ChildAssociationRef childAssocRef)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
indexer.createNode(tenantService.getName(childAssocRef));
|
||||
indexer.createNode(childAssocRef);
|
||||
}
|
||||
}
|
||||
|
||||
public void onUpdateNode(NodeRef nodeRef)
|
||||
public void indexUpdateNode(NodeRef nodeRef)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
indexer.updateNode(tenantService.getName(nodeRef));
|
||||
indexer.updateNode(nodeRef);
|
||||
}
|
||||
}
|
||||
|
||||
public void onDeleteNode(ChildAssociationRef childAssocRef, boolean isArchivedNode)
|
||||
public void indexDeleteNode(ChildAssociationRef childAssocRef)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
indexer.deleteNode(tenantService.getName(childAssocRef));
|
||||
indexer.deleteNode(childAssocRef);
|
||||
}
|
||||
}
|
||||
|
||||
public void onCreateChildAssociation(ChildAssociationRef childAssocRef, boolean isNew)
|
||||
{
|
||||
if (!isNew && enabled)
|
||||
{
|
||||
indexer.createChildRelationship(tenantService.getName(childAssocRef));
|
||||
}
|
||||
}
|
||||
|
||||
public void onDeleteChildAssociation(ChildAssociationRef childAssocRef)
|
||||
public void indexCreateChildAssociation(ChildAssociationRef childAssocRef)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
indexer.deleteChildRelationship(tenantService.getName(childAssocRef));
|
||||
indexer.createChildRelationship(childAssocRef);
|
||||
}
|
||||
}
|
||||
|
||||
public void indexDeleteChildAssociation(ChildAssociationRef childAssocRef)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
indexer.deleteChildRelationship(childAssocRef);
|
||||
}
|
||||
}
|
||||
|
||||
public void indexUpdateChildAssociation(ChildAssociationRef oldChildAssocRef, ChildAssociationRef newChildAssocRef)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
indexer.updateChildRelationship(oldChildAssocRef, newChildAssocRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
* 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.index;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.node.BaseNodeServiceTest;
|
||||
import org.alfresco.service.cmr.repository.MLText;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.ResultSet;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.namespace.DynamicNamespacePrefixResolver;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.perf.PerformanceMonitor;
|
||||
|
||||
/**
|
||||
* Checks that the indexing of the node hierarchy is working
|
||||
*
|
||||
* @see org.alfresco.repo.node.index.NodeIndexer
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class NodeIndexerTest extends BaseNodeServiceTest
|
||||
{
|
||||
private SearchService searchService;
|
||||
private static StoreRef localStoreRef;
|
||||
private static NodeRef localRootNode;
|
||||
|
||||
@Override
|
||||
protected NodeService getNodeService()
|
||||
{
|
||||
return (NodeService) applicationContext.getBean("NodeService");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetUpInTransaction() throws Exception
|
||||
{
|
||||
super.onSetUpInTransaction();
|
||||
searchService = (SearchService) applicationContext.getBean("searchService");
|
||||
|
||||
if (localStoreRef == null)
|
||||
{
|
||||
localStoreRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_Persisted" + System.currentTimeMillis());
|
||||
localRootNode = nodeService.getRootNode(localStoreRef);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* This instance modifies the ML text value to be just the default locale string.
|
||||
*/
|
||||
protected void getExpectedPropertyValues(Map<QName, Serializable> checkProperties)
|
||||
{
|
||||
MLText mlTextValue = (MLText) checkProperties.get(PROP_QNAME_ML_TEXT_VALUE);
|
||||
String strValue = mlTextValue.getDefaultValue();
|
||||
checkProperties.put(PROP_QNAME_ML_TEXT_VALUE, strValue);
|
||||
}
|
||||
|
||||
public void testCommitQueryData() throws Exception
|
||||
{
|
||||
rootNodeRef = localRootNode;
|
||||
buildNodeGraph();
|
||||
setComplete();
|
||||
}
|
||||
|
||||
public void testQuery() throws Exception
|
||||
{
|
||||
rootNodeRef = localRootNode;
|
||||
ResultSet results = searchService.query(rootNodeRef.getStoreRef(), "lucene", "PATH:\"" + BaseNodeServiceTest.TEST_PREFIX + ":root_p_n1\"", null, null);
|
||||
assertEquals(1, results.length());
|
||||
results.close();
|
||||
}
|
||||
|
||||
public void testLikeAndContains() throws Exception
|
||||
{
|
||||
rootNodeRef = localRootNode;
|
||||
|
||||
DynamicNamespacePrefixResolver namespacePrefixResolver = new DynamicNamespacePrefixResolver(null);
|
||||
namespacePrefixResolver.registerNamespace(NamespaceService.SYSTEM_MODEL_PREFIX, NamespaceService.SYSTEM_MODEL_1_0_URI);
|
||||
namespacePrefixResolver.registerNamespace(NamespaceService.CONTENT_MODEL_PREFIX, NamespaceService.CONTENT_MODEL_1_0_URI);
|
||||
namespacePrefixResolver.registerNamespace(BaseNodeServiceTest.TEST_PREFIX, BaseNodeServiceTest.NAMESPACE);
|
||||
|
||||
PerformanceMonitor selectNodesPerf = new PerformanceMonitor(getClass().getSimpleName(), "selectNodes");
|
||||
PerformanceMonitor selectPropertiesPerf = new PerformanceMonitor(getClass().getSimpleName(), "selectProperties");
|
||||
|
||||
List<NodeRef> answer;
|
||||
|
||||
selectNodesPerf.start();
|
||||
answer = searchService.selectNodes(rootNodeRef, "//*[like(@test:animal, 'm_nkey')]", null, namespacePrefixResolver, false);
|
||||
assertEquals(1, answer.size());
|
||||
selectNodesPerf.stop();
|
||||
|
||||
selectNodesPerf.start();
|
||||
answer = searchService.selectNodes(rootNodeRef, "//*[like(@test:animal, 'm%key')]", null, namespacePrefixResolver, false);
|
||||
assertEquals(1, answer.size());
|
||||
selectNodesPerf.stop();
|
||||
|
||||
selectNodesPerf.start();
|
||||
answer = searchService.selectNodes(rootNodeRef, "//*[like(@test:animal, 'monk__')]", null, namespacePrefixResolver, false);
|
||||
assertEquals(1, answer.size());
|
||||
selectNodesPerf.stop();
|
||||
|
||||
selectNodesPerf.start();
|
||||
answer = searchService.selectNodes(rootNodeRef, "//*[like(@test:animal, 'monk%')]", null, namespacePrefixResolver, false);
|
||||
assertEquals(1, answer.size());
|
||||
selectNodesPerf.stop();
|
||||
|
||||
selectNodesPerf.start();
|
||||
answer = searchService.selectNodes(rootNodeRef, "//*[like(@test:animal, 'monk\\%')]", null, namespacePrefixResolver, false);
|
||||
assertEquals(0, answer.size());
|
||||
selectNodesPerf.stop();
|
||||
|
||||
selectNodesPerf.start();
|
||||
answer = searchService.selectNodes(rootNodeRef, "//*[contains('monkey')]", null, namespacePrefixResolver, false);
|
||||
assertEquals(1, answer.size());
|
||||
selectNodesPerf.stop();
|
||||
|
||||
selectPropertiesPerf.start();
|
||||
List<Serializable> result = searchService.selectProperties(rootNodeRef, "//@*[contains('monkey')]", null, namespacePrefixResolver, false);
|
||||
assertEquals(2, result.size());
|
||||
selectPropertiesPerf.stop();
|
||||
|
||||
selectNodesPerf.start();
|
||||
answer = searchService.selectNodes(rootNodeRef, "//*[contains('mon?ey')]", null, namespacePrefixResolver, false);
|
||||
assertEquals(1, answer.size());
|
||||
selectNodesPerf.stop();
|
||||
|
||||
selectPropertiesPerf.start();
|
||||
result = searchService.selectProperties(rootNodeRef, "//@*[contains('mon?ey')]", null, namespacePrefixResolver, false);
|
||||
assertEquals(2, result.size());
|
||||
selectPropertiesPerf.stop();
|
||||
|
||||
selectNodesPerf.start();
|
||||
answer = searchService.selectNodes(rootNodeRef, "//*[contains('m*y')]", null, namespacePrefixResolver, false);
|
||||
assertEquals(1, answer.size());
|
||||
selectNodesPerf.stop();
|
||||
|
||||
selectPropertiesPerf.start();
|
||||
result = searchService.selectProperties(rootNodeRef, "//@*[contains('mon*')]", null, namespacePrefixResolver, false);
|
||||
assertEquals(2, result.size());
|
||||
selectPropertiesPerf.stop();
|
||||
|
||||
selectNodesPerf.start();
|
||||
answer = searchService.selectNodes(rootNodeRef, "//*[contains('*nkey')]", null, namespacePrefixResolver, false);
|
||||
assertEquals(1, answer.size());
|
||||
selectNodesPerf.stop();
|
||||
|
||||
selectPropertiesPerf.start();
|
||||
result = searchService.selectProperties(rootNodeRef, "//@*[contains('?onkey')]", null, namespacePrefixResolver, false);
|
||||
assertEquals(2, result.size());
|
||||
selectPropertiesPerf.stop();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user