/* * Copyright (C) 2005-2010 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 . */ package org.alfresco.repo.rendition; import java.io.Serializable; import java.util.List; import org.alfresco.model.ContentModel; import org.alfresco.model.RenditionModel; import org.alfresco.repo.rendition.executer.AbstractRenderingEngine; import org.alfresco.service.cmr.rendition.RenditionDefinition; import org.alfresco.service.cmr.rendition.RenditionService; import org.alfresco.service.cmr.rendition.RenditionServiceException; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QNamePattern; /** * This class is responsible for placing a rendition node in the correct * location given a temporary rendition, a source node, a rendition location and * optionally an old rendition. This manages the complex logic of deciding * whether to move and old rendition or orphan it and create a new one amongst * other things. * * @author Nick Smith * */ public class RenditionNodeManager { private final NodeRef sourceNode; private final NodeRef oldRendition; private final RenditionDefinition renditionDefinition; private final RenditionLocation location; private final NodeService nodeService; public RenditionNodeManager(NodeRef sourceNode, NodeRef oldRendition, RenditionLocation location, RenditionDefinition renditionDefinition, NodeService nodeService) { this.sourceNode = sourceNode; this.oldRendition = oldRendition; this.location = location; this.renditionDefinition = renditionDefinition; this.nodeService = nodeService; } /** * This method returns the {@link ChildAssociationRef} for the rendition node. In doing this * it may reuse an existing rendition node, move an existing rendition node or create a new rendition node * as appropriate. * * @return the {@link ChildAssociationRef} of the rendition node. */ public ChildAssociationRef findOrCreateRenditionNode() { QName renditionName = renditionDefinition.getRenditionName(); // If no rendition already exists create a new rendition node and // association. if (oldRendition == null) { return getSpecifiedRenditionOrCreateNewRendition(renditionName); } // If a rendition exists and is already in the correct location then // return that renditions primary parent association if (renditionLocationMatches()) { return nodeService.getPrimaryParent(oldRendition); } // If the old rendition is in the wrong location and the 'orphan // existing rendition' param is set to true or the RenditionLocation // specifies a destination NodeRef then delete the old // rendition association and create a new rendition node. if (orphanExistingRendition()) { orphanRendition( renditionName); return getSpecifiedRenditionOrCreateNewRendition(renditionName); } // If the old rendition is in the wrong place and the 'orphan existing // rendition' param is not set to true then move the existing rendition // to the correct location. return moveRendition(renditionName); } private ChildAssociationRef moveRendition(QName associationName) { NodeRef parent = location.getParentRef(); QName assocType = sourceNode.equals(parent) ? RenditionModel.ASSOC_RENDITION : ContentModel.ASSOC_CONTAINS; return nodeService.moveNode(oldRendition, parent, assocType, associationName); } private void orphanRendition(QNamePattern renditionName) { List parents = nodeService.getParentAssocs(oldRendition, RenditionModel.ASSOC_RENDITION, renditionName); if(parents.size() ==1) { ChildAssociationRef parentAssoc = parents.get(0); if(parentAssoc.getParentRef().equals(sourceNode)) { nodeService.removeAspect(oldRendition, RenditionModel.ASPECT_HIDDEN_RENDITION); nodeService.removeAspect(oldRendition, RenditionModel.ASPECT_VISIBLE_RENDITION); nodeService.removeChildAssociation(parentAssoc); return; } } String msg = "Node: " + oldRendition + " is not a rendition of type: " + renditionName + " for source node: " + sourceNode; throw new RenditionServiceException(msg); } private boolean orphanExistingRendition() { if (location.getChildRef() != null) return true; else return AbstractRenderingEngine.getParamWithDefault(RenditionService.PARAM_ORPHAN_EXISTING_RENDITION, Boolean.FALSE, renditionDefinition); } private boolean renditionLocationMatches() { NodeRef destination = location.getChildRef(); if (destination != null) { return destination.equals(oldRendition); } ChildAssociationRef oldParentAssoc = nodeService.getPrimaryParent(oldRendition); NodeRef oldParent = oldParentAssoc.getParentRef(); if (oldParent.equals(location.getParentRef())) { String childName = location.getChildName(); if (childName == null) return true; else { Serializable oldName = nodeService.getProperty(oldRendition, ContentModel.PROP_NAME); return childName.equals(oldName); } } return false; } private ChildAssociationRef getSpecifiedRenditionOrCreateNewRendition(QName renditionName) { NodeRef destination = location.getChildRef(); if (destination != null) return nodeService.getPrimaryParent(destination); else return createNewRendition(renditionName); } private ChildAssociationRef createNewRendition(QName renditionName) { NodeRef parentRef = location.getParentRef(); boolean parentIsSource = parentRef.equals(sourceNode); QName renditionType = RenditionModel.ASSOC_RENDITION; QName assocTypeQName = parentIsSource ? renditionType : ContentModel.ASSOC_CONTAINS; QName nodeTypeQName = ContentModel.TYPE_CONTENT; ChildAssociationRef primaryAssoc = nodeService.createNode(parentRef, assocTypeQName, renditionName, nodeTypeQName); // If the new rendition is not directly under the source node then add // the rendition association. if (parentIsSource == false) { NodeRef rendition = primaryAssoc.getChildRef(); nodeService.addChild(sourceNode, rendition, renditionType, renditionName); } return primaryAssoc; } }