mirror of
				https://github.com/Alfresco/alfresco-community-repo.git
				synced 2025-10-29 15:21:53 +00:00 
			
		
		
		
	125324 rneamtu: Merged 5.1.N (5.1.2) to 5.2.N (5.2.1)
      125247 rneamtu: Merged 5.1.1 (5.1.1) to 5.1.N (5.1.2)
         125138 bhorje: ACE-5306 added cm:titled aspect to virtual smart folder entries  
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@127779 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
		
	
		
			
				
	
	
		
			1516 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			1516 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| /* 
 | |
|  * Copyright (C) 2005-2015 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.virtual.bundle;
 | |
| 
 | |
| import java.io.IOException;
 | |
| import java.io.Serializable;
 | |
| import java.nio.charset.StandardCharsets;
 | |
| import java.util.ArrayList;
 | |
| import java.util.Arrays;
 | |
| import java.util.Collection;
 | |
| import java.util.Collections;
 | |
| 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.download.DownloadModel;
 | |
| import org.alfresco.repo.node.archive.NodeArchiveService;
 | |
| import org.alfresco.repo.node.db.traitextender.NodeServiceExtension;
 | |
| import org.alfresco.repo.node.db.traitextender.NodeServiceTrait;
 | |
| import org.alfresco.repo.virtual.ActualEnvironment;
 | |
| import org.alfresco.repo.virtual.ActualEnvironmentException;
 | |
| import org.alfresco.repo.virtual.VirtualContentModel;
 | |
| import org.alfresco.repo.virtual.VirtualizationException;
 | |
| import org.alfresco.repo.virtual.config.NodeRefExpression;
 | |
| import org.alfresco.repo.virtual.ref.GetActualNodeRefMethod;
 | |
| import org.alfresco.repo.virtual.ref.GetAspectsMethod;
 | |
| import org.alfresco.repo.virtual.ref.GetParentReferenceMethod;
 | |
| import org.alfresco.repo.virtual.ref.NodeProtocol;
 | |
| import org.alfresco.repo.virtual.ref.Protocols;
 | |
| import org.alfresco.repo.virtual.ref.Reference;
 | |
| import org.alfresco.repo.virtual.store.VirtualStore;
 | |
| import org.alfresco.repo.virtual.template.FilingData;
 | |
| import org.alfresco.service.cmr.dictionary.InvalidAspectException;
 | |
| import org.alfresco.service.cmr.model.FileInfo;
 | |
| import org.alfresco.service.cmr.repository.AssociationRef;
 | |
| import org.alfresco.service.cmr.repository.ChildAssociationRef;
 | |
| import org.alfresco.service.cmr.repository.ContentWriter;
 | |
| import org.alfresco.service.cmr.repository.InvalidChildAssociationRefException;
 | |
| import org.alfresco.service.cmr.repository.InvalidNodeRefException;
 | |
| import org.alfresco.service.cmr.repository.InvalidStoreRefException;
 | |
| import org.alfresco.service.cmr.repository.NodeRef;
 | |
| import org.alfresco.service.cmr.repository.NodeRef.Status;
 | |
| import org.alfresco.service.cmr.repository.Path;
 | |
| import org.alfresco.service.cmr.repository.StoreExistsException;
 | |
| import org.alfresco.service.cmr.repository.StoreRef;
 | |
| import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
 | |
| import org.alfresco.service.namespace.QName;
 | |
| import org.alfresco.service.namespace.QNamePattern;
 | |
| import org.alfresco.service.namespace.RegexQNamePattern;
 | |
| import org.apache.commons.io.IOUtils;
 | |
| import org.apache.commons.logging.Log;
 | |
| import org.apache.commons.logging.LogFactory;
 | |
| 
 | |
| public class VirtualNodeServiceExtension extends VirtualSpringBeanExtension<NodeServiceExtension, NodeServiceTrait>
 | |
|             implements NodeServiceExtension
 | |
| {
 | |
|     private static Log logger = LogFactory.getLog(VirtualNodeServiceExtension.class);
 | |
| 
 | |
|     private VirtualStore smartStore;
 | |
| 
 | |
|     private ActualEnvironment environment;
 | |
| 
 | |
|     private NodeRefExpression downloadAssociationsFolder;
 | |
| 
 | |
|     public VirtualNodeServiceExtension()
 | |
|     {
 | |
|         super(NodeServiceTrait.class);
 | |
|     }
 | |
| 
 | |
|     public void setEnvironment(ActualEnvironment environment)
 | |
|     {
 | |
|         this.environment = environment;
 | |
|     }
 | |
| 
 | |
|     public void setSmartStore(VirtualStore smartStore)
 | |
|     {
 | |
|         this.smartStore = smartStore;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean hasAspect(NodeRef nodeRef, QName aspectQName)
 | |
|     {
 | |
|         if (Reference.isReference(nodeRef))
 | |
|         {
 | |
|             boolean isNodeProtocol = Reference.fromNodeRef(nodeRef).getProtocol().equals(Protocols.NODE.protocol);
 | |
|             if (VirtualContentModel.ASPECT_VIRTUAL.equals(aspectQName) || ContentModel.ASPECT_TITLED.equals(aspectQName))
 | |
|             {
 | |
|                 return !isNodeProtocol;
 | |
|             }
 | |
|             else if (VirtualContentModel.ASPECT_VIRTUAL_DOCUMENT.equals(aspectQName))
 | |
|             {
 | |
|                 return isNodeProtocol;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 Reference reference = Reference.fromNodeRef(nodeRef);
 | |
|                 NodeRef actualNodeRef = reference.execute(new GetActualNodeRefMethod(environment));
 | |
|                 return getTrait().hasAspect(actualNodeRef,
 | |
|                                             aspectQName);
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return getTrait().hasAspect(nodeRef,
 | |
|                                         aspectQName);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public QName getType(NodeRef nodeRef)
 | |
|     {
 | |
|         if (Reference.isReference(nodeRef))
 | |
|         {
 | |
|             QName type = smartStore.getType(Reference.fromNodeRef(nodeRef));
 | |
|             return type;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return getTrait().getType(nodeRef);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private Map<QName, Serializable> getVirtualProperties(Reference reference)
 | |
|     {
 | |
|         return smartStore.getProperties(reference);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public Map<QName, Serializable> getProperties(NodeRef nodeRef)
 | |
|     {
 | |
|         if (Reference.isReference(nodeRef))
 | |
|         {
 | |
|             return getVirtualProperties(Reference.fromNodeRef(nodeRef));
 | |
| 
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return getTrait().getProperties(nodeRef);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public Serializable getProperty(NodeRef nodeRef, QName qname)
 | |
|     {
 | |
|         if (Reference.isReference(nodeRef))
 | |
|         {
 | |
|             return getVirtualProperties(Reference.fromNodeRef(nodeRef)).get(qname);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return getTrait().getProperty(nodeRef,
 | |
|                                           qname);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public Set<QName> getAspects(NodeRef nodeRef)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
|         if (Reference.isReference(nodeRef))
 | |
|         {
 | |
|             Reference vRef = Reference.fromNodeRef(nodeRef);
 | |
|             GetAspectsMethod method = new GetAspectsMethod(theTrait,
 | |
|                                                            environment);
 | |
| 
 | |
|             return vRef.execute(method);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return theTrait.getAspects(nodeRef);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public Path getPath(NodeRef nodeRef)
 | |
|     {
 | |
|         if (Reference.isReference(nodeRef))
 | |
|         {
 | |
|             return Reference.fromNodeRef(nodeRef).execute(new GetPathMethod(smartStore,
 | |
|                                                                             environment));
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return getTrait().getPath(nodeRef);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<Path> getPaths(NodeRef nodeRef, boolean primaryOnly)
 | |
|     {
 | |
|         if (Reference.isReference(nodeRef))
 | |
|         {
 | |
|             Reference reference = Reference.fromNodeRef(nodeRef);
 | |
|             NodeRef actualNodeRef = reference.execute(new GetActualNodeRefMethod(environment));
 | |
|             return getTrait().getPaths(actualNodeRef,
 | |
|                                        primaryOnly);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return getTrait().getPaths(nodeRef,
 | |
|                                        primaryOnly);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean exists(NodeRef nodeRef)
 | |
|     {
 | |
|         if (Reference.isReference(nodeRef))
 | |
|         {
 | |
|             // For now references last forever (i.e. there is no expiration
 | |
|             // mechanism )
 | |
|             return true;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return getTrait().exists(nodeRef);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public ChildAssociationRef createNode(NodeRef parentRef, QName assocTypeQName, QName assocQName,
 | |
|                 QName nodeTypeQName)
 | |
|     {
 | |
|         if (Reference.isReference(parentRef))
 | |
|         {
 | |
|             return createNode(parentRef,
 | |
|                               assocTypeQName,
 | |
|                               assocQName,
 | |
|                               nodeTypeQName,
 | |
|                               Collections.<QName, Serializable> emptyMap());
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             QName materialAssocQName = materializeAssocQName(assocQName);
 | |
|             return getTrait().createNode(parentRef,
 | |
|                                          assocTypeQName,
 | |
|                                          materialAssocQName,
 | |
|                                          nodeTypeQName);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public ChildAssociationRef createNode(NodeRef parentRef, QName assocTypeQName, QName assocQName,
 | |
|                 QName nodeTypeQName, Map<QName, Serializable> properties)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
|         if (Reference.isReference(parentRef) && !isVirtualContextFolder(parentRef,
 | |
|                                                                         environment))
 | |
|         {
 | |
|             // CM-533 Suppress options to create folders in a virtual folder
 | |
|             // (repo)
 | |
|             if (environment.isSubClass(nodeTypeQName,
 | |
|                                        ContentModel.TYPE_FOLDER))
 | |
|             {
 | |
|                 throw new VirtualizationException("The creation of folders within virtual folders is disabled.");
 | |
|             }
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 Reference parentReference = Reference.fromNodeRef(parentRef);
 | |
|                 FilingData filingData = smartStore.createFilingData(parentReference,
 | |
|                                                                       assocTypeQName,
 | |
|                                                                       assocQName,
 | |
|                                                                       nodeTypeQName,
 | |
|                                                                       properties);
 | |
| 
 | |
|                 NodeRef childParentNodeRef = filingData.getFilingNodeRef();
 | |
| 
 | |
|                 if (childParentNodeRef != null)
 | |
|                 {
 | |
|                     Map<QName, Serializable> filingDataProperties = filingData.getProperties();
 | |
|                     QName changedAssocQName = assocQName;
 | |
|                     if (filingDataProperties.containsKey(ContentModel.PROP_NAME))
 | |
|                     {
 | |
|                         String fileName = (String) filingDataProperties.get(ContentModel.PROP_NAME);
 | |
|                         String changedFileName = handleExistingFile(childParentNodeRef,
 | |
|                                                                     fileName);
 | |
|                         if (!changedFileName.equals(fileName))
 | |
|                         {
 | |
|                             filingDataProperties.put(ContentModel.PROP_NAME,
 | |
|                                                      changedFileName);
 | |
|                             QName filingDataAssocQName = filingData.getAssocQName();
 | |
|                             changedAssocQName = QName.createQName(filingDataAssocQName.getNamespaceURI(),
 | |
|                                                                   QName.createValidLocalName(changedFileName));
 | |
|                         }
 | |
|                     }
 | |
|                     ChildAssociationRef actualChildAssocRef = theTrait.createNode(childParentNodeRef,
 | |
|                                                                                   filingData.getAssocTypeQName(),
 | |
|                                                                                   changedAssocQName == null
 | |
|                                                                                               ? filingData.getAssocQName()
 | |
|                                                                                               : changedAssocQName,
 | |
|                                                                                   filingData.getNodeTypeQName(),
 | |
|                                                                                   filingDataProperties);
 | |
| 
 | |
|                     Reference nodeProtocolChildRef = NodeProtocol.newReference(actualChildAssocRef.getChildRef(),
 | |
|                                                                                parentReference);
 | |
|                     QName vChildAssocQName = QName
 | |
|                                 .createQNameWithValidLocalName(VirtualContentModel.VIRTUAL_CONTENT_MODEL_1_0_URI,
 | |
|                                                                actualChildAssocRef.getQName().getLocalName());
 | |
|                     ChildAssociationRef childAssocRef = new ChildAssociationRef(actualChildAssocRef.getTypeQName(),
 | |
|                                                                                 parentRef,
 | |
|                                                                                 vChildAssocQName,
 | |
|                                                                                 nodeProtocolChildRef.toNodeRef());
 | |
|                     Set<QName> aspects = filingData.getAspects();
 | |
| 
 | |
|                     for (QName aspect : aspects)
 | |
|                     {
 | |
|                         theTrait.addAspect(actualChildAssocRef.getChildRef(),
 | |
|                                            aspect,
 | |
|                                            filingDataProperties);
 | |
|                     }
 | |
| 
 | |
|                     return childAssocRef;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     throw new InvalidNodeRefException("Can not create node using parent ",
 | |
|                                                       parentRef);
 | |
|                 }
 | |
| 
 | |
|             }
 | |
|             catch (VirtualizationException e)
 | |
|             {
 | |
|                 throw new InvalidNodeRefException("Could not create node in virtual context.",
 | |
|                                                   parentRef,
 | |
|                                                   e);
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             QName materialAssocQName = materializeAssocQName(assocQName);
 | |
|             if (isVirtualContextFolder(parentRef,
 | |
|                                        environment))
 | |
|             {
 | |
|                 parentRef = smartStore.materializeIfPossible(parentRef);
 | |
|             }
 | |
|             return theTrait.createNode(parentRef,
 | |
|                                        assocTypeQName,
 | |
|                                        materialAssocQName,
 | |
|                                        nodeTypeQName,
 | |
|                                        properties);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private QName materializeAssocQName(QName assocQName)
 | |
|     {
 | |
|         // Version nodes have too long assocQNames so we try
 | |
|         // to detect references with "material" protocols in order to
 | |
|         // replace the assocQNames with material correspondents.
 | |
|         try
 | |
|         {
 | |
|             String lName = assocQName.getLocalName();
 | |
|             NodeRef nrAssocQName = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE,
 | |
|                                                lName);
 | |
|             if (Reference.isReference(nrAssocQName))
 | |
|             {
 | |
|                 nrAssocQName = smartStore.materializeIfPossible(nrAssocQName);
 | |
|                 QName materialAssocQName = QName.createQName(assocQName.getNamespaceURI(),
 | |
|                                                              nrAssocQName.getId());
 | |
|                 return materialAssocQName;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 return assocQName;
 | |
|             }
 | |
|         }
 | |
|         catch (VirtualizationException e)
 | |
|         {
 | |
|             // We assume it can not be put through the
 | |
|             // isReference-virtualize-materialize.
 | |
|             if (logger.isDebugEnabled())
 | |
|             {
 | |
|                 logger.debug("Defaulting on materializeAssocQName due to error.",
 | |
|                              e);
 | |
|             }
 | |
|             return assocQName;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private String handleExistingFile(NodeRef parentNodeRef, String fileName)
 | |
|     {
 | |
|         NodeServiceTrait actualNodeService = getTrait();
 | |
|         NodeRef existingFile = actualNodeService.getChildByName(parentNodeRef,
 | |
|                                                                 ContentModel.ASSOC_CONTAINS,
 | |
|                                                                 fileName);
 | |
|         if (existingFile != null)
 | |
|         {
 | |
|             int counter = 1;
 | |
|             int dotIndex;
 | |
|             String tmpFilename = "";
 | |
|             final String dot = ".";
 | |
|             final String hyphen = "-";
 | |
| 
 | |
|             while (existingFile != null)
 | |
|             {
 | |
|                 int beforeCounter = fileName.lastIndexOf(hyphen);
 | |
|                 dotIndex = fileName.lastIndexOf(dot);
 | |
|                 if (dotIndex == 0)
 | |
|                 {
 | |
|                     // File didn't have a proper 'name' instead it had just a
 | |
|                     // suffix and
 | |
|                     // started with a ".", create "1.txt"
 | |
|                     tmpFilename = counter + fileName;
 | |
|                 }
 | |
|                 else if (dotIndex > 0)
 | |
|                 {
 | |
| 
 | |
|                     if (beforeCounter > 0 && beforeCounter < dotIndex)
 | |
|                     {
 | |
|                         // does file have counter in it's name or it just
 | |
|                         // contains -1
 | |
|                         String originalFileName = fileName.substring(0,
 | |
|                                                                      beforeCounter)
 | |
|                                     + fileName.substring(dotIndex);
 | |
|                         boolean doesOriginalFileExist = actualNodeService.getChildByName(parentNodeRef,
 | |
|                                                                                          ContentModel.ASSOC_CONTAINS,
 | |
|                                                                                          originalFileName) != null;
 | |
|                         if (doesOriginalFileExist)
 | |
|                         {
 | |
|                             String counterStr = fileName.substring(beforeCounter + 1,
 | |
|                                                                    dotIndex);
 | |
|                             try
 | |
|                             {
 | |
|                                 int parseInt = DefaultTypeConverter.INSTANCE.intValue(counterStr);
 | |
|                                 counter = parseInt + 1;
 | |
|                                 fileName = fileName.substring(0,
 | |
|                                                               beforeCounter)
 | |
|                                             + fileName.substring(dotIndex);
 | |
|                                 dotIndex = fileName.lastIndexOf(dot);
 | |
| 
 | |
|                             }
 | |
|                             catch (NumberFormatException ex)
 | |
|                             {
 | |
|                                 // "-" is not before counter
 | |
|                             }
 | |
| 
 | |
|                         }
 | |
|                     }
 | |
|                     tmpFilename = fileName.substring(0,
 | |
|                                                      dotIndex)
 | |
|                                 + hyphen + counter + fileName.substring(dotIndex);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     // Filename didn't contain a dot at all, create "filename-1"
 | |
|                     tmpFilename = fileName + hyphen + counter;
 | |
|                 }
 | |
|                 existingFile = actualNodeService.getChildByName(parentNodeRef,
 | |
|                                                                 ContentModel.ASSOC_CONTAINS,
 | |
|                                                                 tmpFilename);
 | |
|                 counter++;
 | |
|             }
 | |
|             fileName = tmpFilename;
 | |
|         }
 | |
| 
 | |
|         return fileName;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<ChildAssociationRef> getParentAssocs(NodeRef nodeRef)
 | |
|     {
 | |
|         if (Reference.isReference(nodeRef))
 | |
|         {
 | |
|             return getParentAssocs(nodeRef,
 | |
|                                    RegexQNamePattern.MATCH_ALL,
 | |
|                                    RegexQNamePattern.MATCH_ALL);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return getTrait().getParentAssocs(nodeRef);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<ChildAssociationRef> getParentAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern,
 | |
|                 QNamePattern qnamePattern)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
|         if (Reference.isReference(nodeRef))
 | |
|         {
 | |
|             Reference reference = Reference.fromNodeRef(nodeRef);
 | |
|             Reference parent = reference.execute(new GetParentReferenceMethod());
 | |
|             if (parent == null)
 | |
|             {
 | |
|                 return theTrait.getParentAssocs(reference.execute(new GetActualNodeRefMethod(environment)),
 | |
|                                                 typeQNamePattern,
 | |
|                                                 qnamePattern);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (typeQNamePattern.isMatch(ContentModel.ASSOC_CONTAINS))
 | |
|                 {
 | |
|                     Reference parentsParent = parent.execute(new GetParentReferenceMethod());
 | |
| 
 | |
|                     NodeRef parentNodeRef = parent.toNodeRef();
 | |
|                     if (parentsParent == null)
 | |
|                     {
 | |
|                         parentNodeRef = parent.execute(new GetActualNodeRefMethod(environment));
 | |
| 
 | |
|                     }
 | |
| 
 | |
|                     NodeRef referenceNodeRef = reference.toNodeRef();
 | |
|                     Map<QName, Serializable> properties = smartStore.getProperties(reference);
 | |
|                     Serializable name = properties.get(ContentModel.PROP_NAME);
 | |
|                     QName assocChildName = QName
 | |
|                                 .createQNameWithValidLocalName(VirtualContentModel.VIRTUAL_CONTENT_MODEL_1_0_URI,
 | |
|                                                                name.toString());
 | |
|                     if (qnamePattern.isMatch(assocChildName))
 | |
|                     {
 | |
|                         ChildAssociationRef assoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS,
 | |
|                                                                             parentNodeRef,
 | |
|                                                                             assocChildName,
 | |
|                                                                             referenceNodeRef);
 | |
|                         return Arrays.asList(assoc);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         return Collections.emptyList();
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     return Collections.emptyList();
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return theTrait.getParentAssocs(nodeRef,
 | |
|                                             typeQNamePattern,
 | |
|                                             qnamePattern);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
|         boolean canVirtualize = canVirtualizeAssocNodeRef(nodeRef);
 | |
|         if (canVirtualize)
 | |
|         {
 | |
|             Reference reference = smartStore.virtualize(nodeRef);
 | |
|             List<ChildAssociationRef> virtualAssociations = smartStore.getChildAssocs(reference,
 | |
|                                                                                         RegexQNamePattern.MATCH_ALL,
 | |
|                                                                                         RegexQNamePattern.MATCH_ALL,
 | |
|                                                                                         Integer.MAX_VALUE,
 | |
|                                                                                         false);
 | |
|             List<ChildAssociationRef> associations = new LinkedList<>(virtualAssociations);
 | |
|             if (smartStore.canMaterialize(reference))
 | |
|             {
 | |
|                 NodeRef materialReference = smartStore.materialize(reference);
 | |
|                 List<ChildAssociationRef> actualAssociations = theTrait.getChildAssocs(materialReference,
 | |
|                                                                                        RegexQNamePattern.MATCH_ALL,
 | |
|                                                                                        RegexQNamePattern.MATCH_ALL,
 | |
|                                                                                        Integer.MAX_VALUE,
 | |
|                                                                                        false);
 | |
|                 associations.addAll(actualAssociations);
 | |
|             }
 | |
| 
 | |
|             return associations;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return theTrait.getChildAssocs(nodeRef);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern,
 | |
|                 QNamePattern qnamePattern)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
|         boolean canVirtualize = canVirtualizeAssocNodeRef(nodeRef);
 | |
|         if (canVirtualize)
 | |
|         {
 | |
|             Reference reference = smartStore.virtualize(nodeRef);
 | |
|             List<ChildAssociationRef> virtualAssociations = smartStore.getChildAssocs(reference,
 | |
|                                                                                         typeQNamePattern,
 | |
|                                                                                         qnamePattern,
 | |
|                                                                                         Integer.MAX_VALUE,
 | |
|                                                                                         false);
 | |
|             List<ChildAssociationRef> associations = new LinkedList<>(virtualAssociations);
 | |
| 
 | |
|             if (smartStore.canMaterialize(reference))
 | |
|             {
 | |
|                 NodeRef materialReference = smartStore.materialize(reference);
 | |
|                 List<ChildAssociationRef> actualAssociations = theTrait.getChildAssocs(materialReference,
 | |
|                                                                                        typeQNamePattern,
 | |
|                                                                                        qnamePattern);
 | |
|                 associations.addAll(actualAssociations);
 | |
|             }
 | |
|             return associations;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return theTrait.getChildAssocs(nodeRef,
 | |
|                                            typeQNamePattern,
 | |
|                                            qnamePattern);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern,
 | |
|                 QNamePattern qnamePattern, int maxResults, boolean preload)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
|         boolean canVirtualize = canVirtualizeAssocNodeRef(nodeRef);
 | |
|         if (canVirtualize)
 | |
|         {
 | |
|             Reference reference = smartStore.virtualize(nodeRef);
 | |
|             List<ChildAssociationRef> virtualAssociations = smartStore.getChildAssocs(reference,
 | |
|                                                                                         typeQNamePattern,
 | |
|                                                                                         qnamePattern,
 | |
|                                                                                         maxResults,
 | |
|                                                                                         preload);
 | |
|             List<ChildAssociationRef> associations = new LinkedList<>(virtualAssociations);
 | |
| 
 | |
|             if (associations.size() < maxResults)
 | |
|             {
 | |
|                 if (smartStore.canMaterialize(reference))
 | |
|                 {
 | |
|                     NodeRef materialReference = smartStore.materialize(reference);
 | |
|                     List<ChildAssociationRef> actualAssociations = theTrait.getChildAssocs(materialReference,
 | |
|                                                                                            typeQNamePattern,
 | |
|                                                                                            qnamePattern,
 | |
|                                                                                            maxResults - associations
 | |
|                                                                                                        .size(),
 | |
|                                                                                            preload);
 | |
|                     associations.addAll(actualAssociations);
 | |
|                 }
 | |
|             }
 | |
|             return associations;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return theTrait.getChildAssocs(nodeRef,
 | |
|                                            typeQNamePattern,
 | |
|                                            qnamePattern,
 | |
|                                            maxResults,
 | |
|                                            preload);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private boolean canVirtualizeAssocNodeRef(NodeRef nodeRef)
 | |
|     {
 | |
|         boolean canVirtualize = nodeRef.getId().contains("solr") ? false : smartStore.canVirtualize(nodeRef);
 | |
|         return canVirtualize;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, QNamePattern typeQNamePattern,
 | |
|                 QNamePattern qnamePattern, boolean preload)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
|         boolean canVirtualize = canVirtualizeAssocNodeRef(nodeRef);
 | |
|         if (canVirtualize)
 | |
|         {
 | |
|             Reference reference = smartStore.virtualize(nodeRef);
 | |
|             List<ChildAssociationRef> virtualAssociations = smartStore.getChildAssocs(reference,
 | |
|                                                                                         typeQNamePattern,
 | |
|                                                                                         qnamePattern,
 | |
|                                                                                         Integer.MAX_VALUE,
 | |
|                                                                                         preload);
 | |
|             List<ChildAssociationRef> associations = new LinkedList<>(virtualAssociations);
 | |
| 
 | |
|             if (smartStore.canMaterialize(reference))
 | |
|             {
 | |
|                 NodeRef materialReference = smartStore.materialize(reference);
 | |
|                 List<ChildAssociationRef> actualAssociations = theTrait.getChildAssocs(materialReference,
 | |
|                                                                                        typeQNamePattern,
 | |
|                                                                                        qnamePattern,
 | |
|                                                                                        preload);
 | |
|                 associations.addAll(actualAssociations);
 | |
|             }
 | |
|             return associations;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return theTrait.getChildAssocs(nodeRef,
 | |
|                                            typeQNamePattern,
 | |
|                                            qnamePattern,
 | |
|                                            preload);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<ChildAssociationRef> getChildAssocs(NodeRef nodeRef, Set<QName> childNodeTypeQNames)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
|         boolean canVirtualize = canVirtualizeAssocNodeRef(nodeRef);
 | |
|         if (canVirtualize)
 | |
|         {
 | |
|             Reference reference = smartStore.virtualize(nodeRef);
 | |
|             List<ChildAssociationRef> virtualAssociations = smartStore.getChildAssocs(reference,
 | |
|                                                                                         childNodeTypeQNames);
 | |
|             List<ChildAssociationRef> associations = new LinkedList<>(virtualAssociations);
 | |
|             if (smartStore.canMaterialize(reference))
 | |
|             {
 | |
|                 NodeRef materialReference = smartStore.materialize(reference);
 | |
|                 List<ChildAssociationRef> actualAssociations = theTrait.getChildAssocs(materialReference,
 | |
|                                                                                        childNodeTypeQNames);
 | |
|                 associations.addAll(actualAssociations);
 | |
|             }
 | |
| 
 | |
|             return associations;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return theTrait.getChildAssocs(nodeRef,
 | |
|                                            childNodeTypeQNames);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<ChildAssociationRef> getChildAssocsByPropertyValue(NodeRef nodeRef, QName propertyQName,
 | |
|                 Serializable value)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
|         boolean canVirtualize = canVirtualizeAssocNodeRef(nodeRef);
 | |
|         if (canVirtualize)
 | |
|         {
 | |
|             Reference reference = smartStore.virtualize(nodeRef);
 | |
|             List<ChildAssociationRef> virtualAssociations = smartStore.getChildAssocsByPropertyValue(reference,
 | |
|                                                                                                        propertyQName,
 | |
|                                                                                                        value);
 | |
|             List<ChildAssociationRef> associations = new LinkedList<>(virtualAssociations);
 | |
|             if (smartStore.canMaterialize(reference))
 | |
|             {
 | |
|                 NodeRef materialReference = smartStore.materialize(reference);
 | |
|                 List<ChildAssociationRef> actualAssociations = theTrait.getChildAssocsByPropertyValue(materialReference,
 | |
|                                                                                                       propertyQName,
 | |
|                                                                                                       value);
 | |
|                 associations.addAll(actualAssociations);
 | |
|             }
 | |
| 
 | |
|             return associations;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return theTrait.getChildAssocsByPropertyValue(nodeRef,
 | |
|                                                           propertyQName,
 | |
|                                                           value);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public NodeRef getChildByName(NodeRef nodeRef, QName assocTypeQName, String childName)
 | |
|     {
 | |
|         // TODO: optimize
 | |
| 
 | |
|         if (smartStore.canVirtualize(nodeRef))
 | |
|         {
 | |
|             Reference virtualNode = smartStore.virtualize(nodeRef);
 | |
| 
 | |
|             Reference theChild = smartStore.getChildByName(virtualNode,
 | |
|                                                              assocTypeQName,
 | |
|                                                              childName);
 | |
| 
 | |
|             if (theChild != null)
 | |
|             {
 | |
|                 NodeRef childNodeRef = theChild.toNodeRef();
 | |
| 
 | |
|                 return childNodeRef;
 | |
|             }
 | |
|             if (smartStore.isVirtual(nodeRef))
 | |
|             {
 | |
|                 return null;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // TODO: add virtualizable enabler
 | |
|         nodeRef = materializeIfPossible(nodeRef);
 | |
|         return getTrait().getChildByName(nodeRef,
 | |
|                                          assocTypeQName,
 | |
|                                          childName);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public ChildAssociationRef getPrimaryParent(NodeRef nodeRef)
 | |
|     {
 | |
|         if (Reference.isReference(nodeRef))
 | |
|         {
 | |
|             Reference reference = Reference.fromNodeRef(nodeRef);
 | |
|             Reference parent = reference.execute(new GetParentReferenceMethod());
 | |
|             if (parent == null)
 | |
|             {
 | |
|                 return getTrait().getPrimaryParent(reference.execute(new GetActualNodeRefMethod(environment)));
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 Reference parentsParent = parent.execute(new GetParentReferenceMethod());
 | |
| 
 | |
|                 NodeRef parentNodeRef = parent.toNodeRef();
 | |
|                 if (parentsParent == null)
 | |
|                 {
 | |
|                     parentNodeRef = parent.execute(new GetActualNodeRefMethod(environment));
 | |
| 
 | |
|                 }
 | |
| 
 | |
|                 NodeRef referenceNodeRef = reference.toNodeRef();
 | |
|                 ChildAssociationRef assoc = new ChildAssociationRef(ContentModel.ASSOC_CONTAINS,
 | |
|                                                                     parentNodeRef,
 | |
|                                                                     NodeArchiveService.QNAME_ARCHIVED_ITEM,
 | |
|                                                                     referenceNodeRef,
 | |
|                                                                     true,
 | |
|                                                                     -1);
 | |
|                 return assoc;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return getTrait().getPrimaryParent(nodeRef);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public void setDownloadAssociationsFolder(NodeRefExpression downloadAssocaiationsFolder)
 | |
|     {
 | |
|         this.downloadAssociationsFolder = downloadAssocaiationsFolder;
 | |
|     }
 | |
| 
 | |
|     private void cleanUpDownloadTargetAssocs(NodeRef sourceNodeRef)
 | |
|     {
 | |
| 
 | |
|         NodeRef tempFolderNodeRef = downloadAssociationsFolder.resolve();
 | |
|         if (tempFolderNodeRef == null)
 | |
|         {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         String tempFileName = sourceNodeRef.getId();
 | |
| 
 | |
|         NodeRef tempFileNodeRef = environment.getChildByName(tempFolderNodeRef,
 | |
|                                                              ContentModel.ASSOC_CONTAINS,
 | |
|                                                              tempFileName);
 | |
|         if (tempFileNodeRef == null)
 | |
|         {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         environment.delete(tempFileNodeRef);
 | |
|     }
 | |
| 
 | |
|     private List<AssociationRef> getDownloadTargetAssocs(NodeRef sourceNodeRef)
 | |
|     {
 | |
|         try
 | |
|         {
 | |
|             List<AssociationRef> result = new ArrayList<AssociationRef>();
 | |
| 
 | |
|             NodeRef tempFolderNodeRef = downloadAssociationsFolder.resolve();
 | |
|             if (tempFolderNodeRef == null)
 | |
|             {
 | |
|                 return result;
 | |
|             }
 | |
| 
 | |
|             String tempFileName = sourceNodeRef.getId();
 | |
| 
 | |
|             NodeRef tempFileNodeRef = environment.getChildByName(tempFolderNodeRef,
 | |
|                                                                  ContentModel.ASSOC_CONTAINS,
 | |
|                                                                  tempFileName);
 | |
|             if (tempFileNodeRef == null)
 | |
|             {
 | |
|                 return result;
 | |
|             }
 | |
|             List<String> readLines = IOUtils.readLines(environment.openContentStream(tempFileNodeRef),
 | |
|                                                        StandardCharsets.UTF_8);
 | |
|             for (String line : readLines)
 | |
|             {
 | |
|                 NodeRef targetRef = new NodeRef(line);
 | |
|                 AssociationRef assocRef = new AssociationRef(sourceNodeRef,
 | |
|                                                              DownloadModel.ASSOC_REQUESTED_NODES,
 | |
|                                                              targetRef);
 | |
|                 result.add(assocRef);
 | |
|             }
 | |
| 
 | |
|             return result;
 | |
|         }
 | |
|         catch (IOException e)
 | |
|         {
 | |
|             throw new VirtualizationException(e);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private void createDownloadAssociation(NodeRef sourceNodeRef, NodeRef targetRef)
 | |
|     {
 | |
| 
 | |
|         NodeRef tempFolderNodeRef = downloadAssociationsFolder.resolve(true);
 | |
| 
 | |
|         String tempFileName = sourceNodeRef.getId();
 | |
|         NodeRef tempFileNodeRef = environment.getChildByName(tempFolderNodeRef,
 | |
|                                                              ContentModel.ASSOC_CONTAINS,
 | |
|                                                              tempFileName);
 | |
|         if (tempFileNodeRef == null)
 | |
|         {
 | |
|             FileInfo newTempFileInfo = environment.create(tempFolderNodeRef,
 | |
|                                                           tempFileName,
 | |
|                                                           ContentModel.TYPE_CONTENT);
 | |
|             tempFileNodeRef = newTempFileInfo.getNodeRef();
 | |
|             ContentWriter writer = environment.getWriter(tempFileNodeRef,
 | |
|                                                          ContentModel.PROP_CONTENT,
 | |
|                                                          true);
 | |
|             writer.setMimetype("text/plain");
 | |
|             writer.putContent(targetRef.toString());
 | |
| 
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             ContentWriter writer = environment.getWriter(tempFileNodeRef,
 | |
|                                                          ContentModel.PROP_CONTENT,
 | |
|                                                          true);
 | |
|             try
 | |
|             {
 | |
|                 List<String> readLines = IOUtils.readLines(environment.openContentStream(tempFileNodeRef),
 | |
|                                                            StandardCharsets.UTF_8);
 | |
| 
 | |
|                 String targetRefString = targetRef.toString();
 | |
|                 if (!readLines.contains(targetRefString))
 | |
|                 {
 | |
|                     readLines.add(targetRefString);
 | |
|                 }
 | |
|                 String text = "";
 | |
|                 for (String line : readLines)
 | |
|                 {
 | |
|                     if (text.isEmpty())
 | |
|                     {
 | |
|                         text = line;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         text = text + IOUtils.LINE_SEPARATOR + line;
 | |
|                     }
 | |
| 
 | |
|                 }
 | |
|                 writer.putContent(text);
 | |
|             }
 | |
|             catch (IOException e)
 | |
|             {
 | |
|                 throw new ActualEnvironmentException(e);
 | |
|             }
 | |
| 
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<AssociationRef> getTargetAssocs(NodeRef sourceRef, QNamePattern qnamePattern)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
|         List<AssociationRef> targetAssocs = null;
 | |
| 
 | |
|         if (Reference.isReference(sourceRef))
 | |
|         {
 | |
|             Reference reference = Reference.fromNodeRef(sourceRef);
 | |
|             if (smartStore.canMaterialize(reference))
 | |
|             {
 | |
|                 NodeRef materializedReferece = smartStore.materialize(reference);
 | |
|                 targetAssocs = theTrait.getTargetAssocs(materializedReferece,
 | |
|                                                         qnamePattern);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 targetAssocs = new LinkedList<>();
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             targetAssocs = theTrait.getTargetAssocs(sourceRef,
 | |
|                                                     qnamePattern);
 | |
|         }
 | |
| 
 | |
|         List<AssociationRef> virtualizedIfNeededTargetAssocs = null;
 | |
| 
 | |
|         if (Reference.isReference(sourceRef))
 | |
|         {
 | |
|             virtualizedIfNeededTargetAssocs = new LinkedList<>();
 | |
| 
 | |
|             Reference sourceReference = Reference.fromNodeRef(sourceRef);
 | |
| 
 | |
|             for (AssociationRef associationRef : targetAssocs)
 | |
|             {
 | |
|                 NodeRef targetNodeRef = associationRef.getTargetRef();
 | |
|                 Reference targetReference = NodeProtocol.newReference(targetNodeRef,
 | |
|                                                                       sourceReference
 | |
|                                                                                   .execute(new GetParentReferenceMethod()));
 | |
|                 AssociationRef virtualAssocRef = new AssociationRef(associationRef.getId(),
 | |
|                                                                     sourceRef,
 | |
|                                                                     associationRef.getTypeQName(),
 | |
|                                                                     targetReference.toNodeRef(targetNodeRef
 | |
|                                                                                 .getStoreRef()));
 | |
|                 virtualizedIfNeededTargetAssocs.add(virtualAssocRef);
 | |
|             }
 | |
| 
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             virtualizedIfNeededTargetAssocs = targetAssocs;
 | |
| 
 | |
|             if (DownloadModel.TYPE_DOWNLOAD.equals(environment.getType(sourceRef)))
 | |
|             {
 | |
|                 if (qnamePattern.isMatch(DownloadModel.ASSOC_REQUESTED_NODES))
 | |
|                 {
 | |
|                     List<AssociationRef> virtualTargetAssocs = getDownloadTargetAssocs(sourceRef);
 | |
|                     virtualizedIfNeededTargetAssocs.addAll(virtualTargetAssocs);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return virtualizedIfNeededTargetAssocs;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<AssociationRef> getSourceAssocs(NodeRef targetRef, QNamePattern qnamePattern)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
| 
 | |
|         if (Reference.isReference(targetRef))
 | |
|         {
 | |
|             Reference reference = Reference.fromNodeRef(targetRef);
 | |
| 
 | |
|             List<AssociationRef> materialAssocs = new ArrayList<AssociationRef>();
 | |
| 
 | |
|             if (smartStore.canMaterialize(reference))
 | |
|             {
 | |
|                 List<AssociationRef> sourceAssocs = theTrait.getSourceAssocs(smartStore.materialize(reference),
 | |
|                                                                              qnamePattern);
 | |
|                 for (AssociationRef associationRef : sourceAssocs)
 | |
|                 {
 | |
|                     NodeRef sourceRef = associationRef.getSourceRef();
 | |
|                     Reference sourceReference = NodeProtocol.newReference(sourceRef,
 | |
|                                                                           reference
 | |
|                                                                                       .execute(new GetParentReferenceMethod()));
 | |
|                     AssociationRef virtualAssocRef = new AssociationRef(associationRef.getId(),
 | |
|                                                                         sourceReference.toNodeRef(),
 | |
|                                                                         associationRef.getTypeQName(),
 | |
|                                                                         targetRef);
 | |
|                     materialAssocs.add(virtualAssocRef);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // Download sources are deliberately not virtualized due to
 | |
|             // performance and complexity issues.
 | |
|             // However they could be detected using
 | |
|             // if (qnamePattern.isMatch(DownloadModel.ASSOC_REQUESTED_NODES))
 | |
| 
 | |
|             return materialAssocs;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return theTrait.getSourceAssocs(targetRef,
 | |
|                                             qnamePattern);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public ChildAssociationRef moveNode(NodeRef nodeToMoveRef, NodeRef newParentRef, QName assocTypeQName,
 | |
|                 QName assocQName)
 | |
|     {
 | |
|         if (Reference.isReference(nodeToMoveRef) || Reference.isReference(newParentRef))
 | |
|         {
 | |
|             throw new UnsupportedOperationException("Unsuported operation for virtual source or destination");
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return getTrait().moveNode(nodeToMoveRef,
 | |
|                                        newParentRef,
 | |
|                                        assocTypeQName,
 | |
|                                        assocQName);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void addProperties(NodeRef nodeRef, Map<QName, Serializable> properties)
 | |
|     {
 | |
|         if (Reference.isReference(nodeRef))
 | |
|         {
 | |
|             Reference reference = Reference.fromNodeRef(nodeRef);
 | |
|             NodeRef actualNodeRef = reference.execute(new GetActualNodeRefMethod(null));
 | |
| 
 | |
|             getTrait().addProperties(actualNodeRef,
 | |
|                                      properties);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             getTrait().addProperties(nodeRef,
 | |
|                                      properties);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public AssociationRef createAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName)
 | |
|     {
 | |
|         if (Reference.isReference(targetRef)
 | |
|                     && getTrait().getType(materializeIfPossible(sourceRef)).equals(DownloadModel.TYPE_DOWNLOAD))
 | |
|         {
 | |
|             // NOTE : this is enables downloads of virtual structures
 | |
|             createDownloadAssociation(sourceRef,
 | |
|                                       targetRef);
 | |
| 
 | |
|             AssociationRef assocRef = new AssociationRef(sourceRef,
 | |
|                                                          assocTypeQName,
 | |
|                                                          targetRef);
 | |
|             return assocRef;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return getTrait().createAssociation(materializeIfPossible(sourceRef),
 | |
|                                                 materializeIfPossible(targetRef),
 | |
|                                                 assocTypeQName);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private List<NodeRef> materializeIfPossible(Collection<NodeRef> nodeRefs)
 | |
|     {
 | |
|         List<NodeRef> nodeRefList = new LinkedList<>();
 | |
|         for (NodeRef nodeRef : nodeRefs)
 | |
|         {
 | |
|             nodeRefList.add(materializeIfPossible(nodeRef));
 | |
|         }
 | |
| 
 | |
|         return nodeRefList;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @deprecated use {@link VirtualStore#materializeIfPossible(NodeRef)}
 | |
|      *             instead
 | |
|      */
 | |
