001/**
002 * Copyright 2005-2017 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.kew.engine.node;
017
018import org.kuali.rice.core.api.reflect.ObjectDefinition;
019import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
020import org.kuali.rice.core.api.util.ClassLoaderUtils;
021import org.kuali.rice.kew.api.exception.ResourceUnavailableException;
022
023import java.util.ArrayList;
024import java.util.Collections;
025import java.util.Comparator;
026import java.util.Iterator;
027import java.util.List;
028
029
030/**
031 * A typesafe enumeration defining the various types of Nodes in the Workflow Engine.
032 * This class was added to aid in unifying the node type concept across multiple
033 * components within the system.  It also defines type hierarchys for the various
034 * node types.
035 *
036 * @author Kuali Rice Team (rice.collab@kuali.org)
037 */
038public class NodeType {
039
040    private static final String SIMPLE_NAME = "simple";
041    private static final String JOIN_NAME = "join";
042    private static final String SPLIT_NAME = "split";
043    private static final String SUB_PROCESS_NAME = "process";
044    private static final String DYNAMIC_NAME = "dynamic";
045    private static final String START_NAME = "start";
046    private static final String REQUEST_ACTIVATION_NAME = "requestActivation";
047    private static final String REQUESTS_NAME = "requests";
048    private static final String ROLE_NAME = "role";
049
050    /**
051     * A Sorted List containing the NodeTypes in order sorted by largest extension depth first, i.e. in bottom-up extension order.
052     */
053    private static final List typeList = new ArrayList();
054    private static final Comparator depthComparator = new ExtensionDepthComparator();
055
056
057    // primitive node types
058    public static final NodeType SIMPLE = new NodeType(SIMPLE_NAME, SimpleNode.class, null);
059    public static final NodeType SPLIT = new NodeType(SPLIT_NAME, SplitNode.class, SimpleSplitNode.class);
060    public static final NodeType JOIN = new NodeType(JOIN_NAME, JoinNode.class, SimpleJoinNode.class);
061    public static final NodeType SUB_PROCESS = new NodeType(SUB_PROCESS_NAME, SubProcessNode.class, SimpleSubProcessNode.class);
062    public static final NodeType DYNAMIC = new NodeType(DYNAMIC_NAME, DynamicNode.class, null);
063
064    // derivative node types
065    public static final NodeType REQUEST_ACTIVATION = new NodeType(SIMPLE, REQUEST_ACTIVATION_NAME, RequestActivationNode.class, RequestActivationNode.class);
066    public static final NodeType START = new NodeType(REQUEST_ACTIVATION, START_NAME, InitialNode.class, InitialNode.class);
067    public static final NodeType REQUESTS = new NodeType(REQUEST_ACTIVATION, REQUESTS_NAME, RequestsNode.class, RequestsNode.class);
068    public static final NodeType ROLE = new NodeType(REQUESTS, ROLE_NAME, RoleNode.class, RoleNode.class);
069
070    private NodeType extensionBase;
071    private String name;
072    private Class baseClass;
073    private Class defaultClass;
074    private int extensionDepth = 0;
075
076    private NodeType(String name, Class baseClass, Class defaultClass) {
077        this(null, name, baseClass, defaultClass);
078    }
079
080    private NodeType(NodeType extensionBase, String name, Class baseClass, Class defaultClass) {
081        this.extensionBase = extensionBase;
082        this.name = name;
083        this.baseClass = baseClass;
084        this.defaultClass = defaultClass;
085        while (extensionBase != null) {
086            extensionDepth++;
087            extensionBase = extensionBase.getExtensionBase();
088        }
089        typeList.add(this);
090        // keep the list sorted
091        Collections.sort(typeList, depthComparator);
092    }
093
094    public NodeType getExtensionBase() {
095        return extensionBase;
096    }
097
098    public Class getBaseClass() {
099        return baseClass;
100    }
101
102    public Class getDefaultClass() {
103        return defaultClass;
104    }
105
106    public String getName() {
107        return name;
108    }
109
110    public int getExtensionDepth() {
111        return extensionDepth;
112    }
113
114    public boolean isAssignableFrom(Class typeClass) {
115        return getBaseClass().isAssignableFrom(typeClass);
116    }
117
118    public boolean isAssignableFrom(NodeType type) {
119        return getBaseClass().isAssignableFrom(type.getBaseClass());
120    }
121
122    public boolean isInstanceOf(Object object) {
123        return ClassLoaderUtils.isInstanceOf(object, getBaseClass());
124    }
125
126    public boolean isTypeOf(Class typeClass) {
127        return typeClass.isAssignableFrom(getBaseClass());
128    }
129
130    public boolean isTypeOf(NodeType type) {
131        return type.getBaseClass().isAssignableFrom(getBaseClass());
132    }
133
134    public boolean isCustomNode(String className) {
135        return getDefaultClass() == null || !getDefaultClass().getName().equals(className);
136    }
137
138    public boolean equals(Object object) {
139        if (object instanceof NodeType) {
140            return ((NodeType)object).name.equals(name);
141        }
142        return false;
143    }
144
145    public int hashCode() {
146        return name.hashCode();
147    }
148
149    public static NodeType fromClassName(String className) throws ResourceUnavailableException {
150        //Class typeClass = SpringServiceLocator.getExtensionService().loadClass(className);
151        Object typeObject = GlobalResourceLoader.getResourceLoader().getObject(new ObjectDefinition(className));
152        if (typeObject == null) {
153                throw new ResourceUnavailableException("Could not locate the node with the given class name '" + className + "'.");
154        }
155        //Class typeClass = typeObject.getClass();
156        // depends upon the proper sorting of typeList
157        for (Iterator iterator = typeList.iterator(); iterator.hasNext();) {
158            NodeType type = (NodeType) iterator.next();
159            //if (type.isAssignableFrom(typeClass)) {
160            //if (ClassLoaderUtils.isInstanceOf(typeObject, type))
161            if (type.isInstanceOf(typeObject)) {
162                return type;
163            }
164        }
165        return null;
166    }
167
168    public static NodeType fromNode(RouteNode node) throws ResourceUnavailableException {
169        return fromClassName(node.getNodeType());
170    }
171
172    public static NodeType fromNodeInstance(RouteNodeInstance nodeInstance) throws ResourceUnavailableException {
173        return fromNode(nodeInstance.getRouteNode());
174    }
175
176    /**
177     * Sorts in descending extension-depth order.
178     */
179    private static class ExtensionDepthComparator implements Comparator {
180
181        public int compare(Object object1, Object object2) {
182            NodeType type1 = (NodeType)object1;
183            NodeType type2 = (NodeType)object2;
184            if (type1.getExtensionDepth() > type2.getExtensionDepth()) {
185                return -1;
186            } else if (type1.getExtensionDepth() < type2.getExtensionDepth()) {
187                return 1;
188            }
189            return 0;
190        }
191
192    }
193
194    public static List<NodeType> getTypeList(){
195        return typeList;
196    }
197
198}