/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License, version 2 as published by the Free Software * Foundation. * * You should have received a copy of the GNU General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program 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 General Public License for more details. * * * Copyright 2005 - 2008 Pentaho Corporation. All rights reserved. * * @created Jul 18, 2005 * @author James Dixon * */ package org.pentaho.platform.engine.services.actionsequence; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.collections.map.ListOrderedMap; import org.dom4j.Document; import org.dom4j.Node; import org.pentaho.commons.connection.memory.MemoryResultSet; import org.pentaho.platform.api.engine.IActionParameter; import org.pentaho.platform.api.engine.IActionSequence; import org.pentaho.platform.api.engine.IActionSequenceResource; import org.pentaho.platform.api.engine.IApplicationContext; import org.pentaho.platform.api.engine.IConditionalExecution; import org.pentaho.platform.api.engine.ILogger; import org.pentaho.platform.api.engine.ISequenceDefinition; import org.pentaho.platform.api.engine.ISolutionActionDefinition; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.services.messages.Messages; import org.pentaho.platform.util.logging.Logger; import org.pentaho.platform.util.xml.dom4j.XmlDom4JHelper; public class SequenceDefinition implements ISequenceDefinition { private static final boolean debug = PentahoSystem.debug; private int errorCode; private String solutionPath; private String solutionName; private String name; private String version; private String title; private boolean isWebService; private String cacheLevel; private int loggingLevel; private String description; private String author; private String help; private String resultType; private String iconPath; private Map outputDefinitions; private Map inputDefinitions; private Map resourceDefinitions; IApplicationContext applicationContext; ISolutionActionDefinition actionDefinitions[]; public static IActionSequence ActionSequenceFactory(final Document document, final String actionName, final String solutionPath, final String solutionName, final ILogger logger, final IApplicationContext applicationContext, final int loggingLevel) { // Check for a sequence document Node sequenceDefinitionNode = document.selectSingleNode("//action-sequence"); //$NON-NLS-1$ if (sequenceDefinitionNode == null) { logger.error(Messages.getInstance().getErrorString( "SequenceDefinition.ERROR_0002_NO_ACTION_SEQUENCE_NODE", solutionName, solutionPath, actionName)); //$NON-NLS-1$ return null; } ISequenceDefinition seqDef = new SequenceDefinition(sequenceDefinitionNode, actionName, solutionPath, solutionName, logger, applicationContext); Node actionNode = sequenceDefinitionNode.selectSingleNode("actions"); //$NON-NLS-1$ return (SequenceDefinition.getNextLoopGroup(seqDef, actionNode, solutionPath, solutionName, logger, loggingLevel)); } private static IActionSequence getNextLoopGroup(final ISequenceDefinition seqDef, final Node actionsNode, final String solutionPath, final String solutionName, final ILogger logger, final int loggingLevel) { String loopParameterName = XmlDom4JHelper.getNodeText("@loop-on", actionsNode); //$NON-NLS-1$ boolean loopUsingPeek = "true".equalsIgnoreCase(XmlDom4JHelper.getNodeText("@peek-only", actionsNode)); //$NON-NLS-1$ //$NON-NLS-2$ Node actionDefinitionNode; ActionDefinition actionDefinition; List actionDefinitionList = new ArrayList(); List nodeList = actionsNode.selectNodes("*"); //$NON-NLS-1$ Iterator actionDefinitionNodes = nodeList.iterator(); while (actionDefinitionNodes.hasNext()) { actionDefinitionNode = (Node) actionDefinitionNodes.next(); if (actionDefinitionNode.getName().equals("actions")) { //$NON-NLS-1$ actionDefinitionList.add(SequenceDefinition.getNextLoopGroup(seqDef, actionDefinitionNode, solutionPath, solutionName, logger, loggingLevel)); } else if (actionDefinitionNode.getName().equals("action-definition")) { //$NON-NLS-1$ actionDefinition = new ActionDefinition(actionDefinitionNode, logger); actionDefinition.setLoggingLevel(loggingLevel); actionDefinitionList.add(actionDefinition); } } // action sequences with 0 actions are valid, see: JIRA PLATFORM-837 IConditionalExecution conditionalExecution = SequenceDefinition.parseConditionalExecution(actionsNode, logger, "condition"); //$NON-NLS-1$ ActionSequence sequence = new ActionSequence(loopParameterName, seqDef, actionDefinitionList, loopUsingPeek); sequence.setConditionalExecution(conditionalExecution); return sequence; } private SequenceDefinition(final Node sequenceRootNode, final String actionName, final String solutionPath, final String solutionName, final ILogger logger, final IApplicationContext applicationContext) { // initialize this object from the contents of the xml this.name = actionName; this.solutionName = solutionName; this.solutionPath = solutionPath; this.applicationContext = applicationContext; // get the descriptive entries version = XmlDom4JHelper.getNodeText("version", sequenceRootNode); //$NON-NLS-1$ title = XmlDom4JHelper.getNodeText("title", sequenceRootNode); //$NON-NLS-1$ isWebService = "true".equals(XmlDom4JHelper.getNodeText("web-service", sequenceRootNode)); //$NON-NLS-1$ //$NON-NLS-2$ loggingLevel = Logger.getLogLevel(XmlDom4JHelper.getNodeText("logging-level", sequenceRootNode)); //$NON-NLS-1$ description = XmlDom4JHelper.getNodeText("documentation/description", sequenceRootNode); //$NON-NLS-1$ help = XmlDom4JHelper.getNodeText("documentation/help", sequenceRootNode); //$NON-NLS-1$ author = XmlDom4JHelper.getNodeText("documentation/author", sequenceRootNode); //$NON-NLS-1$ resultType = XmlDom4JHelper.getNodeText("documentation/result-type", sequenceRootNode); //$NON-NLS-1$ iconPath = XmlDom4JHelper.getNodeText("documentation/icon", sequenceRootNode); //$NON-NLS-1$ // get the input parameter definitions inputDefinitions = new ListOrderedMap(); errorCode = SequenceDefinition.parseParameters(sequenceRootNode, logger, "inputs/*", inputDefinitions, null, true); //$NON-NLS-1$ // get the ouput definitions outputDefinitions = new ListOrderedMap(); errorCode = SequenceDefinition.parseParameters(sequenceRootNode, logger, "outputs/*", outputDefinitions, null, false); //$NON-NLS-1$ if (errorCode != ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_OK) { logger.info(Messages.getInstance().getString("SequenceDefinition.INFO_OUTPUT_PARAMETERS_NOT_DEFINED")); //$NON-NLS-1$ } // get the resource definitions errorCode = parseResourceDefinitions(sequenceRootNode, logger); if (errorCode != ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_OK) { logger.info(Messages.getInstance().getString("SequenceDefinition.INFO_RESOURCES_PARAMETERS_NOT_DEFINED")); //$NON-NLS-1$ } } public String getVersion() { return version; } public boolean isWebService() { return isWebService; } public String getCacheLevel() { return cacheLevel; } public int getErrorCode() { return errorCode; } static IConditionalExecution parseConditionalExecution(final Node actionRootNode, final ILogger logger, final String nodePath) { try { Node condition = actionRootNode.selectSingleNode(nodePath); if (condition == null) { return null; } String script = condition.getText(); IConditionalExecution ce = PentahoSystem.get(IConditionalExecution.class, null); ce.setScript(script); return ce; } catch (Exception ex) { logger.error(Messages.getInstance().getErrorString("SequenceDefinition.ERROR_0005_PARSING_PARAMETERS"), ex); //$NON-NLS-1$ } return null; } static int parseParameters(final Node actionRootNode, final ILogger logger, final String nodePath, final Map parameterMap, final Map mapTo, final boolean inputVar) { try { List parameters = actionRootNode.selectNodes(nodePath); // TODO create objects to represent the types // TODO need source variable list Iterator parametersIterator = parameters.iterator(); Node parameterNode; String parameterName; String parameterType; ActionParameter parameter; List variableNodes; List variables; Node variableNode; Iterator variablesIterator; String variableSource; String variableName; int variableIdx; Object defaultValue = null; while (parametersIterator.hasNext()) { parameterNode = (Node) parametersIterator.next(); parameterName = parameterNode.getName(); parameterType = XmlDom4JHelper.getNodeText("@type", parameterNode); //$NON-NLS-1$ if (mapTo != null) { mapTo.put(parameterName, XmlDom4JHelper.getNodeText("@mapping", parameterNode, parameterName)); //$NON-NLS-1$ } defaultValue = SequenceDefinition.getDefaultValue(parameterNode); // get the list of sources for this parameter variableNodes = parameterNode.selectNodes((inputVar) ? "sources/*" : "destinations/*"); //$NON-NLS-1$ //$NON-NLS-2$ variablesIterator = variableNodes.iterator(); variableIdx = 1; variables = new ArrayList(); while (variablesIterator.hasNext()) { variableNode = (Node) variablesIterator.next(); // try to resolve the parameter value for this try { variableSource = variableNode.getName(); variableName = variableNode.getText(); ActionParameterSource variable = new ActionParameterSource(variableSource, variableName); if (SequenceDefinition.debug) { logger.debug(Messages.getInstance().getString( "SequenceDefinition.DEBUG_ADDING_SOURCE_FOR_PARAMETER", variableSource, parameterName)); //$NON-NLS-1$ } variables.add(variable); } catch (Exception e) { logger .error( Messages.getInstance() .getErrorString( "SequenceDefinition.ERROR_0004_VARIABLE_SOURCE_NOT_VALID", Integer.toString(variableIdx), parameterName), e); //$NON-NLS-1$ } variableIdx++; } if (defaultValue != null) { if (SequenceDefinition.debug) { logger.debug(Messages.getInstance().getString( "SequenceDefinition.DEBUG_USING_DEFAULT_VALUE", defaultValue.toString(), parameterName)); //$NON-NLS-1$ } } parameter = new ActionParameter(parameterName, parameterType, null, variables, defaultValue); parameterMap.put(parameterName, parameter); } return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_OK; } catch (Exception e) { logger.error(Messages.getInstance().getErrorString("SequenceDefinition.ERROR_0005_PARSING_PARAMETERS"), e); //$NON-NLS-1$ } return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_INVALID_ACTION_DOC; } private int parseResourceDefinitions(final Node actionRootNode, final ILogger logger) { resourceDefinitions = new ListOrderedMap(); try { List resources = actionRootNode.selectNodes("resources/*"); //$NON-NLS-1$ // TODO create objects to represent the types // TODO need source variable list Iterator resourcesIterator = resources.iterator(); Node resourceNode; String resourceName; String resourceTypeName; String resourceMimeType; int resourceType; ActionResource resource; Node typeNode, mimeNode; while (resourcesIterator.hasNext()) { resourceNode = (Node) resourcesIterator.next(); typeNode = resourceNode.selectSingleNode("./*"); //$NON-NLS-1$ if (typeNode != null) { resourceName = resourceNode.getName(); resourceTypeName = typeNode.getName(); resourceType = ActionResource.getResourceType(resourceTypeName); String resourceLocation = XmlDom4JHelper.getNodeText("location", typeNode); //$NON-NLS-1$ if (resourceType == IActionSequenceResource.SOLUTION_FILE_RESOURCE) { if (resourceLocation == null) { logger.error(Messages.getInstance().getErrorString("SequenceDefinition.ERROR_0008_RESOURCE_NO_LOCATION", resourceName)); //$NON-NLS-1$ continue; } } else if (resourceType == IActionSequenceResource.STRING) { resourceLocation = XmlDom4JHelper.getNodeText("string", resourceNode); //$NON-NLS-1$ } else if (resourceType == IActionSequenceResource.XML) { //resourceLocation = XmlHelper.getNodeText("xml", resourceNode); //$NON-NLS-1$ Node xmlNode = typeNode.selectSingleNode("./location/*"); //$NON-NLS-1$ // Danger, we have now lost the character encoding of the XML in this node // see BISERVER-895 resourceLocation = (xmlNode == null) ? "" : xmlNode.asXML(); //$NON-NLS-1$ } mimeNode = typeNode.selectSingleNode("mime-type"); //$NON-NLS-1$ if (mimeNode != null) { resourceMimeType = mimeNode.getText(); resource = new ActionResource(resourceName, resourceType, resourceMimeType, solutionName, solutionPath, resourceLocation); resourceDefinitions.put(resourceName, resource); } else { logger.error(Messages.getInstance().getErrorString("SequenceDefinition.ERROR_0007_RESOURCE_NO_MIME_TYPE", resourceName)); //$NON-NLS-1$ } } // input = new ActionParameter( resourceName, resourceType, null // ); // resourceDefinitions.put( inputName, input ); } return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_OK; } catch (Exception e) { logger.error(Messages.getInstance().getErrorString("SequenceDefinition.ERROR_0006_PARSING_RESOURCE"), e); //$NON-NLS-1$ } return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_INVALID_ACTION_DOC; } /** * sbarkdull: method appears to never be used anywhere * * @param actionRootNode * @param logger * @param nodePath * @param mapTo * @return */ static int parseActionResourceDefinitions(final Node actionRootNode, final ILogger logger, final String nodePath, final Map mapTo) { try { List resources = actionRootNode.selectNodes(nodePath); // TODO create objects to represent the types // TODO need source variable list Iterator resourcesIterator = resources.iterator(); Node resourceNode; String resourceName; while (resourcesIterator.hasNext()) { resourceNode = (Node) resourcesIterator.next(); resourceName = resourceNode.getName(); if (mapTo != null) { mapTo.put(resourceName, XmlDom4JHelper.getNodeText("@mapping", resourceNode, resourceName)); //$NON-NLS-1$ } } return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_OK; } catch (Exception e) { logger.error(Messages.getInstance().getErrorString("SequenceDefinition.ERROR_0006_PARSING_RESOURCE"), e); //$NON-NLS-1$ } return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_INVALID_ACTION_DOC; } private static Object getDefaultValue(final Node parameterNode) { Node rootNode = parameterNode.selectSingleNode("default-value"); //$NON-NLS-1$ if (rootNode == null) { return (null); } String dataType = XmlDom4JHelper.getNodeText("@type", rootNode); //$NON-NLS-1$ if (dataType == null) { dataType = XmlDom4JHelper.getNodeText("@type", parameterNode); //$NON-NLS-1$ } if ("string-list".equals(dataType)) { //$NON-NLS-1$ List nodes = rootNode.selectNodes("list-item"); //$NON-NLS-1$ if (nodes == null) { return (null); } ArrayList rtnList = new ArrayList(); for (Iterator it = nodes.iterator(); it.hasNext();) { rtnList.add(((Node) it.next()).getText()); } return (rtnList); } else if ("property-map-list".equals(dataType)) { //$NON-NLS-1$ List nodes = rootNode.selectNodes("property-map"); //$NON-NLS-1$ if (nodes == null) { return (null); } ArrayList rtnList = new ArrayList(); for (Iterator it = nodes.iterator(); it.hasNext();) { Node mapNode = (Node) it.next(); rtnList.add(SequenceDefinition.getMapFromNode(mapNode)); } return (rtnList); } else if ("property-map".equals(dataType)) { //$NON-NLS-1$ return (SequenceDefinition.getMapFromNode(rootNode.selectSingleNode("property-map"))); //$NON-NLS-1$ } else if ("long".equals(dataType)) { //$NON-NLS-1$ try { return (new Long(rootNode.getText())); } catch (Exception e) { } return (null); } else if ("result-set".equals(dataType)) { //$NON-NLS-1$ return (MemoryResultSet.createFromActionSequenceInputsNode(parameterNode)); } else { // Assume String return (rootNode.getText()); } } private static Map getMapFromNode(final Node mapNode) { Map rtnMap = new ListOrderedMap(); if (mapNode != null) { List nodes = mapNode.selectNodes("entry"); //$NON-NLS-1$ if (nodes != null) { for (Iterator it = nodes.iterator(); it.hasNext();) { Node entryNode = (Node) it.next(); rtnMap.put(XmlDom4JHelper.getNodeText("@key", entryNode), entryNode.getText()); //$NON-NLS-1$ } } } return (rtnMap); } /* * (non-Javadoc) * * @see org.pentaho.newcode.IActionDefinition#getParamDefs() */ public Map getInputDefinitions() { return inputDefinitions; } public Map getInputDefinitionsForParameterProvider(final String parameterProviderName) { Map rtnMap = new ListOrderedMap(); Map paramList = getInputDefinitions(); for (Iterator it = paramList.values().iterator(); it.hasNext();) { IActionParameter actionParameter = (IActionParameter) it.next(); List vars = actionParameter.getVariables(); for (int i = 0; i < vars.size(); i++) { ActionParameterSource source = (ActionParameterSource) (vars.get(i)); if (source.getSourceName().equals(parameterProviderName)) { rtnMap.put(source.getValue(), actionParameter); } } } return (rtnMap); } /* * (non-Javadoc) * * @see org.pentaho.newcode.IActionDefinition#getOutputDefs() */ public Map getOutputDefinitions() { return outputDefinitions; } /* * (non-Javadoc) * * @see org.pentaho.newcode.IActionDefinition#getResourceDefs() */ public Map getResourceDefinitions() { return resourceDefinitions; } public String getSequenceName() { return name; } public String getAuthor() { return author; } public String getDescription() { return description; } public String getResultType() { return resultType; } public String getHelp() { return help; } public String getTitle() { return title; } public String getSolutionName() { return solutionName; } public String getSolutionPath() { return solutionPath; } public int getLoggingLevel() { return (loggingLevel); } public String getIcon() { return iconPath; } }