package fr.acxio.tools.agia.alfresco.configuration; /* * Copyright 2014 Acxio * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.util.Date; import java.util.Iterator; import java.util.List; import javax.xml.namespace.NamespaceContext; import org.alfresco.webservice.util.Constants; import org.alfresco.webservice.util.ISO9075; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.support.ManagedList; import org.springframework.expression.EvaluationContext; import org.springframework.util.Assert; import fr.acxio.tools.agia.alfresco.domain.Aspect; import fr.acxio.tools.agia.alfresco.domain.Document; import fr.acxio.tools.agia.alfresco.domain.Folder; import fr.acxio.tools.agia.alfresco.domain.Node; import fr.acxio.tools.agia.alfresco.domain.NodeList; import fr.acxio.tools.agia.alfresco.domain.Property; import fr.acxio.tools.agia.alfresco.domain.QName; import fr.acxio.tools.agia.alfresco.domain.QueryAssociation; import fr.acxio.tools.agia.alfresco.domain.RefAssociation; import fr.acxio.tools.agia.convert.ConversionException; import fr.acxio.tools.agia.convert.FormatConverter; import fr.acxio.tools.agia.expression.DataExpressionResolver; import fr.acxio.tools.agia.expression.StandardDataExpressionResolver; /** * <p> * Simple implementation of * {@link fr.acxio.tools.agia.alfresco.configuration.NodeFactory NodeFactory} . * </p> * <p> * The expressions than can be used in the template tree are delimited by @{ and * }. * </p> * <p> * In an expression, the references to variables are prefixed by #. * </p> * * @author pcollardez * */ public class SimpleNodeFactory implements NodeFactory, InitializingBean { private static final String ALFRESCO_PATH_SPLIT_REGEX = "/"; private DataExpressionResolver expressionResolver = new StandardDataExpressionResolver(); private NodeDefinition nodeDefinition; private NamespaceContext namespaceContext; public void setNodeDefinition(NodeDefinition sNodeDefinition) { nodeDefinition = sNodeDefinition; } public NodeDefinition getNodeDefinition() { return nodeDefinition; } public NamespaceContext getNamespaceContext() { return namespaceContext; } public void setNamespaceContext(NamespaceContext sNamespaceContext) { namespaceContext = sNamespaceContext; } public NodeList getNodes(EvaluationContext sContext) throws ConversionException { Assert.notNull(sContext, "The evaluation context is mandatory."); ManagedList<Node> aResult = new ManagedList<Node>(); if (nodeDefinition instanceof FolderDefinition) { // Regular usecase FolderDefinition aFolderDefinition = (FolderDefinition) nodeDefinition; addFolderNode(aResult, aFolderDefinition, null, sContext); } // TODO : special usecase: document with a path in its name. Folders // should be created as default ones _without_ coyping document // properties. // If the document has no path in its name, then a default // app:company_home is added. return new NodeList(aResult); } public void afterPropertiesSet() { Assert.notNull(nodeDefinition, "The node factory must have a node definition"); } private Folder createFolderNode(String sFolderName, FolderDefinition sFolderDefinition, Node sParentFolder, EvaluationContext sContext) throws ConversionException { Folder aResult = new Folder(); aResult.setAddedTimestamp(new Date()); aResult.setType(getQNameWithDefault(expressionResolver.evaluate(sFolderDefinition.getNodeType(), sContext, String.class), Constants.TYPE_FOLDER, namespaceContext)); aResult.setVersionOperation(mapVersionOperation(expressionResolver.evaluate(sFolderDefinition.getVersionOperation(), sContext, String.class))); if (sFolderDefinition.getAssocTargetId() != null) { aResult.setAssocTargetId(expressionResolver.evaluate(sFolderDefinition.getAssocTargetId(), sContext, String.class)); } addPropertiesToNode(aResult, sFolderDefinition, sContext); addAspectsToNode(aResult, sFolderDefinition, sContext); addAssociationsToNode(aResult, sFolderDefinition, sContext); setName(aResult, sFolderName); aResult.setParent(sParentFolder); aResult.setPathElement(getPathElement(sFolderName, aResult.getType().getPrefix(), namespaceContext)); return aResult; } private boolean evaluateCondition(String sCondition, EvaluationContext sContext) { boolean aResult = true; if ((sCondition != null) && (sCondition.length() > 0) && (sContext != null)) { aResult = expressionResolver.evaluate(sCondition, sContext, Boolean.class); } return aResult; } private Folder addFolderNode(List<Node> sResult, FolderDefinition sFolderDefinition, Node sParentFolder, EvaluationContext sContext) throws ConversionException { Folder aFolder = null; if (evaluateCondition(sFolderDefinition.getCondition(), sContext)) { Node aParentFolder = sParentFolder; // Parse the folder cm:name on path separators. String aPath = getName(sFolderDefinition, sContext); String[] aSubPaths = aPath.split(ALFRESCO_PATH_SPLIT_REGEX); String aFolderName = aSubPaths[aSubPaths.length - 1]; if (aSubPaths.length > 1) { Folder aTmpFolder; for (int i = 0; i < (aSubPaths.length - 1); i++) { if (aSubPaths[i].length() > 0) { aTmpFolder = createFolderNode(aSubPaths[i], sFolderDefinition, aParentFolder, sContext); sResult.add(aTmpFolder); if (aParentFolder != null) { ((Folder) aParentFolder).addFolder(aTmpFolder); } aParentFolder = aTmpFolder; } } } // Then add the current folder aFolder = createFolderNode(aFolderName, sFolderDefinition, aParentFolder, sContext); sResult.add(aFolder); if (aParentFolder != null) { ((Folder) aParentFolder).addFolder(aFolder); } for (FolderDefinition aFolderDef : sFolderDefinition.getFolders()) { addFolderNode(sResult, aFolderDef, aFolder, sContext); } for (DocumentDefinition aDocumentDef : sFolderDefinition.getDocuments()) { aFolder.addDocument(addDocumentNode(sResult, aDocumentDef, aFolder, sContext)); } } return aFolder; } private String getName(NodeDefinition sNodeDefinition, EvaluationContext sContext) { QName aCMName = new QName(Constants.PROP_NAME, namespaceContext); Iterator<PropertyDefinition> aPropertyIterator = sNodeDefinition.getPropertiesDefinitions().iterator(); String aPropertyName = null; String aName = null; PropertyDefinition aProperty; while ((aName == null) && (aPropertyIterator.hasNext())) { aProperty = aPropertyIterator.next(); aPropertyName = expressionResolver.evaluate(aProperty.getLocalName(), sContext, String.class); if ((aCMName.toString().equals(aPropertyName) || aCMName.getShortName().equals(aPropertyName)) && (aProperty.getValues().size() > 0)) { aName = expressionResolver.evaluate(aProperty.getValues().get(0), sContext, String.class); } } return aName; } private void setName(Node sNode, String sName) { sNode.setName(sName); } private void addPropertiesToNode(Node aNode, NodeDefinition sNodeDefinition, EvaluationContext sContext) throws ConversionException { Property aProperty; String aPropertyName = null; String aResolvedValue; List<String> aConvertedValue; for (PropertyDefinition aPropDef : sNodeDefinition.getPropertiesDefinitions()) { aProperty = new Property(); aPropertyName = expressionResolver.evaluate(aPropDef.getLocalName(), sContext, String.class); aProperty.setName(new QName(aPropertyName, namespaceContext)); for (String aValue : aPropDef.getValues()) { aResolvedValue = expressionResolver.evaluate(aValue, sContext, String.class); FormatConverter aConverter = aPropDef.getConverter(); if (aConverter != null) { aConvertedValue = aConverter.convert(aResolvedValue); for (String aNewValue : aConvertedValue) { aProperty.addValue(aNewValue); } } else { aProperty.addValue(aResolvedValue); } } aNode.addProperty(aProperty); } } private void addAspectsToNode(Node sNode, NodeDefinition sNodeDefinition, EvaluationContext sContext) { Aspect aAspect; for (AspectDefinition aAspectDef : sNodeDefinition.getAspectsDefinitions()) { aAspect = new Aspect(); aAspect.setName(new QName(expressionResolver.evaluate(aAspectDef.getName(), sContext, String.class), namespaceContext)); sNode.addAspect(aAspect); } } private void addAssociationsToNode(Node sNode, NodeDefinition sNodeDefinition, EvaluationContext sContext) { for (AssociationDefinition aAssociationDef : sNodeDefinition.getAssociationsDefinitions()) { if (aAssociationDef instanceof RefAssociationDefinition) { RefAssociation aRefAssociation = new RefAssociation(); aRefAssociation.setType(new QName(expressionResolver.evaluate(aAssociationDef.getType(), sContext, String.class), namespaceContext)); aRefAssociation.setReference(expressionResolver.evaluate(((RefAssociationDefinition) aAssociationDef).getTargetRef(), sContext, String.class)); sNode.addAssociation(aRefAssociation); } else if (aAssociationDef instanceof QueryAssociationDefinition) { QueryAssociation aQueryAssociation = new QueryAssociation(); aQueryAssociation.setType(new QName(expressionResolver.evaluate(aAssociationDef.getType(), sContext, String.class), namespaceContext)); aQueryAssociation.setQueryLanguage(expressionResolver.evaluate(((QueryAssociationDefinition) aAssociationDef).getQueryLanguage(), sContext, String.class)); aQueryAssociation.setQuery(expressionResolver.evaluate(((QueryAssociationDefinition) aAssociationDef).getQuery(), sContext, String.class)); sNode.addAssociation(aQueryAssociation); } } } private Document addDocumentNode(List<Node> sResult, DocumentDefinition sDocumentDefinition, Node sParentFolder, EvaluationContext sContext) throws ConversionException { Document aDocument = new Document(); aDocument.setAddedTimestamp(new Date()); sResult.add(aDocument); aDocument.setParent(sParentFolder); aDocument.setType(getQNameWithDefault(expressionResolver.evaluate(sDocumentDefinition.getNodeType(), sContext, String.class), Constants.TYPE_CONTENT, namespaceContext)); aDocument.setVersionOperation(mapVersionOperation(expressionResolver.evaluate(sDocumentDefinition.getVersionOperation(), sContext, String.class))); if (sDocumentDefinition.getAssocTargetId() != null) { aDocument.setAssocTargetId(expressionResolver.evaluate(sDocumentDefinition.getAssocTargetId(), sContext, String.class)); } addPropertiesToNode(aDocument, sDocumentDefinition, sContext); addAspectsToNode(aDocument, sDocumentDefinition, sContext); addAssociationsToNode(aDocument, sDocumentDefinition, sContext); aDocument.setPathElement(getPathElement(aDocument.getName(), aDocument.getType().getPrefix(), namespaceContext)); aDocument.setContentPath(expressionResolver.evaluate(sDocumentDefinition.getContentPath(), sContext, String.class)); aDocument.setEncoding(expressionResolver.evaluate(sDocumentDefinition.getEncoding(), sContext, String.class)); aDocument.setMimeType(expressionResolver.evaluate(sDocumentDefinition.getMimeType(), sContext, String.class)); return aDocument; } private QName getQNameWithDefault(String sValue, String sDefault, NamespaceContext sContext) { return new QName(((sValue == null) || (sValue.length() == 0)) ? sDefault : sValue, sContext); } private String getPathElement(String sName, String sDefaultPrefix, NamespaceContext sContext) { StringBuilder aPathElement = new StringBuilder(); QName aQName = new QName(sName, sContext); aPathElement.append(((aQName.getPrefix() != null) && (aQName.getPrefix().length() > 0)) ? aQName.getPrefix() : sDefaultPrefix); aPathElement.append(":"); aPathElement.append(((aQName.getNamespaceURI() != null) && (aQName.getNamespaceURI().length() > 0)) ? aQName.getLocalName() : ISO9075.encode(aQName .getLocalName())); return aPathElement.toString(); } private Node.VersionOperation mapVersionOperation(String sValue) { return ((sValue == null) || (sValue.length() == 0)) ? Node.VersionOperation.RAISEERROR : ("error".equalsIgnoreCase(sValue) ? Node.VersionOperation.RAISEERROR : ("version".equalsIgnoreCase(sValue) ? Node.VersionOperation.VERSION : ("update".equalsIgnoreCase(sValue) ? Node.VersionOperation.UPDATE : ("replace".equalsIgnoreCase(sValue) ? Node.VersionOperation.REPLACE : Node.VersionOperation.RAISEERROR)))); } }