001: /*
002: * Copyright 2007 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 Jun 29, 2007
014: * @author wseyler
015: */
016:
017: package org.pentaho.plugin.olap;
018:
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.List;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025: import org.dom4j.Document;
026: import org.dom4j.Element;
027: import org.dom4j.Node;
028: import org.pentaho.core.repository.ISolutionRepository;
029: import org.pentaho.core.session.IPentahoSession;
030: import org.pentaho.core.solution.ISolutionFile;
031: import org.pentaho.core.system.PentahoMessenger;
032: import org.pentaho.core.system.PentahoSystem;
033: import org.pentaho.core.system.PentahoSystem.ActionInfo;
034: import org.pentaho.core.util.XmlHelper;
035: import org.pentaho.messages.Messages;
036:
037: /**
038: * Utility class used to save an analysis action sequence from a
039: * JPivot view.
040: */
041: public class AnalysisSaver extends PentahoMessenger {
042: private static final long serialVersionUID = 6290291421129174060L;
043:
044: private static final String ATTRIBUTE_TYPE = "type"; //$NON-NLS-1$
045:
046: private static final String ATTRIBUTE_STRING = "string"; //$NON-NLS-1$
047:
048: private static final String TITLE_NODE_NAME = "title"; //$NON-NLS-1$
049:
050: public static final String SUFFIX = ".xaction"; //$NON-NLS-1$
051:
052: public static final String PROPERTIES_SUFFIX = ".properties"; //$NON-NLS-1$
053:
054: private static Log logger = null;
055:
056: /* (non-Javadoc)
057: * @see org.pentaho.core.system.PentahoBase#getLogger()
058: */
059: public Log getLogger() {
060: return logger;
061: }
062:
063: public static int saveAnalysis(IPentahoSession session,
064: HashMap props, String path, String fileName,
065: boolean overwrite) {
066: int result = 0;
067: try {
068: logger = LogFactory.getLog(AnalysisSaver.class);
069: String baseUrl = PentahoSystem.getApplicationContext()
070: .getSolutionPath(""); //$NON-NLS-1$
071: ISolutionRepository solutionRepository = PentahoSystem
072: .getSolutionRepository(session);
073:
074: // We will (at this point in time) always have an original action sequence to start from...
075: String originalActionReference = (String) props
076: .get("actionreference"); //$NON-NLS-1$
077:
078: if (originalActionReference == null) {
079: throw new MissingParameterException(
080: Messages
081: .getErrorString("ANALYSISSAVER.ERROR_0001_MISSING_ACTION_REFERENCE")); //$NON-NLS-1$
082: }
083:
084: org.dom4j.Document document = XmlHelper
085: .getDomFromResource(originalActionReference);
086:
087: // Update the document with the stuff we passed in on the props
088: document = updateDocument(document, props);
089: System.out.println(document.asXML());
090: fileName = fileName.endsWith(SUFFIX) ? fileName : fileName
091: + SUFFIX;
092: result = solutionRepository.addSolutionFile(baseUrl, path,
093: fileName, document.asXML().getBytes(), overwrite);
094:
095: // Now save the resource files
096: ActionInfo actionInfo = PentahoSystem
097: .parseActionString(originalActionReference);
098: String originalPath = actionInfo.getSolutionName()
099: + "/" + actionInfo.getPath(); //$NON-NLS-1$
100: String originalFileName = actionInfo.getActionName();
101: originalFileName = originalFileName.substring(0,
102: originalFileName.lastIndexOf(SUFFIX));
103: ISolutionFile[] parentFiles = solutionRepository
104: .getFileByPath(originalPath).listFiles();
105: String baseFileName = fileName.substring(0, fileName
106: .lastIndexOf(SUFFIX));
107: for (int i = 0; i < parentFiles.length; i++) {
108: ISolutionFile aSolutionFile = parentFiles[i];
109: if (!aSolutionFile.isDirectory()
110: && aSolutionFile.getFileName().startsWith(
111: originalFileName)
112: && aSolutionFile.getFileName().toLowerCase()
113: .endsWith(PROPERTIES_SUFFIX)) {
114: String newFileName = aSolutionFile.getFileName()
115: .replaceFirst(originalFileName,
116: baseFileName);
117: result = result
118: & solutionRepository.addSolutionFile(
119: baseUrl, path, newFileName,
120: aSolutionFile.getData(), overwrite);
121: }
122: }
123:
124: solutionRepository.resetRepository();
125: } catch (Exception e) {
126: logger
127: .error(
128: Messages
129: .getErrorString("ANALYSISSAVER.ERROR_0000_UNKNOWN"), e); //$NON-NLS-1$
130: result = ISolutionRepository.FILE_ADD_FAILED;
131: }
132:
133: return result;
134: }
135:
136: /**
137: * @param document
138: * @param props
139: * @return
140: */
141: private static Document updateDocument(Document document,
142: HashMap props) {
143: try {
144: Element componentDefinition = null;
145: Element actionOutput = null;
146: Element actionSequenceOutput = null;
147:
148: Node actionSequence = document
149: .selectSingleNode("/action-sequence"); //$NON-NLS-1$
150: if (actionSequence == null) {
151: throw new InvalidDocumentException(
152: Messages
153: .getErrorString("ANALYSISSAVER.ERROR_0004_INVALID_ORIGIN_DOCUMENT")); //$NON-NLS-1$
154: }
155:
156: Node title = null;
157: String propertyTitle = (String) props.get(TITLE_NODE_NAME);
158: title = document.selectSingleNode("action-sequence/title"); //$NON-NLS-1$
159: if ((propertyTitle != null) && (title != null)) {
160: title.setText(propertyTitle);
161: }
162:
163: // Next, we need to retrieve the PivotViewComponent action and
164: // process/update it.. there could popssibly be more than one
165: // PivotViewComponent in an action sequence, however, we have no idea
166: // how to figure out which one to process, so we default to picking the last one we found.
167:
168: componentDefinition = (Element) document
169: .selectSingleNode("//action-definition[component-name='PivotViewComponent']/component-definition"); //$NON-NLS-1$
170: if (componentDefinition == null) {
171: throw new InvalidDocumentException(
172: Messages
173: .getErrorString("ANALYSISSAVER.ERROR_0005_INVALID_NO_PIVOT_ACTION")); //$NON-NLS-1$
174: }
175:
176: updateComponent(componentDefinition, props);
177:
178: // Get the action's root action-output node, in case we need to add the
179: // appropriate outputs for the pivot view...
180: actionOutput = (Element) document
181: .selectSingleNode("//action-definition[component-name='PivotViewComponent']/action-outputs"); //$NON-NLS-1$
182: updateOutput(actionOutput, props);
183:
184: // Get the action's root action sequence output node, in case we need to add the
185: // appropriate outputs for the pivot view...
186: actionSequenceOutput = (Element) document
187: .selectSingleNode("//action-sequence/outputs"); //$NON-NLS-1$
188: updateOutput(actionSequenceOutput, props);
189:
190: } catch (Exception e) {
191: e.printStackTrace();
192: }
193: return document;
194: }
195:
196: /**
197: * @param componentDefinition
198: * @param props
199: */
200: private static void updateComponent(Element componentDefinition,
201: HashMap props) {
202: Iterator iter = props.keySet().iterator();
203:
204: while (iter.hasNext()) {
205: Object key = iter.next();
206: Node node = componentDefinition.selectSingleNode(key
207: .toString());
208: if (node == null) {
209: node = componentDefinition.addElement(key.toString());
210: }
211: if (PivotViewComponent.OPTIONS.equals(node.getName())) {
212: List optionsList = (List) props.get(key);
213: Iterator optsIter = optionsList.iterator();
214: while (optsIter.hasNext()) {
215: String anOption = optsIter.next().toString();
216: Node anOptionNode = node.selectSingleNode(anOption);
217: if (anOptionNode == null) {
218: ((Element) node).addElement(anOption);
219: }
220: }
221: } else {
222: Object value = props.get(key);
223: if (value != null) {
224: node.setText(value.toString());
225: }
226: }
227: }
228:
229: String mdxValue = componentDefinition
230: .selectSingleNode("mdx").getText();//$NON-NLS-1$
231: componentDefinition.selectSingleNode("query").setText(mdxValue);//$NON-NLS-1$
232: }
233:
234: /**
235: * @param outputNode
236: * @param props
237: */
238: private static void updateOutput(Element outputNode, HashMap props) {
239: Iterator iter = props.keySet().iterator();
240:
241: while (iter.hasNext()) {
242: Object key = iter.next();
243: Node node = outputNode.selectSingleNode(key.toString());
244: if (node == null) {
245: outputNode
246: .addElement(key.toString())
247: .addAttribute(
248: ATTRIBUTE_TYPE,
249: "options".equals(key.toString()) ? "list" : ATTRIBUTE_STRING);//$NON-NLS-1$//$NON-NLS-2$
250: }
251: }
252: }
253: }
|