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 Nov 17, 2005
014: * @author wseyler
015: */
016:
017: package org.pentaho.ui.component.charting;
018:
019: import java.io.File;
020: import java.io.IOException;
021: import java.io.OutputStream;
022: import java.io.UnsupportedEncodingException;
023: import java.lang.reflect.Array;
024: import java.net.URLEncoder;
025: import java.util.ArrayList;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.List;
029:
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032: import org.pentaho.commons.connection.IPentahoResultSet;
033: import org.pentaho.core.runtime.IActionParameter;
034: import org.pentaho.core.runtime.IRuntimeContext;
035: import org.pentaho.core.solution.ISolutionEngine;
036: import org.pentaho.core.solution.SimpleOutputHandler;
037: import org.pentaho.core.system.PentahoSystem;
038: import org.pentaho.core.ui.IPentahoUrlFactory;
039: import org.pentaho.core.util.TemplateUtil;
040: import org.pentaho.messages.Messages;
041: import org.pentaho.messages.util.LocaleHelper;
042: import org.pentaho.ui.XmlComponent;
043: import org.pentaho.util.logging.ILogger;
044:
045: public abstract class AbstractChartComponent extends XmlComponent {
046:
047: public static final String CHART_NODE_NAME = "chart"; //$NON-NLS-1$
048:
049: public static final String URLTEMPLE_NODE_NAME = "url-template"; //$NON-NLS-1$
050:
051: public static final String PARAM2_NODE_NAME = "series-name"; //$NON-NLS-1$
052:
053: public static final int FILENAME_INDEX = 0;
054:
055: public static final int FILENAME_WITHOUT_EXTENSION_INDEX = 1;
056:
057: protected String definitionPath;
058:
059: protected int width = -1;
060:
061: protected int height = -1;
062:
063: protected String title;
064:
065: protected Object values;
066:
067: protected boolean byRow = true;
068:
069: protected String solution;
070:
071: protected String actionPath;
072:
073: protected String actionName;
074:
075: protected String actionOutput;
076:
077: protected String instanceId = null;
078:
079: protected IRuntimeContext context;
080:
081: protected String urlTemplate = null;
082:
083: protected List outerParamNames = new ArrayList();
084:
085: protected String paramName; // Assumes 1 parameter subclasses may need more
086:
087: protected static int chartCount = 0;
088:
089: protected static Log logger = null;
090:
091: public AbstractChartComponent(String definitionPath, int width,
092: int height, IPentahoUrlFactory urlFactory, List messages) {
093: this (urlFactory, messages);
094: this .definitionPath = definitionPath;
095: this .width = width;
096: this .height = height;
097: PentahoSystem.ActionInfo info = PentahoSystem
098: .parseActionString(definitionPath);
099: if (info != null) {
100: setSourcePath(info.getSolutionName() + File.separator
101: + info.getPath());
102: }
103: }
104:
105: /**
106: * @param definitionPath
107: * @param urlFactory
108: * @param messages
109: */
110: public AbstractChartComponent(String definitionPath,
111: IPentahoUrlFactory urlFactory, ArrayList messages) {
112: this (urlFactory, messages);
113: this .definitionPath = definitionPath;
114: PentahoSystem.ActionInfo info = PentahoSystem
115: .parseActionString(definitionPath);
116: if (info != null) {
117: setSourcePath(info.getSolutionName() + File.separator
118: + info.getPath());
119: }
120: }
121:
122: public AbstractChartComponent(IPentahoUrlFactory urlFactory,
123: List messages) {
124: super (urlFactory, messages, null);
125: setXsl("text/html", "Chart.xsl"); //$NON-NLS-1$ //$NON-NLS-2$
126: logger = LogFactory.getLog(this .getClass());
127: }
128:
129: /**
130: * @param chartDefinition
131: * String that represents a file in the solution to create the
132: * chart from.
133: * @return
134: */
135: public abstract boolean setDataAction(String chartDefinition);
136:
137: /**
138: * Sets the action to be executed to get the data for the pies
139: *
140: * @param solution
141: * @param actionPath
142: * @param actionName
143: * @param actionOutput
144: */
145: public void setDataAction(String solution, String actionPath,
146: String actionName, String actionOutput) {
147: this .solution = solution;
148: this .actionPath = actionPath;
149: this .actionName = actionName;
150: this .actionOutput = actionOutput;
151: }
152:
153: /**
154: * Gets a IPentahoResultSet from the action output
155: *
156: * @return IPentahoResultSet
157: */
158: public IPentahoResultSet getActionData() {
159: // create an instance of the solution engine to execute the specified
160: // action
161:
162: ISolutionEngine solutionEngine = PentahoSystem
163: .getSolutionEngineInstance(getSession());
164: solutionEngine.setLoggingLevel(ILogger.DEBUG);
165: solutionEngine.init(getSession());
166:
167: HashMap parameterProviders = getParameterProviders();
168:
169: OutputStream outputStream = null;
170: SimpleOutputHandler outputHandler = null;
171: outputHandler = new SimpleOutputHandler(outputStream, false);
172:
173: ArrayList messages = new ArrayList();
174: String processId = this .getClass().getName();
175: context = solutionEngine.execute(solution, actionPath,
176: actionName, processId, false, true, instanceId, false,
177: parameterProviders, outputHandler, null, urlFactory,
178: messages);
179:
180: if (context == null) {
181: // this went badly wrong
182: return null;
183: }
184:
185: if (actionOutput != null) {
186: if (context.getOutputNames().contains(actionOutput)) {
187: IActionParameter output = context
188: .getOutputParameter(actionOutput);
189: IPentahoResultSet results = output
190: .getValueAsResultSet();
191: if (results != null) {
192: results = results.memoryCopy();
193: }
194: return results;
195: } else {
196: // this is an error
197: return null;
198: }
199: } else {
200: Iterator it = context.getOutputNames().iterator();
201: while (it.hasNext()) {
202: IActionParameter output = (IActionParameter) it.next();
203: if (output.getType().equalsIgnoreCase(
204: IActionParameter.TYPE_RESULT_SET)) {
205: IPentahoResultSet results = output
206: .getValueAsResultSet();
207: if (results != null) {
208: results = results.memoryCopy();
209: }
210: return results;
211: }
212: }
213: }
214: return null;
215: }
216:
217: public Log getLogger() {
218: return logger;
219: }
220:
221: /**
222: * @return String that represents the file path to a temporary file
223: */
224: protected String[] createTempFile() {
225: // create temporary file names
226: String solutionDir = "system/tmp/"; //$NON-NLS-1$
227: String fileNamePrefix = "tmp_chart_"; //$NON-NLS-1$
228: String extension = ".png"; //$NON-NLS-1$
229: String fileName = null;
230: String filePathWithoutExtension = null;
231: try {
232: File file = File.createTempFile(fileNamePrefix, extension,
233: new File(PentahoSystem.getApplicationContext()
234: .getFileOutputPath(solutionDir)));
235: file.deleteOnExit();
236: fileName = file.getName();
237: filePathWithoutExtension = solutionDir
238: + fileName.substring(0, fileName.indexOf('.'));
239: } catch (IOException e) {
240: getLogger()
241: .error(
242: Messages
243: .getErrorString("AbstractChartComponent.ERROR_0001_CANT_CREATE_TEMP_CHART"), e); //$NON-NLS-1$
244: }
245: String[] value = new String[2];
246: value[FILENAME_INDEX] = fileName;
247: value[FILENAME_WITHOUT_EXTENSION_INDEX] = filePathWithoutExtension;
248:
249: return value;
250: }
251:
252: protected void applyOuterURLTemplateParam() {
253: if (outerParamNames == null) {
254: return;
255: }
256: Iterator iter = outerParamNames.iterator();
257: while (iter.hasNext()) {
258: String outerParamName = iter.next().toString();
259: Object value = null;
260: if (context != null
261: && context.getInputNames().contains(outerParamName)) {
262: value = context.getInputParameterValue(outerParamName);
263: }
264: if (value == null) {
265: return;
266: }
267: try {
268: if (value.getClass().isArray()) {
269: if (Array.getLength(value) > 0) {
270: String[] encodedVals = new String[Array
271: .getLength(value)];
272: for (int i = 0; i < Array.getLength(value); ++i) {
273: encodedVals[i] = URLEncoder.encode(Array
274: .get(value, i).toString(),
275: LocaleHelper.getSystemEncoding());
276: }
277: // TODO Sleeze Alert!!! This is a temporary hack for making the
278: // URLs generated support multiple selections. A JIRA case PLATFORM-393
279: // has been generated to address this issue.
280: //
281: // For now, applyTemplate looks for an "&" or "?" preceding and following the param, uses all
282: // the characters between them as the template and repeats it once for each param value
283: // separating them with '&'
284: urlTemplate = TemplateUtil.applyTemplate(
285: urlTemplate, outerParamName,
286: encodedVals);
287: }
288: } else {
289: String encodedVal = URLEncoder.encode(value
290: .toString(), LocaleHelper
291: .getSystemEncoding());
292: urlTemplate = TemplateUtil.applyTemplate(
293: urlTemplate, outerParamName, encodedVal);
294: }
295:
296: //encodedVal = URLEncoder.encode(stringVal, LocaleHelper.getSystemEncoding()); //$NON-NLS-1$
297: } catch (UnsupportedEncodingException e) {
298: getLogger()
299: .error(
300: Messages
301: .getErrorString("AbstractChartComponent.ERROR_0002_URL_ENCODE_FAILED"), e); //$NON-NLS-1$
302: }
303: }
304: }
305:
306: /**
307: *
308: */
309: public void dispose() {
310: if (context != null)
311: context.dispose();
312: }
313:
314: /**
315: * @return Returns the actionName.
316: */
317: public String getActionName() {
318: return actionName;
319: }
320:
321: /**
322: * @param actionName
323: * The actionName to set.
324: */
325: public void setActionName(String actionName) {
326: this .actionName = actionName;
327: }
328:
329: /**
330: * @return Returns the actionOutput.
331: */
332: public String getActionOutput() {
333: return actionOutput;
334: }
335:
336: /**
337: * @param actionOutput
338: * The actionOutput to set.
339: */
340: public void setActionOutput(String actionOutput) {
341: this .actionOutput = actionOutput;
342: }
343:
344: /**
345: * @return Returns the actionPath.
346: */
347: public String getActionPath() {
348: return actionPath;
349: }
350:
351: /**
352: * @param actionPath
353: * The actionPath to set.
354: */
355: public void setActionPath(String actionPath) {
356: this .actionPath = actionPath;
357: }
358:
359: /**
360: * @return Returns the context.
361: */
362: public IRuntimeContext getContext() {
363: return context;
364: }
365:
366: /**
367: * @param context
368: * The context to set.
369: */
370: public void setContext(IRuntimeContext context) {
371: this .context = context;
372: }
373:
374: /**
375: * @return Returns the definitionPath.
376: */
377: public String getDefinitionPath() {
378: return definitionPath;
379: }
380:
381: /**
382: * @param definitionPath
383: * The definitionPath to set.
384: */
385: public void setDefinitionPath(String definitionPath) {
386: this .definitionPath = definitionPath;
387: }
388:
389: /**
390: * @return Returns the height.
391: */
392: public int getHeight() {
393: return height;
394: }
395:
396: /**
397: * @param height
398: * The height to set.
399: */
400: public void setHeight(int height) {
401: this .height = height;
402: }
403:
404: /**
405: * @return Returns the instanceId.
406: */
407: public String getInstanceId() {
408: return instanceId;
409: }
410:
411: /**
412: * @param instanceId
413: * The instanceId to set.
414: */
415: public void setInstanceId(String instanceId) {
416: this .instanceId = instanceId;
417: }
418:
419: /**
420: * @return Returns the solution.
421: */
422: public String getSolution() {
423: return solution;
424: }
425:
426: /**
427: * @param solution
428: * The solution to set.
429: */
430: public void setSolution(String solution) {
431: this .solution = solution;
432: }
433:
434: /**
435: * @return Returns the title.
436: */
437: public String getTitle() {
438: return title;
439: }
440:
441: /**
442: * @param title
443: * The title to set.
444: */
445: public void setTitle(String title) {
446: this .title = title;
447: }
448:
449: /**
450: * @return Returns the urlTemplate.
451: */
452: public String getUrlTemplate() {
453: return urlTemplate;
454: }
455:
456: /**
457: * @param urlTemplate
458: * The urlTemplate to set.
459: */
460: public void setUrlTemplate(String urlTemplate) {
461: this .urlTemplate = urlTemplate;
462: }
463:
464: /**
465: * @return Returns the values.
466: */
467: public Object getValues() {
468: return values;
469: }
470:
471: /**
472: * @param values
473: * The values to set.
474: */
475: public void setValues(Object values) {
476: this .values = values;
477: }
478:
479: /**
480: * @return Returns the width.
481: */
482: public int getWidth() {
483: return width;
484: }
485:
486: /**
487: * @param width
488: * The width to set.
489: */
490: public void setWidth(int width) {
491: this .width = width;
492: }
493:
494: /**
495: * @param logger
496: * The logger to set.
497: */
498: public void setLogger(Log logger) {
499: AbstractChartComponent.logger = logger;
500: }
501:
502: /**
503: * @return Returns the byRow.
504: */
505: public boolean isByRow() {
506: return byRow;
507: }
508:
509: /**
510: * @param byRow
511: * The byRow to set.
512: */
513: public void setByRow(boolean byRow) {
514: this .byRow = byRow;
515: }
516:
517: /**
518: * @return Returns the paramName.
519: */
520: public String getParamName() {
521: return paramName;
522: }
523:
524: /**
525: * @param paramName
526: * The paramName to set.
527: */
528: public void setParamName(String paramName) {
529: this .paramName = paramName;
530: }
531:
532: /**
533: * @return Returns the outerParamNames.
534: */
535: public List getOuterParamNames() {
536: return outerParamNames;
537: }
538:
539: /**
540: * @param outerParamName
541: * The outerParamNames name to add to the outParamNames list.
542: */
543: public void addOuterParamName(String outerParamName) {
544: outerParamNames.add(outerParamName);
545: }
546:
547: }
|