001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: *
013: * @created Jul 18, 2005
014: * @author James Dixon
015: *
016: */
017: package org.pentaho.core.solution;
018:
019: import java.util.ArrayList;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Map;
023:
024: import org.apache.commons.collections.map.ListOrderedMap;
025: import org.dom4j.Document;
026: import org.dom4j.Node;
027: import org.pentaho.commons.connection.memory.MemoryResultSet;
028: import org.pentaho.core.runtime.ActionParameter;
029: import org.pentaho.core.runtime.IActionParameter;
030: import org.pentaho.core.system.IApplicationContext;
031: import org.pentaho.core.system.PentahoSystem;
032: import org.pentaho.core.util.XmlHelper;
033: import org.pentaho.messages.Messages;
034: import org.pentaho.util.logging.ILogger;
035: import org.pentaho.util.logging.Logger;
036:
037: public class SequenceDefinition implements ISequenceDefinition {
038:
039: private static final boolean debug = PentahoSystem.debug;
040:
041: private int errorCode;
042:
043: private String solutionPath;
044:
045: private String solutionName;
046:
047: private String name;
048:
049: private String version;
050:
051: private String title;
052:
053: private boolean isWebService;
054:
055: private String cacheLevel;
056:
057: private int loggingLevel;
058:
059: private String description;
060:
061: private String author;
062:
063: private String help;
064:
065: private String resultType;
066:
067: private String iconPath;
068:
069: private Map outputDefinitions;
070:
071: private Map inputDefinitions;
072:
073: private Map resourceDefinitions;
074:
075: IApplicationContext applicationContext;
076:
077: IActionDefinition actionDefinitions[];
078:
079: public static IActionSequence ActionSequenceFactory(
080: Document document, String actionName, String solutionPath,
081: String solutionName, ILogger logger,
082: IApplicationContext applicationContext, int loggingLevel) {
083:
084: // Check for a sequence document
085: Node sequenceDefinitionNode = document
086: .selectSingleNode("//action-sequence"); //$NON-NLS-1$
087: if (sequenceDefinitionNode == null) {
088: logger
089: .error(Messages
090: .getErrorString(
091: "SequenceDefinition.ERROR_0002_NO_ACTION_SEQUENCE_NODE", solutionName, solutionPath, actionName)); //$NON-NLS-1$
092: return null;
093: }
094:
095: ISequenceDefinition seqDef = new SequenceDefinition(
096: sequenceDefinitionNode, actionName, solutionPath,
097: solutionName, logger, applicationContext);
098:
099: Node actionNode = sequenceDefinitionNode
100: .selectSingleNode("actions"); //$NON-NLS-1$
101:
102: return (getNextLoopGroup(seqDef, actionNode, solutionPath,
103: solutionName, logger, loggingLevel));
104: }
105:
106: private static IActionSequence getNextLoopGroup(
107: ISequenceDefinition seqDef, Node actionsNode,
108: String solutionPath, String solutionName, ILogger logger,
109: int loggingLevel) {
110:
111: String loopParameterName = XmlHelper.getNodeText(
112: "@loop-on", actionsNode); //$NON-NLS-1$
113:
114: Node actionDefinitionNode;
115: ActionDefinition actionDefinition;
116:
117: List actionDefinitionList = new ArrayList();
118:
119: List nodeList = actionsNode.selectNodes("*"); //$NON-NLS-1$
120: Iterator actionDefinitionNodes = nodeList.iterator();
121: while (actionDefinitionNodes.hasNext()) {
122: actionDefinitionNode = (Node) actionDefinitionNodes.next();
123: if (actionDefinitionNode.getName().equals("actions")) { //$NON-NLS-1$
124: actionDefinitionList.add(getNextLoopGroup(seqDef,
125: actionDefinitionNode, solutionPath,
126: solutionName, logger, loggingLevel));
127: } else if (actionDefinitionNode.getName().equals(
128: "action-definition")) { //$NON-NLS-1$
129: actionDefinition = new ActionDefinition(
130: actionDefinitionNode, logger);
131: actionDefinition.setLoggingLevel(loggingLevel);
132: actionDefinitionList.add(actionDefinition);
133: }
134: }
135: // action sequences with 0 actions are valid, see: JIRA PLATFORM-837
136:
137: ConditionalExecution conditionalExecution = SequenceDefinition
138: .parseConditionalExecution(actionsNode, logger,
139: "condition"); //$NON-NLS-1$
140:
141: ActionSequence sequence = new ActionSequence(loopParameterName,
142: seqDef, actionDefinitionList);
143:
144: sequence.setConditionalExecution(conditionalExecution);
145: return sequence;
146: }
147:
148: private SequenceDefinition(Node sequenceRootNode,
149: String actionName, String solutionPath,
150: String solutionName, ILogger logger,
151: IApplicationContext applicationContext) {
152:
153: // initialize this object from the contents of the xml
154:
155: this .name = actionName;
156: this .solutionName = solutionName;
157: this .solutionPath = solutionPath;
158: this .applicationContext = applicationContext;
159:
160: // get the descriptive entries
161: version = XmlHelper.getNodeText("version", sequenceRootNode); //$NON-NLS-1$
162: title = XmlHelper.getNodeText("title", sequenceRootNode); //$NON-NLS-1$
163:
164: isWebService = "true".equals(XmlHelper.getNodeText("web-service", sequenceRootNode)); //$NON-NLS-1$ //$NON-NLS-2$
165: loggingLevel = Logger.getLogLevel(XmlHelper.getNodeText(
166: "logging-level", sequenceRootNode)); //$NON-NLS-1$
167:
168: description = XmlHelper.getNodeText(
169: "documentation/description", sequenceRootNode); //$NON-NLS-1$
170: help = XmlHelper.getNodeText(
171: "documentation/help", sequenceRootNode); //$NON-NLS-1$
172: author = XmlHelper.getNodeText(
173: "documentation/author", sequenceRootNode); //$NON-NLS-1$
174: resultType = XmlHelper.getNodeText(
175: "documentation/result-type", sequenceRootNode); //$NON-NLS-1$
176: iconPath = XmlHelper.getNodeText(
177: "documentation/icon", sequenceRootNode); //$NON-NLS-1$
178:
179: // get the input parameter definitions
180: inputDefinitions = new ListOrderedMap();
181: errorCode = parseParameters(sequenceRootNode, logger,
182: "inputs/*", inputDefinitions, null, true); //$NON-NLS-1$
183:
184: // get the ouput definitions
185: outputDefinitions = new ListOrderedMap();
186: errorCode = parseParameters(sequenceRootNode, logger,
187: "outputs/*", outputDefinitions, null, false); //$NON-NLS-1$
188:
189: // get the resource definitions
190: errorCode = parseResourceDefinitions(sequenceRootNode, logger);
191: }
192:
193: public String getVersion() {
194: return version;
195: }
196:
197: public boolean isWebService() {
198: return isWebService;
199: }
200:
201: public String getCacheLevel() {
202: return cacheLevel;
203: }
204:
205: public int getErrorCode() {
206: return errorCode;
207: }
208:
209: static ConditionalExecution parseConditionalExecution(
210: Node actionRootNode, ILogger logger, String nodePath) {
211: try {
212: Node condition = actionRootNode.selectSingleNode(nodePath);
213: if (condition == null) {
214: return null;
215: }
216: String script = condition.getText();
217: ConditionalExecution ce = new ConditionalExecution();
218: ce.setScript(script);
219: return ce;
220: } catch (Exception ex) {
221: logger
222: .error(
223: Messages
224: .getErrorString("SequenceDefinition.ERROR_0005_PARSING_CONDITIONAL_EXECUTION"), ex); //$NON-NLS-1$
225: }
226: return null;
227: }
228:
229: static int parseParameters(Node actionRootNode, ILogger logger,
230: String nodePath, Map parameterMap, Map mapTo,
231: boolean inputVar) {
232: try {
233: List parameters = actionRootNode.selectNodes(nodePath);
234:
235: // TODO create objects to represent the types
236: // TODO need source variable list
237: Iterator parametersIterator = parameters.iterator();
238: Node parameterNode;
239: String parameterName;
240: String parameterType;
241: ActionParameter parameter;
242: List variableNodes;
243: List variables;
244: Node variableNode;
245: Iterator variablesIterator;
246: String variableSource;
247: String variableName;
248: int variableIdx;
249: Object defaultValue = null;
250:
251: while (parametersIterator.hasNext()) {
252: parameterNode = (Node) parametersIterator.next();
253: parameterName = parameterNode.getName();
254: parameterType = XmlHelper.getNodeText(
255: "@type", parameterNode); //$NON-NLS-1$
256:
257: if (mapTo != null) {
258: mapTo.put(parameterName, XmlHelper.getNodeText(
259: "@mapping", parameterNode, parameterName)); //$NON-NLS-1$
260: }
261:
262: defaultValue = getDefaultValue(parameterNode);
263: // get the list of sources for this parameter
264: variableNodes = parameterNode
265: .selectNodes((inputVar) ? "sources/*" : "destinations/*"); //$NON-NLS-1$ //$NON-NLS-2$
266: variablesIterator = variableNodes.iterator();
267: variableIdx = 1;
268: variables = new ArrayList();
269: while (variablesIterator.hasNext()) {
270: variableNode = (Node) variablesIterator.next();
271: // try to resolve the parameter value for this
272: try {
273: variableSource = variableNode.getName();
274: variableName = variableNode.getText();
275: ActionParameterSource variable = new ActionParameterSource(
276: variableSource, variableName);
277: if (debug)
278: logger
279: .debug(Messages
280: .getString(
281: "SequenceDefinition.DEBUG_ADDING_SOURCE_FOR_PARAMETER", variableSource, parameterName)); //$NON-NLS-1$
282:
283: variables.add(variable);
284: } catch (Exception e) {
285: logger
286: .error(
287: Messages
288: .getErrorString(
289: "SequenceDefinition.ERROR_0004_VARIABLE_SOURCE_NOT_VALID", Integer.toString(variableIdx), parameterName), e); //$NON-NLS-1$
290: }
291: variableIdx++;
292: }
293: if (defaultValue != null) {
294: if (debug)
295: logger
296: .debug(Messages
297: .getString(
298: "SequenceDefinition.DEBUG_USING_DEFAULT_VALUE", defaultValue.toString(), parameterName)); //$NON-NLS-1$
299: }
300: parameter = new ActionParameter(parameterName,
301: parameterType, null, variables, defaultValue);
302: parameterMap.put(parameterName, parameter);
303: }
304: return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_OK;
305: } catch (Exception e) {
306: logger
307: .error(
308: Messages
309: .getErrorString("SequenceDefinition.ERROR_0005_PARSING_PARAMETERS"), e); //$NON-NLS-1$
310: }
311: return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_INVALID_ACTION_DOC;
312: }
313:
314: private int parseResourceDefinitions(Node actionRootNode,
315: ILogger logger) {
316:
317: resourceDefinitions = new ListOrderedMap();
318:
319: try {
320: List resources = actionRootNode.selectNodes("resources/*"); //$NON-NLS-1$
321:
322: // TODO create objects to represent the types
323: // TODO need source variable list
324: Iterator resourcesIterator = resources.iterator();
325:
326: Node resourceNode;
327: String resourceName;
328: String resourceTypeName;
329: String resourceMimeType;
330: int resourceType;
331: ActionResource resource;
332: Node typeNode, mimeNode;
333: while (resourcesIterator.hasNext()) {
334: resourceNode = (Node) resourcesIterator.next();
335: typeNode = resourceNode.selectSingleNode("./*"); //$NON-NLS-1$
336: if (typeNode != null) {
337: resourceName = resourceNode.getName();
338: resourceTypeName = typeNode.getName();
339: resourceType = ActionResource
340: .getResourceType(resourceTypeName);
341: String resourceLocation = XmlHelper.getNodeText(
342: "location", typeNode); //$NON-NLS-1$
343: if (resourceType == IActionResource.SOLUTION_FILE_RESOURCE) {
344: if (resourceLocation == null) {
345: logger
346: .error(Messages
347: .getErrorString(
348: "SequenceDefinition.ERROR_0008_RESOURCE_NO_LOCATION", resourceName)); //$NON-NLS-1$
349: continue;
350: }
351: } else if (resourceType == IActionResource.STRING) {
352: resourceLocation = XmlHelper.getNodeText(
353: "string", resourceNode); //$NON-NLS-1$
354: } else if (resourceType == IActionResource.XML) {
355: //resourceLocation = XmlHelper.getNodeText("xml", resourceNode); //$NON-NLS-1$
356: Node xmlNode = typeNode
357: .selectSingleNode("./location/*"); //$NON-NLS-1$
358: // Danger, we have now lost the character encoding of the XML in this node
359: // see BISERVER-895
360: resourceLocation = (xmlNode == null) ? "" : xmlNode.asXML(); //$NON-NLS-1$
361: }
362: mimeNode = typeNode.selectSingleNode("mime-type"); //$NON-NLS-1$
363: if (mimeNode != null) {
364: resourceMimeType = mimeNode.getText();
365: resource = new ActionResource(resourceName,
366: resourceType, resourceMimeType,
367: solutionName, solutionPath,
368: resourceLocation);
369: resourceDefinitions.put(resourceName, resource);
370: } else {
371: logger
372: .error(Messages
373: .getErrorString(
374: "SequenceDefinition.ERROR_0007_RESOURCE_NO_MIME_TYPE", resourceName)); //$NON-NLS-1$
375: }
376: }
377: // input = new ActionParameter( resourceName, resourceType, null
378: // );
379: // resourceDefinitions.put( inputName, input );
380: }
381: return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_OK;
382: } catch (Exception e) {
383: logger
384: .error(
385: Messages
386: .getErrorString("SequenceDefinition.ERROR_0006_PARSING_RESOURCE"), e); //$NON-NLS-1$
387: }
388: return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_INVALID_ACTION_DOC;
389:
390: }
391:
392: /**
393: * sbarkdull: method appears to never be used anywhere
394: *
395: * @param actionRootNode
396: * @param logger
397: * @param nodePath
398: * @param mapTo
399: * @return
400: */
401: static int parseActionResourceDefinitions(Node actionRootNode,
402: ILogger logger, String nodePath, Map mapTo) {
403:
404: try {
405: List resources = actionRootNode.selectNodes(nodePath);
406:
407: // TODO create objects to represent the types
408: // TODO need source variable list
409: Iterator resourcesIterator = resources.iterator();
410:
411: Node resourceNode;
412: String resourceName;
413: while (resourcesIterator.hasNext()) {
414: resourceNode = (Node) resourcesIterator.next();
415: resourceName = resourceNode.getName();
416: if (mapTo != null) {
417: mapTo.put(resourceName, XmlHelper.getNodeText(
418: "@mapping", resourceNode, resourceName)); //$NON-NLS-1$
419: }
420: }
421: return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_OK;
422: } catch (Exception e) {
423: logger
424: .error(
425: Messages
426: .getErrorString("SequenceDefinition.ERROR_0006_PARSING_RESOURCE"), e); //$NON-NLS-1$
427: }
428: return ISequenceDefinition.ACTION_SEQUENCE_DEFINITION_INVALID_ACTION_DOC;
429:
430: }
431:
432: private static Object getDefaultValue(Node parameterNode) {
433: Node rootNode = parameterNode.selectSingleNode("default-value"); //$NON-NLS-1$
434: if (rootNode == null) {
435: return (null);
436: }
437:
438: String dataType = XmlHelper.getNodeText("@type", rootNode); //$NON-NLS-1$
439: if (dataType == null) {
440: dataType = XmlHelper.getNodeText("@type", parameterNode); //$NON-NLS-1$
441: }
442:
443: if ("string-list".equals(dataType)) { //$NON-NLS-1$
444: List nodes = rootNode.selectNodes("list-item"); //$NON-NLS-1$
445: if (nodes == null) {
446: return (null);
447: }
448:
449: ArrayList rtnList = new ArrayList();
450: for (Iterator it = nodes.iterator(); it.hasNext();) {
451: rtnList.add(((Node) it.next()).getText());
452: }
453: return (rtnList);
454: } else if ("property-map-list".equals(dataType)) { //$NON-NLS-1$
455: List nodes = rootNode.selectNodes("property-map"); //$NON-NLS-1$
456: if (nodes == null) {
457: return (null);
458: }
459:
460: ArrayList rtnList = new ArrayList();
461: for (Iterator it = nodes.iterator(); it.hasNext();) {
462: Node mapNode = (Node) it.next();
463: rtnList.add(getMapFromNode(mapNode));
464: }
465: return (rtnList);
466: } else if ("property-map".equals(dataType)) { //$NON-NLS-1$
467: return (getMapFromNode(rootNode
468: .selectSingleNode("property-map"))); //$NON-NLS-1$
469: } else if ("long".equals(dataType)) { //$NON-NLS-1$
470: try {
471: return (new Long(rootNode.getText()));
472: } catch (Exception e) {
473: }
474: return (null);
475: } else if ("result-set".equals(dataType)) { //$NON-NLS-1$
476:
477: return (MemoryResultSet
478: .createFromActionSequenceInputsNode(parameterNode));
479: } else { // Assume String
480: return (rootNode.getText());
481: }
482:
483: }
484:
485: private static Map getMapFromNode(Node mapNode) {
486: Map rtnMap = new ListOrderedMap();
487:
488: if (mapNode != null) {
489: List nodes = mapNode.selectNodes("entry"); //$NON-NLS-1$
490: if (nodes != null) {
491: for (Iterator it = nodes.iterator(); it.hasNext();) {
492: Node entryNode = (Node) it.next();
493: rtnMap
494: .put(
495: XmlHelper.getNodeText(
496: "@key", entryNode), entryNode.getText()); //$NON-NLS-1$
497: }
498: }
499: }
500: return (rtnMap);
501: }
502:
503: /*
504: * (non-Javadoc)
505: *
506: * @see org.pentaho.newcode.IActionDefinition#getParamDefs()
507: */
508: public Map getInputDefinitions() {
509: return inputDefinitions;
510: }
511:
512: public Map getInputDefinitionsForParameterProvider(
513: String parameterProviderName) {
514: Map rtnMap = new ListOrderedMap();
515:
516: Map paramList = getInputDefinitions();
517: for (Iterator it = paramList.values().iterator(); it.hasNext();) {
518: IActionParameter actionParameter = (IActionParameter) it
519: .next();
520: List vars = actionParameter.getVariables();
521: for (int i = 0; i < vars.size(); i++) {
522: ActionParameterSource source = (ActionParameterSource) (vars
523: .get(i));
524: if (source.getSourceName()
525: .equals(parameterProviderName)) {
526: rtnMap.put(source.getValue(), actionParameter);
527: }
528: }
529: }
530: return (rtnMap);
531: }
532:
533: /*
534: * (non-Javadoc)
535: *
536: * @see org.pentaho.newcode.IActionDefinition#getOutputDefs()
537: */
538: public Map getOutputDefinitions() {
539: return outputDefinitions;
540: }
541:
542: /*
543: * (non-Javadoc)
544: *
545: * @see org.pentaho.newcode.IActionDefinition#getResourceDefs()
546: */
547: public Map getResourceDefinitions() {
548: return resourceDefinitions;
549: }
550:
551: public String getSequenceName() {
552: return name;
553: }
554:
555: public String getAuthor() {
556: return author;
557: }
558:
559: public String getDescription() {
560: return description;
561: }
562:
563: public String getResultType() {
564: return resultType;
565: }
566:
567: public String getHelp() {
568: return help;
569: }
570:
571: public String getTitle() {
572: return title;
573: }
574:
575: public String getSolutionName() {
576: return solutionName;
577: }
578:
579: public String getSolutionPath() {
580: return solutionPath;
581: }
582:
583: public int getLoggingLevel() {
584: return (loggingLevel);
585: }
586:
587: public String getIcon() {
588: return iconPath;
589: }
590:
591: }
|