/*
* 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;
}
}