com.sirma.itt.cmf.integration.workflow.TransientNode.java Source code

Java tutorial

Introduction

Here is the source code for com.sirma.itt.cmf.integration.workflow.TransientNode.java

Source

/*
 * 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 <http://www.gnu.org/licenses/>.
 */
package com.sirma.itt.cmf.integration.workflow;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ClassDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.dictionary.TypeDefinition;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID;
import org.alfresco.web.bean.repository.Node;
import org.alfresco.web.bean.repository.QNameNodeMap;
import org.alfresco.web.bean.repository.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Represents a transient node i.e. it is not and will not be present in the
 * repository.
 * <p>
 * This type of node is typically used to drive the property sheet when data
 * collection is required for a type but the node does not need to be stored in
 * the repository. An example use is the workflow, transient nodes are used to
 * collect workitem metadata.
 * </p>
 * 
 * @author gavinc
 */
public class TransientNode extends Node {

    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = 2140554155948154106L;

    /** The Constant logger. */
    private static final Log logger = LogFactory.getLog(TransientNode.class);

    /**
     * Constructor.
     * <p>
     * NOTE: The name is NOT automatically added to the map of properties, if
     * you need the name of this node to be in the map then add it to the map
     * passed in to this constructor.
     * </p>
     * 
     * @param type
     *            The type this node will represent
     * @param name
     *            The name of the node
     * @param data
     *            The properties and associations this node will have
     */
    public TransientNode(QName type, String name, Map<QName, Serializable> data) {
        // create a dummy NodeRef to pass to the constructor
        super(new NodeRef(Repository.getStoreRef(), GUID.generate()));

        this.type = type;
        this.name = name;

        // initialise the node
        initNode(data);
    }

    /**
     * Instantiates a new transient node.
     *
     * @param dictionaryService the dictionary service
     * @param type the type
     * @param name the name
     * @param data the data
     */
    public TransientNode(ServiceRegistry dictionaryService, QName type, String name,
            Map<QName, Serializable> data) {
        // create a dummy NodeRef to pass to the constructor
        super(new NodeRef(Repository.getStoreRef(), GUID.generate()));

        this.type = type;
        this.name = name;
        this.services = dictionaryService;
        // initialise the node
        initNode(data);
    }

    /**
     * Construct a transient node for an item yet to be created in the
     * Repository.
     * 
     * This will apply any one-time initialisation required upon creation of the
     * node e.g. assignment of default values.
     *
     * @param registry the registry
     * @param typeDef The type definition this node will represent
     * @param name The name of the node
     * @param data The properties and associations this node will have
     * @return transient node
     */
    public static TransientNode createNew(ServiceRegistry registry, TypeDefinition typeDef, String name,
            Map<QName, Serializable> data) {
        // build a complete anonymous type for the start task
        List<AspectDefinition> aspects = typeDef.getDefaultAspects();
        List<QName> aspectNames = new ArrayList<QName>(aspects.size());
        getMandatoryAspects(typeDef, aspectNames);
        ClassDefinition startTaskDef = registry.getDictionaryService().getAnonymousType(typeDef.getName(),
                aspectNames);

        // initialise start task values
        Map<QName, Serializable> startValues = new HashMap<QName, Serializable>();
        if (data != null) {
            startValues.putAll(data);
        }

        // apply default values
        Map<QName, PropertyDefinition> propertyDefs = startTaskDef.getProperties();
        for (Map.Entry<QName, PropertyDefinition> entry : propertyDefs.entrySet()) {
            String defaultValue = entry.getValue().getDefaultValue();
            if (defaultValue != null) {
                if (startValues.get(entry.getKey()) == null) {
                    startValues.put(entry.getKey(), (Serializable) DefaultTypeConverter.INSTANCE
                            .convert(entry.getValue().getDataType(), defaultValue));
                }
            }
        }

        return new TransientNode(registry, typeDef.getName(), name, startValues);
    }

    /**
     * Gets a flattened list of all mandatory aspects for a given class.
     *
     * @param classDef the class
     * @param aspects a list to hold the mandatory aspects
     */
    private static void getMandatoryAspects(ClassDefinition classDef, List<QName> aspects) {
        for (AspectDefinition aspect : classDef.getDefaultAspects()) {
            QName aspectName = aspect.getName();
            if (!aspects.contains(aspectName)) {
                aspects.add(aspect.getName());
                getMandatoryAspects(aspect, aspects);
            }
        }
    }

