001    /*
002     * Copyright 2005-2007 The Kuali Foundation
003     * 
004     * 
005     * Licensed under the Educational Community License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     * 
009     * http://www.opensource.org/licenses/ecl2.php
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.kuali.rice.kew.engine.node;
018    
019    import java.util.Iterator;
020    import java.util.List;
021    
022    import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
023    
024    
025    /**
026     * Logs {@link RouteNodeInstance} graphs in a format which is indented and easy to read. 
027     *
028     * @author Kuali Rice Team (rice.collab@kuali.org)
029     */
030    public class NodeJotter {
031    
032        private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(NodeJotter.class);
033        private static final String INDENT = "   ";
034    
035        public static void jotNodeInstance(DocumentRouteHeaderValue document, RouteNodeInstance nodeInstance) {
036            try {
037                if (LOG.isDebugEnabled()) {
038                    List initialNodeInstances = document.getInitialRouteNodeInstances();
039                    for (Iterator iterator = initialNodeInstances.iterator(); iterator.hasNext();) {
040                        RouteNodeInstance initialNodeInstance = (RouteNodeInstance) iterator.next();
041                        NodeType nodeType = NodeType.fromNodeInstance(initialNodeInstance);
042                        LOG.debug(orchestrateOutput(initialNodeInstance, nodeType, null, 0));
043                    }
044                } else if (LOG.isInfoEnabled()) {
045                    NodeType nodeType = NodeType.fromNodeInstance(nodeInstance);
046                    LOG.info(outputNodeInstanceToLog(nodeInstance, nodeType, 0));
047                }
048            } catch (Throwable t) {
049                LOG.warn("Caught error attempting to jot node instance" + nodeInstance);
050            }
051        }
052    
053        private static String orchestrateOutput(RouteNodeInstance nodeInstance, NodeType nodeType, SplitJoinContext sjCtx, int indentDepth) throws Exception {
054            String output = "";
055            boolean isSplit = NodeType.SPLIT.equals(nodeType);
056            boolean isJoin = NodeType.JOIN.equals(nodeType);
057            if (isJoin && sjCtx != null) {
058                sjCtx.joinNodeInstance = nodeInstance;
059                return output;
060            }
061            SplitJoinContext newSplitJoinContext = null;
062            if (isSplit) {
063                newSplitJoinContext = new SplitJoinContext(nodeInstance);
064            }
065            output += outputNodeInstanceToLog(nodeInstance, nodeType, indentDepth);
066            for (Iterator iterator = nodeInstance.getNextNodeInstances().iterator(); iterator.hasNext();) {
067                RouteNodeInstance nextNodeInstance = (RouteNodeInstance) iterator.next();
068                nodeType = NodeType.fromNodeInstance(nextNodeInstance);
069                if (newSplitJoinContext != null) {
070                    output += orchestrateOutput(nextNodeInstance, nodeType, newSplitJoinContext, indentDepth + 1);
071                } else {
072                    output += orchestrateOutput(nextNodeInstance, nodeType, sjCtx, indentDepth + 1);
073                }
074            }
075            if (isSplit) {
076                if (newSplitJoinContext != null && newSplitJoinContext.joinNodeInstance != null) {
077                    nodeType = NodeType.fromNodeInstance(newSplitJoinContext.joinNodeInstance);
078                    output += orchestrateOutput(newSplitJoinContext.joinNodeInstance, nodeType, sjCtx, indentDepth);
079                }
080            }
081            return output;
082        }
083    
084        private static String outputNodeInstanceToLog(RouteNodeInstance nodeInstance, NodeType nodeType, int indentDepth) throws Exception {
085            String memAddress = nodeInstance.toString().split("@")[1];
086            String dataIndent = getIndent(indentDepth + 1);
087            String output = getIndent(indentDepth) + "[NODE type=" + nodeType.getName() + "]\n" + dataIndent + "Name: " + nodeInstance.getName() + "(" + memAddress + ")\n";
088            output += dataIndent + "State: ";
089            for (Iterator iterator = nodeInstance.getState().iterator(); iterator.hasNext();) {
090                NodeState nodeState = (NodeState) iterator.next();
091                output += nodeState.getKey() + "=" + nodeState.getValue();
092                if (iterator.hasNext()) {
093                    output += ",";
094                }
095            }
096            output += "\n" + dataIndent + "Status Flags: initial=" + nodeInstance.isInitial() + ", active=" + nodeInstance.isActive() + ", complete=" + nodeInstance.isComplete();
097            output += (nodeInstance.getProcess() == null ? "" : "\n" + dataIndent + "Process Name: " + nodeInstance.getProcess().getName());
098            output += "\n";
099            return output;
100        }
101    
102        private static String getIndent(int indentDepth) {
103            StringBuffer buffer = new StringBuffer();
104            for (int depth = 0; depth < indentDepth; depth++) {
105                buffer.append(INDENT);
106            }
107            return buffer.toString();
108        }
109    
110        private static class SplitJoinContext {
111            public RouteNodeInstance splitNodeInstance;
112            public RouteNodeInstance joinNodeInstance;
113    
114            public SplitJoinContext(RouteNodeInstance splitNodeInstance) {
115                this.splitNodeInstance = splitNodeInstance;
116            }
117        }
118    
119    }