|     private NodeRef materializeIfPossible(NodeRef nodeRef)
 | |
|     {
 | |
|         if (Reference.isReference(nodeRef))
 | |
|         {
 | |
|             Reference ref = Reference.fromNodeRef(nodeRef);
 | |
|             if (smartStore.canMaterialize(ref))
 | |
|             {
 | |
|                 return smartStore.materialize(ref);
 | |
|             }
 | |
| 
 | |
|         }
 | |
|         return nodeRef;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<StoreRef> getStores()
 | |
|     {
 | |
|         return getTrait().getStores();
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public StoreRef createStore(String protocol, String identifier) throws StoreExistsException
 | |
|     {
 | |
|         return getTrait().createStore(protocol,
 | |
|                                       identifier);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void deleteStore(StoreRef storeRef)
 | |
|     {
 | |
|         getTrait().deleteStore(storeRef);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean exists(StoreRef storeRef)
 | |
|     {
 | |
|         return getTrait().exists(storeRef);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public Status getNodeStatus(NodeRef nodeRef)
 | |
|     {
 | |
|         return getTrait().getNodeStatus(materializeIfPossible(nodeRef));
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public NodeRef getNodeRef(Long nodeId)
 | |
|     {
 | |
|         return getTrait().getNodeRef(nodeId);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public NodeRef getRootNode(StoreRef storeRef) throws InvalidStoreRefException
 | |
|     {
 | |
|         return getTrait().getRootNode(storeRef);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public Set<NodeRef> getAllRootNodes(StoreRef storeRef)
 | |
|     {
 | |
|         return getTrait().getAllRootNodes(storeRef);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void setChildAssociationIndex(ChildAssociationRef childAssocRef, int index)
 | |
|                 throws InvalidChildAssociationRefException
 | |
|     {
 | |
|         getTrait().setChildAssociationIndex(childAssocRef,
 | |
|                                             index);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void setType(NodeRef nodeRef, QName typeQName) throws InvalidNodeRefException
 | |
|     {
 | |
|         getTrait().setType(materializeIfPossible(nodeRef),
 | |
|                            typeQName);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void addAspect(NodeRef nodeRef, QName aspectTypeQName, Map<QName, Serializable> aspectProperties)
 | |
|                 throws InvalidNodeRefException, InvalidAspectException
 | |
|     {
 | |
|         getTrait().addAspect(materializeIfPossible(nodeRef),
 | |
|                              aspectTypeQName,
 | |
|                              aspectProperties);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void removeAspect(NodeRef nodeRef, QName aspectTypeQName)
 | |
|                 throws InvalidNodeRefException, InvalidAspectException
 | |
|     {
 | |
|         getTrait().removeAspect(materializeIfPossible(nodeRef),
 | |
|                                 aspectTypeQName);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void deleteNode(NodeRef nodeRef) throws InvalidNodeRefException
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
|         NodeRef materialNode = smartStore.materializeIfPossible(nodeRef);
 | |
|         boolean isDownload = DownloadModel.TYPE_DOWNLOAD.equals(theTrait.getType(materialNode));
 | |
|         theTrait.deleteNode(materialNode);
 | |
|         if (isDownload)
 | |
|         {
 | |
|             cleanUpDownloadTargetAssocs(nodeRef);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public ChildAssociationRef addChild(NodeRef parentRef, NodeRef childRef, QName assocTypeQName, QName qname)
 | |
|                 throws InvalidNodeRefException
 | |
|     {
 | |
|         return getTrait().addChild(materializeIfPossible(parentRef),
 | |
|                                    materializeIfPossible(childRef),
 | |
|                                    assocTypeQName,
 | |
|                                    qname);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<ChildAssociationRef> addChild(Collection<NodeRef> parentRefs, NodeRef childRef, QName assocTypeQName,
 | |
|                 QName qname) throws InvalidNodeRefException
 | |
|     {
 | |
|         return getTrait().addChild(materializeIfPossible(parentRefs),
 | |
|                                    materializeIfPossible(childRef),
 | |
|                                    assocTypeQName,
 | |
|                                    qname);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void removeChild(NodeRef parentRef, NodeRef childRef) throws InvalidNodeRefException
 | |
|     {
 | |
|         getTrait().removeChild(materializeIfPossible(parentRef),
 | |
|                                materializeIfPossible(childRef));
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean removeChildAssociation(ChildAssociationRef childAssocRef)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
| 
 | |
|         NodeRef childRef = childAssocRef.getChildRef();
 | |
|         if (Reference.isReference(childRef))
 | |
|         {
 | |
|             List<ChildAssociationRef> assocsToRemove = revertVirtualAssociation(childAssocRef,
 | |
|                                                                                 theTrait,
 | |
|                                                                                 childRef);
 | |
|             boolean removed = false;
 | |
|             if (!assocsToRemove.isEmpty())
 | |
|             {
 | |
|                 for (ChildAssociationRef assoc : assocsToRemove)
 | |
|                 {
 | |
|                     removed = removed || theTrait.removeChildAssociation(assoc);
 | |
|                 }
 | |
|             }
 | |
|             return removed;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return theTrait.removeChildAssociation(childAssocRef);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private List<ChildAssociationRef> revertVirtualAssociation(ChildAssociationRef childAssocRef,
 | |
|                 NodeServiceTrait theTrait, NodeRef childRef)
 | |
|     {
 | |
|         childRef = smartStore.materialize(Reference.fromNodeRef(childRef));
 | |
|         ChildAssociationRef parent = theTrait.getPrimaryParent(childRef);
 | |
|         final QName assocName = childAssocRef.getQName();
 | |
|         List<ChildAssociationRef> assocsToRemove = theTrait.getChildAssocs(parent.getParentRef(),
 | |
|                                                                            childAssocRef.getTypeQName(),
 | |
|                                                                            new QNamePattern()
 | |
|                                                                            {
 | |
| 
 | |
|                                                                                @Override
 | |
|                                                                                public boolean isMatch(QName qname)
 | |
|                                                                                {
 | |
|                                                                                    return assocName
 | |
|                                                                                                .getLocalName()
 | |
|                                                                                                    .equals(qname
 | |
|                                                                                                                .getLocalName());
 | |
|                                                                                }
 | |
|                                                                            });
 | |
|         return assocsToRemove;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean removeSeconaryChildAssociation(ChildAssociationRef childAssocRef)
 | |
|     {
 | |
| 
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
| 
 | |
|         NodeRef childRef = childAssocRef.getChildRef();
 | |
|         if (Reference.isReference(childRef))
 | |
|         {
 | |
|             List<ChildAssociationRef> assocsToRemove = revertVirtualAssociation(childAssocRef,
 | |
|                                                                                 theTrait,
 | |
|                                                                                 childRef);
 | |
|             boolean removed = false;
 | |
|             if (!assocsToRemove.isEmpty())
 | |
|             {
 | |
|                 for (ChildAssociationRef assoc : assocsToRemove)
 | |
|                 {
 | |
|                     removed = removed || theTrait.removeSeconaryChildAssociation(assoc);
 | |
|                 }
 | |
|             }
 | |
|             return removed;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return theTrait.removeSeconaryChildAssociation(childAssocRef);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean removeSecondaryChildAssociation(ChildAssociationRef childAssocRef)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
| 
 | |
|         NodeRef childRef = childAssocRef.getChildRef();
 | |
|         if (Reference.isReference(childRef))
 | |
|         {
 | |
|             List<ChildAssociationRef> assocsToRemove = revertVirtualAssociation(childAssocRef,
 | |
|                                                                                 theTrait,
 | |
|                                                                                 childRef);
 | |
|             boolean removed = false;
 | |
|             if (!assocsToRemove.isEmpty())
 | |
|             {
 | |
|                 for (ChildAssociationRef assoc : assocsToRemove)
 | |
|                 {
 | |
|                     removed = removed || theTrait.removeSecondaryChildAssociation(assoc);
 | |
|                 }
 | |
|             }
 | |
|             return removed;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return theTrait.removeSecondaryChildAssociation(childAssocRef);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public Long getNodeAclId(NodeRef nodeRef) throws InvalidNodeRefException
 | |
|     {
 | |
|         return getTrait().getNodeAclId(materializeIfPossible(nodeRef));
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void setProperties(NodeRef nodeRef, Map<QName, Serializable> properties) throws InvalidNodeRefException
 | |
|     {
 | |
|         getTrait().setProperties(materializeIfPossible(nodeRef),
 | |
|                                  properties);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void setProperty(NodeRef nodeRef, QName qname, Serializable value) throws InvalidNodeRefException
 | |
|     {
 | |
|         getTrait().setProperty(materializeIfPossible(nodeRef),
 | |
|                                qname,
 | |
|                                value);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void removeProperty(NodeRef nodeRef, QName qname) throws InvalidNodeRefException
 | |
|     {
 | |
|         getTrait().removeProperty(materializeIfPossible(nodeRef),
 | |
|                                   qname);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<ChildAssociationRef> getChildrenByName(NodeRef nodeRef, QName assocTypeQName,
 | |
|                 Collection<String> childNames)
 | |
|     {
 | |
|         return getTrait().getChildrenByName(materializeIfPossible(nodeRef),
 | |
|                                             assocTypeQName,
 | |
|                                             childNames);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public Collection<ChildAssociationRef> getChildAssocsWithoutParentAssocsOfType(NodeRef nodeRef,
 | |
|                 QName assocTypeQName)
 | |
|     {
 | |
|         NodeServiceTrait theTrait = getTrait();
 | |
|         boolean canVirtualize = canVirtualizeAssocNodeRef(nodeRef);
 | |
|         if (canVirtualize)
 | |
|         {
 | |
|             Reference reference = smartStore.virtualize(nodeRef);
 | |
|             Collection<ChildAssociationRef> virtualAssociations = smartStore
 | |
|                         .getChildAssocsWithoutParentAssocsOfType(reference,
 | |
|                                                                  assocTypeQName);
 | |
|             List<ChildAssociationRef> associations = new LinkedList<>(virtualAssociations);
 | |
|             if (smartStore.canMaterialize(reference))
 | |
|             {
 | |
|                 NodeRef materialReference = smartStore.materialize(reference);
 | |
|                 Collection<ChildAssociationRef> actualAssociations = theTrait
 | |
|                             .getChildAssocsWithoutParentAssocsOfType(materialReference,
 | |
|                                                                      assocTypeQName);
 | |
|                 associations.addAll(actualAssociations);
 | |
|             }
 | |
| 
 | |
|             return associations;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return theTrait.getChildAssocsWithoutParentAssocsOfType(nodeRef,
 | |
|                                                                     assocTypeQName);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName)
 | |
|                 throws InvalidNodeRefException
 | |
|     {
 | |
|         getTrait().removeAssociation(materializeIfPossible(sourceRef),
 | |
|                                      materializeIfPossible(targetRef),
 | |
|                                      assocTypeQName);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void setAssociations(NodeRef sourceRef, QName assocTypeQName, List<NodeRef> targetRefs)
 | |
|     {
 | |
|         getTrait().setAssociations(materializeIfPossible(sourceRef),
 | |
|                                    assocTypeQName,
 | |
|                                    materializeIfPossible(targetRefs));
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public AssociationRef getAssoc(Long id)
 | |
|     {
 | |
|         return getTrait().getAssoc(id);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public NodeRef getStoreArchiveNode(StoreRef storeRef)
 | |
|     {
 | |
|         return getTrait().getStoreArchiveNode(storeRef);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public NodeRef restoreNode(NodeRef archivedNodeRef, NodeRef destinationParentNodeRef, QName assocTypeQName,
 | |
|                 QName assocQName)
 | |
|     {
 | |
|         return getTrait().restoreNode(materializeIfPossible(archivedNodeRef),
 | |
|                                       materializeIfPossible(destinationParentNodeRef),
 | |
|                                       assocTypeQName,
 | |
|                                       assocQName);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<NodeRef> findNodes(FindNodeParameters params)
 | |
|     {
 | |
|         return getTrait().findNodes(params);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public int countChildAssocs(NodeRef nodeRef, boolean isPrimary) throws InvalidNodeRefException
 | |
|     {
 | |
|         return getTrait().countChildAssocs(nodeRef,
 | |
|                                            isPrimary);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<AssociationRef> getTargetAssocsByPropertyValue(NodeRef sourceRef, QNamePattern qnamePattern,
 | |
|                 QName propertyQName, Serializable propertyValue)
 | |
|     {
 | |
|         return getTrait().getTargetAssocsByPropertyValue(sourceRef,
 | |
|                                                          qnamePattern,
 | |
|                                                          propertyQName,
 | |
|                                                          propertyValue);
 | |
|     }
 | |
| 
 | |
| }
 |