    /**
     * Initialises the node.
     * 
     * @param data
     *            The properties and associations to initialise the node with
     */
    @SuppressWarnings("rawtypes")
    protected void initNode(Map<QName, Serializable> data) {
        // setup the transient node so that the super class methods work
        // and do not need to go back to the repository

        if (logger.isDebugEnabled())
            logger.debug("Initialising transient node with data: " + data);

        DictionaryService ddService = this.getServiceRegistry().getDictionaryService();

        // marshall the given properties and associations into the internal maps
        this.associations = new QNameNodeMap(this, this);
        this.childAssociations = new QNameNodeMap(this, this);

        if (data != null) {
            // go through all data items and allocate to the correct internal
            // list
            for (QName item : data.keySet()) {
                PropertyDefinition propDef = ddService.getProperty(item);
                if (propDef != null) {
                    this.properties.put(item, data.get(item));
                } else {
                    // see if the item is either type of association
                    AssociationDefinition assocDef = ddService.getAssociation(item);
                    if (assocDef != null) {
                        if (assocDef.isChild()) {
                            Object obj = data.get(item);
                            if (obj instanceof NodeRef) {
                                NodeRef child = (NodeRef) obj;

                                // create a child association reference, add it
                                // to a list and add the list
                                // to the list of child associations for this
                                // node
                                List<ChildAssociationRef> assocs = new ArrayList<ChildAssociationRef>(1);
                                ChildAssociationRef childRef = new ChildAssociationRef(assocDef.getName(),
                                        this.nodeRef, null, child);
                                assocs.add(childRef);

                                this.childAssociations.put(item, assocs);
                            } else if (obj instanceof List) {
                                List targets = (List) obj;

                                List<ChildAssociationRef> assocs = new ArrayList<ChildAssociationRef>(
                                        targets.size());

                                for (Object target : targets) {
                                    if (target instanceof NodeRef) {
                                        NodeRef currentChild = (NodeRef) target;
                                        ChildAssociationRef childRef = new ChildAssociationRef(assocDef.getName(),
                                                this.nodeRef, null, currentChild);
                                        assocs.add(childRef);
                                    }
                                }

                                if (assocs.size() > 0) {
                                    this.childAssociations.put(item, assocs);
                                }
                            }
                        } else {
                            Object obj = data.get(item);
                            if (obj instanceof NodeRef) {
                                NodeRef target = (NodeRef) obj;

                                // create a association reference, add it to a
                                // list and add the list
                                // to the list of associations for this node
                                List<AssociationRef> assocs = new ArrayList<AssociationRef>(1);
                                AssociationRef assocRef = new AssociationRef(null, this.nodeRef, assocDef.getName(),
                                        target);
                                assocs.add(assocRef);

                                this.associations.put(item, assocs);
                            } else if (obj instanceof List) {
                                List targets = (List) obj;

                                List<AssociationRef> assocs = new ArrayList<AssociationRef>(targets.size());

                                for (Object target : targets) {
                                    if (target instanceof NodeRef) {
                                        NodeRef currentTarget = (NodeRef) target;
                                        AssociationRef assocRef = new AssociationRef(null, this.nodeRef,
                                                assocDef.getName(), currentTarget);
                                        assocs.add(assocRef);
                                    }
                                }

                                if (assocs.size() > 0) {
                                    this.associations.put(item, assocs);
                                }
                            }
                        }
                    }
                }
            }
        }

        // show that the maps have been initialised
        this.propsRetrieved = true;
        this.assocsRetrieved = true;
        this.childAssocsRetrieved = true;

        // setup the list of aspects the node would have
        TypeDefinition typeDef = ddService.getType(this.type);
        if (typeDef == null) {
            throw new AlfrescoRuntimeException("Failed to find type definition: " + this.type);
        }

        // get flat list of all aspects for the type
        List<QName> defaultAspects = new ArrayList<QName>(16);
        getMandatoryAspects(typeDef, defaultAspects);

        this.aspects = new HashSet<QName>(defaultAspects);

        // setup remaining variables
        this.path = null;
        this.locked = Boolean.FALSE;
        this.workingCopyOwner = Boolean.FALSE;
    }

    /* (non-Javadoc)
     * @see org.alfresco.web.bean.repository.Node#hasPermission(java.lang.String)
     */
    /**
     * Checks for permission.
     *
     * @param permission the permission
     * @return true, if successful
     */
    @Override
    public boolean hasPermission(String permission) {
        return true;
    }

    /* (non-Javadoc)
     * @see org.alfresco.web.bean.repository.Node#reset()
     */
    /**
     * Reset.
     */
    @Override
    public void reset() {
        // don't reset anything otherwise we'll lose our data
        // with no way of getting it back!!
    }

    /* (non-Javadoc)
     * @see org.alfresco.web.bean.repository.Node#toString()
     */
    /**
     * To string.
     *
     * @return the string
     */
    @Override
    public String toString() {
        return "Transient node of type: " + getType() + "\nProperties: " + this.getProperties().toString();
    }
}