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 William Seyler
015: */
016: package org.pentaho.plugin.jfreechart;
017:
018: import java.io.BufferedWriter;
019: import java.io.File;
020: import java.io.FileWriter;
021: import java.io.IOException;
022: import java.io.OutputStream;
023: import java.io.PrintWriter;
024: import java.io.StringWriter;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Set;
028:
029: import org.apache.commons.logging.Log;
030: import org.apache.commons.logging.LogFactory;
031: import org.dom4j.Element;
032: import org.dom4j.Node;
033: import org.jfree.chart.ChartRenderingInfo;
034: import org.jfree.chart.ChartUtilities;
035: import org.jfree.chart.JFreeChart;
036: import org.jfree.chart.entity.StandardEntityCollection;
037: import org.jfree.chart.imagemap.ImageMapUtilities;
038: import org.jfree.chart.imagemap.StandardToolTipTagFragmentGenerator;
039: import org.jfree.data.general.Dataset;
040: import org.pentaho.commons.connection.IPentahoResultSet;
041: import org.pentaho.core.repository.IContentItem;
042: import org.pentaho.core.solution.IActionResource;
043: import org.pentaho.core.system.PentahoSystem;
044: import org.pentaho.core.util.XmlHelper;
045: import org.pentaho.messages.Messages;
046: import org.pentaho.plugin.ComponentBase;
047:
048: public class ChartComponent extends ComponentBase {
049: private static final long serialVersionUID = 9050456842938084174L;
050:
051: private static final String CHART_NAME_PROP = "chart-name"; //$NON-NLS-1$
052:
053: private static final String CHART_OUTPUT = "chart-object"; //$NON-NLS-1$
054:
055: private static final String CHART_TYPE = "CHART-OBJECT"; //$NON-NLS-1$
056:
057: private static final String CHART_DATA_PROP = "chart-data"; //$NON-NLS-1$
058:
059: // Root xml tag for chart attributes when chart is generated via an action sequence
060: private static final String CHART_ATTRIBUTES_PROP = "chart-attributes"; //$NON-NLS-1$
061:
062: // This member added for compatibility to dashboard chart definitions
063: // Root xml tag for chart attributes when chart is generated via a dashboard
064: private static final String ALTERNATIVE_CHART_ATTRIBUTES_PROP = "chart"; //$NON-NLS-1$
065:
066: private static final String BY_ROW_PROP = "by-row"; //$NON-NLS-1$
067:
068: private static final String URL_TEMPLATE = "url-template"; //$NON-NLS-1$
069:
070: private static final String PARAMETER_NAME = "paramName"; //$NON-NLS-1$
071:
072: private static final String OUTER_PARAMETER_NAME = "series-name"; //$NON-NLS-1$
073:
074: private static final String OUTPUT_TYPE_PROP = "output-type"; //$NON-NLS-1$
075:
076: private static final String CHART_FILE_NAME_OUTPUT = "chart-filename"; //$NON-NLS-1$
077:
078: private static final String HTML_MAPPING_OUTPUT = "chart-mapping"; //$NON-NLS-1$
079:
080: private static final String HTML_MAPPING_HTML = "chart-map-html"; //$NON-NLS-1$
081:
082: private static final String BASE_URL_OUTPUT = "base-url"; //$NON-NLS-1$
083:
084: private static final String HTML_IMG_TAG = "image-tag"; //$NON-NLS-1$
085:
086: private static final String SVG_TYPE = "SVG"; //$NON-NLS-1$
087:
088: private static final String PNG_BYTES_TYPE = "png-bytes"; //$NON-NLS-1$
089:
090: private static final String TEMP_DIRECTORY = "system/tmp/"; //$NON-NLS-1$
091:
092: private static final String FILENAME_PREFIX = "tmp_chart_"; //$NON-NLS-1$
093:
094: private static final String USE_BASE_URL_TAG = "use-base-url"; //$NON-NLS-1$
095:
096: private static final String URL_TARGET_TAG = "url-target"; //$NON-NLS-1$
097:
098: private static final String PNG_EXTENSION = ".png"; //$NON-NLS-1$
099:
100: private static final String SVG_EXTENSION = ".svg"; //$NON-NLS-1$
101:
102: private static final String MAP_EXTENSION = ".map"; //$NON-NLS-1$
103:
104: private static final int FILE_NAME = 0;
105:
106: private static final int MAP_NAME = 1;
107:
108: public Log getLogger() {
109: return LogFactory.getLog(ChartComponent.class);
110: }
111:
112: protected boolean validateSystemSettings() {
113: // This component does not have any system settings to validate
114: return true;
115: }
116:
117: protected boolean validateAction() {
118: // See if we have chart data
119: if (!isDefinedInput(CHART_DATA_PROP)) {
120: inputMissingError(CHART_DATA_PROP);
121: return false;
122: }
123: // See if we have chart attributes
124: if (!isDefinedInput(CHART_ATTRIBUTES_PROP)) {
125: if (!isDefinedResource(CHART_ATTRIBUTES_PROP)) {
126: inputMissingError(CHART_ATTRIBUTES_PROP);
127: return false;
128: }
129: }
130:
131: // Anything else should be optional
132: return true;
133: }
134:
135: public void done() {
136: }
137:
138: protected boolean executeAction() {
139: int height = -1;
140: int width = -1;
141: String title = "";//$NON-NLS-1$
142:
143: IPentahoResultSet data = (IPentahoResultSet) getInputValue(CHART_DATA_PROP);
144: String urlTemplate = (String) getInputValue(URL_TEMPLATE);
145:
146: Node chartAttributes = null;
147: String chartAttributeString = null;
148:
149: // Attempt to get chart attributes as an input string or as a resource file
150: // If these don't trip, then we assume the chart attributes are defined in
151: // the component-definition of the chart action.
152:
153: if (getInputNames().contains(CHART_ATTRIBUTES_PROP)) {
154: chartAttributeString = getInputStringValue(CHART_ATTRIBUTES_PROP);
155: } else if (isDefinedResource(CHART_ATTRIBUTES_PROP)) {
156: IActionResource resource = getResource(CHART_ATTRIBUTES_PROP);
157: chartAttributeString = getResourceAsString(resource);
158: }
159:
160: // Realize chart attributes as an XML document
161: if (chartAttributeString != null) {
162:
163: Node chartDocument = XmlHelper
164: .getDocFromString(chartAttributeString);
165: chartAttributes = chartDocument
166: .selectSingleNode(CHART_ATTRIBUTES_PROP);
167:
168: // This line of code handles a discrepancy between the schema of a chart definition
169: // handed to a dashboard versus a ChartComponent schema. The top level node for the dashboard charts
170: // is <chart>, whereas the ChartComponent expects <chart-attributes>.
171:
172: // TODO:
173: // This discrepancy should be resolved when we have ONE chart solution.
174:
175: if (chartAttributes == null) {
176: chartAttributes = chartDocument
177: .selectSingleNode(ALTERNATIVE_CHART_ATTRIBUTES_PROP);
178: }
179: }
180:
181: // Default chart attributes are in the component-definition section of the action definition.
182: if (chartAttributes == null) {
183: chartAttributes = getComponentDefinition(true)
184: .selectSingleNode(CHART_ATTRIBUTES_PROP);
185: }
186:
187: // URL click-through attributes (useBaseURL, target) are only processed IF we
188: // have an urlTemplate attribute
189: if (urlTemplate == null || urlTemplate.length() == 0) {
190: if (chartAttributes.selectSingleNode(URL_TEMPLATE) != null) {
191: urlTemplate = chartAttributes.selectSingleNode(
192: URL_TEMPLATE).getText();
193: }
194: }
195:
196: // These parameters are replacement variables parsed into the
197: // urlTemplate specifically when we have a URL that is a drill-through
198: // link in a chart intended to drill down into the chart data.
199: String parameterName = (String) getInputValue(PARAMETER_NAME);
200: if (parameterName == null || parameterName.length() == 0) {
201: if (chartAttributes.selectSingleNode(PARAMETER_NAME) != null) {
202: parameterName = chartAttributes.selectSingleNode(
203: PARAMETER_NAME).getText();
204: }
205: }
206:
207: // These parameters are replacement variables parsed into the
208: // urlTemplate specifically when we have a URL that is a drill-through
209: // link in a chart intended to drill down into the chart data.
210: String outerParameterName = (String) getInputValue(OUTER_PARAMETER_NAME);
211: if (outerParameterName == null
212: || outerParameterName.length() == 0) {
213: if (chartAttributes.selectSingleNode(OUTER_PARAMETER_NAME) != null) {
214: outerParameterName = chartAttributes.selectSingleNode(
215: OUTER_PARAMETER_NAME).getText();
216: }
217: }
218:
219: String chartType = chartAttributes.selectSingleNode(
220: ChartDefinition.TYPE_NODE_NAME).getText();
221:
222: // --------------- This code allows inputs to override the chartAttributes
223: // of width, height, and title
224: Object widthObj = getInputValue(ChartDefinition.WIDTH_NODE_NAME);
225: if (widthObj != null) {
226: width = Integer.parseInt(widthObj.toString());
227: if (width != -1) {
228: if (chartAttributes
229: .selectSingleNode(ChartDefinition.WIDTH_NODE_NAME) == null) {
230: ((Element) chartAttributes)
231: .addElement(ChartDefinition.WIDTH_NODE_NAME);
232: }
233: chartAttributes.selectSingleNode(
234: ChartDefinition.WIDTH_NODE_NAME).setText(
235: Integer.toString(width));
236: }
237: }
238: Object heightObj = getInputValue(ChartDefinition.HEIGHT_NODE_NAME);
239: if (heightObj != null) {
240: height = Integer.parseInt(heightObj.toString());
241: if (height != -1) {
242: if (chartAttributes
243: .selectSingleNode(ChartDefinition.HEIGHT_NODE_NAME) == null) {
244: ((Element) chartAttributes)
245: .addElement(ChartDefinition.HEIGHT_NODE_NAME);
246: }
247: chartAttributes.selectSingleNode(
248: ChartDefinition.HEIGHT_NODE_NAME).setText(
249: Integer.toString(height));
250: }
251: }
252: Object titleObj = getInputValue(ChartDefinition.TITLE_NODE_NAME);
253: if (titleObj != null) {
254: if (chartAttributes
255: .selectSingleNode(ChartDefinition.TITLE_NODE_NAME) == null) {
256: ((Element) chartAttributes)
257: .addElement(ChartDefinition.TITLE_NODE_NAME);
258: }
259: chartAttributes.selectSingleNode(
260: ChartDefinition.TITLE_NODE_NAME).setText(
261: titleObj.toString());
262: }
263: // ----------------End of Override
264:
265: // ---------------Feed the Title and Subtitle information through the input substitution
266: Node titleNode = chartAttributes
267: .selectSingleNode(ChartDefinition.TITLE_NODE_NAME);
268: if (titleNode != null) {
269: String titleStr = titleNode.getText();
270: if (titleStr != null) {
271: title = titleStr;
272: String newTitle = applyInputsToFormat(titleStr);
273: titleNode.setText(newTitle);
274: }
275: }
276:
277: List subtitles = chartAttributes
278: .selectNodes(ChartDefinition.SUBTITLE_NODE_NAME);
279:
280: if ((subtitles == null) || (subtitles.isEmpty())) {
281: Node subTitlesNode = chartAttributes
282: .selectSingleNode(ChartDefinition.SUBTITLES_NODE_NAME);
283: if (subTitlesNode != null) {
284: subtitles = chartAttributes
285: .selectNodes(ChartDefinition.SUBTITLE_NODE_NAME);
286: }
287: } else {
288: // log a deprecation warning for this property...
289: getLogger()
290: .warn(
291: Messages
292: .getString(
293: "CHART.WARN_DEPRECATED_CHILD", ChartDefinition.SUBTITLE_NODE_NAME, ChartDefinition.SUBTITLES_NODE_NAME));//$NON-NLS-1$
294: getLogger()
295: .warn(
296: Messages
297: .getString(
298: "CHART.WARN_PROPERTY_WILL_NOT_VALIDATE", ChartDefinition.SUBTITLE_NODE_NAME));//$NON-NLS-1$
299: }
300:
301: if (subtitles != null) {
302: for (Iterator iter = subtitles.iterator(); iter.hasNext();) {
303: Node subtitleNode = (Node) iter.next();
304: if (subtitleNode != null) {
305: String subtitleStr = subtitleNode.getText();
306: if (subtitleStr != null) {
307: String newSubtitle = applyInputsToFormat(subtitleStr);
308: subtitleNode.setText(newSubtitle);
309: }
310: }
311: }
312: }
313:
314: //----------------End of Format
315:
316: // Determine if we are going to read the chart data set by row or by column
317: boolean byRow = false;
318: if (getInputStringValue(BY_ROW_PROP) != null) {
319: byRow = Boolean.valueOf(getInputStringValue(BY_ROW_PROP))
320: .booleanValue();
321: }
322:
323: // TODO Figure out why these overrides are called here. Seems like we are doing the same thing we just did above, but
324: // could possibly step on the height and width values set previously.
325:
326: if (height == -1) {
327: height = (int) getInputLongValue(CHART_ATTRIBUTES_PROP
328: + "/" + ChartDefinition.HEIGHT_NODE_NAME, 50); //$NON-NLS-1$
329: }
330: if (width == -1) {
331: width = (int) getInputLongValue(CHART_ATTRIBUTES_PROP
332: + "/" + ChartDefinition.WIDTH_NODE_NAME, 100); //$NON-NLS-1$
333: }
334:
335: if (title.length() <= 0)
336: title = getInputStringValue(CHART_ATTRIBUTES_PROP
337: + "/" + ChartDefinition.TITLE_NODE_NAME); //$NON-NLS-1$
338:
339: // Select the right dataset to use based on the chart type
340: // Default to category dataset
341: String datasetType = ChartDefinition.CATAGORY_DATASET_STR;
342: boolean isStacked = false;
343: Node datasetTypeNode = chartAttributes
344: .selectSingleNode(ChartDefinition.DATASET_TYPE_NODE_NAME);
345: if (datasetTypeNode != null) {
346: datasetType = datasetTypeNode.getText();
347: }
348: Dataset dataDefinition = null;
349: if (ChartDefinition.XY_SERIES_COLLECTION_STR
350: .equalsIgnoreCase(datasetType)) {
351: dataDefinition = new XYSeriesCollectionChartDefinition(
352: data, byRow, chartAttributes, getSession());
353: } else if (ChartDefinition.TIME_SERIES_COLLECTION_STR
354: .equalsIgnoreCase(datasetType)) {
355:
356: Node stackedNode = chartAttributes
357: .selectSingleNode(ChartDefinition.STACKED_NODE_NAME);
358: if (stackedNode != null) {
359: isStacked = Boolean.valueOf(stackedNode.getText())
360: .booleanValue();
361: }
362: if ((isStacked)
363: && (ChartDefinition.AREA_CHART_STR
364: .equalsIgnoreCase(chartType))) {
365: dataDefinition = new TimeTableXYDatasetChartDefinition(
366: data, byRow, chartAttributes, getSession());
367: } else {
368: dataDefinition = new TimeSeriesCollectionChartDefinition(
369: data, byRow, chartAttributes, getSession());
370: }
371: } else if (ChartDefinition.PIE_CHART_STR
372: .equalsIgnoreCase(chartType)) {
373: dataDefinition = new PieDatasetChartDefinition(data, byRow,
374: chartAttributes, getSession());
375: } else if (ChartDefinition.DIAL_CHART_STR
376: .equalsIgnoreCase(chartType)) {
377: dataDefinition = new DialWidgetDefinition(data, byRow,
378: chartAttributes, width, height, getSession());
379: } else if (ChartDefinition.BAR_LINE_CHART_STR
380: .equalsIgnoreCase(chartType)) {
381: dataDefinition = new BarLineChartDefinition(data, byRow,
382: chartAttributes, getSession());
383: } else if (ChartDefinition.BUBBLE_CHART_STR
384: .equalsIgnoreCase(chartType)) {
385: dataDefinition = new XYZSeriesCollectionChartDefinition(
386: data, byRow, chartAttributes, getSession());
387: } else {
388: dataDefinition = new CategoryDatasetChartDefinition(data,
389: byRow, chartAttributes, getSession());
390: }
391:
392: // Determine what we are sending back - Default to OUTPUT_PNG output
393: // OUTPUT_PNG = the chart gets written to a file in .png format
394: // OUTPUT_SVG = the chart gets written to a file in .svg (XML) format
395: // OUTPUT_CHART = the chart in a byte stream gets stored as as an IContentItem
396: // OUTPUT_PNG_BYTES = the chart gets sent as a byte stream in .png format
397:
398: int outputType = JFreeChartEngine.OUTPUT_PNG;
399:
400: if (getInputStringValue(OUTPUT_TYPE_PROP) != null) {
401: if (SVG_TYPE
402: .equalsIgnoreCase(getInputStringValue(OUTPUT_TYPE_PROP))) {
403: outputType = JFreeChartEngine.OUTPUT_SVG;
404: } else if (CHART_TYPE
405: .equalsIgnoreCase(getInputStringValue(OUTPUT_TYPE_PROP))) {
406: outputType = JFreeChartEngine.OUTPUT_CHART;
407: } else if (PNG_BYTES_TYPE
408: .equalsIgnoreCase(getInputStringValue(OUTPUT_TYPE_PROP))) {
409: outputType = JFreeChartEngine.OUTPUT_PNG_BYTES;
410: }
411: }
412:
413: JFreeChart chart = null;
414:
415: switch (outputType) {
416:
417: /**************************** OUTPUT_PNG_BYTES *********************************************/
418: case JFreeChartEngine.OUTPUT_PNG_BYTES:
419:
420: chart = JFreeChartEngine.getChart(dataDefinition, title,
421: "", width, height, this ); //$NON-NLS-1$
422:
423: // TODO Shouldn't the mime types and other strings here be constant somewhere? Where do we
424: // put this type of general info ?
425:
426: String mimeType = "image/png"; //$NON-NLS-1$
427: IContentItem contentItem = getOutputItem(
428: "chartdata", mimeType, ".png"); //$NON-NLS-1$ //$NON-NLS-2$
429: contentItem.setMimeType(mimeType);
430: try {
431:
432: OutputStream output = contentItem
433: .getOutputStream(getActionName());
434: ChartUtilities.writeChartAsPNG(output, chart, width,
435: height);
436:
437: } catch (Exception e) {
438: error(
439: Messages
440: .getErrorString("ChartComponent.ERROR_0004_CANT_CREATE_IMAGE"), e); //$NON-NLS-1$
441: return false;
442: }
443:
444: break;
445:
446: /**************************** OUTPUT_SVG && OUTPUT_PNG *************************************/
447: case JFreeChartEngine.OUTPUT_SVG:
448: // intentionally fall through to PNG
449:
450: case JFreeChartEngine.OUTPUT_PNG:
451:
452: // Don't include the map in a file if HTML_MAPPING_HTML is specified, as that
453: // param sends the map back on the outputstream as a string
454: boolean includeMapFile = !isDefinedOutput(HTML_MAPPING_HTML);
455:
456: File[] fileResults = createTempFile(outputType,
457: includeMapFile);
458:
459: if (fileResults == null) {
460: error(Messages
461: .getErrorString("ChartComponent.ERROR_0003_CANT_CREATE_TEMP_FILES")); //$NON-NLS-1$
462: return false;
463: }
464:
465: String chartId = fileResults[FILE_NAME].getName()
466: .substring(
467: 0,
468: fileResults[FILE_NAME].getName().indexOf(
469: '.'));
470: String filePathWithoutExtension = TEMP_DIRECTORY + chartId;
471: PrintWriter printWriter = new PrintWriter(
472: new StringWriter());
473: ChartRenderingInfo info = new ChartRenderingInfo(
474: new StandardEntityCollection());
475:
476: JFreeChartEngine
477: .saveChart(
478: dataDefinition,
479: title,
480: "", filePathWithoutExtension, width, height, outputType, printWriter, info, this ); //$NON-NLS-1$
481:
482: //Creating the image map
483: boolean useBaseUrl = true;
484: String urlTarget = "pentaho_popup"; //$NON-NLS-1$
485:
486: // Prepend the base url to the front of every drill through link
487: if (chartAttributes.selectSingleNode(USE_BASE_URL_TAG) != null) {
488: Boolean booleanValue = new Boolean(chartAttributes
489: .selectSingleNode(USE_BASE_URL_TAG).getText());
490: useBaseUrl = booleanValue.booleanValue();
491: }
492:
493: // What target for link? _parent, _blank, etc.
494: if (chartAttributes.selectSingleNode(URL_TARGET_TAG) != null) {
495: urlTarget = chartAttributes.selectSingleNode(
496: URL_TARGET_TAG).getText();
497: }
498:
499: String mapString = null;
500: if (includeMapFile) {
501: try {
502: String mapId = fileResults[MAP_NAME].getName()
503: .substring(
504: 0,
505: fileResults[MAP_NAME].getName()
506: .indexOf('.'));
507: mapString = ImageMapUtilities.getImageMap(mapId,
508: info,
509: new StandardToolTipTagFragmentGenerator(),
510: new PentahoChartURLTagFragmentGenerator(
511: urlTemplate, urlTarget, useBaseUrl,
512: dataDefinition, parameterName,
513: outerParameterName));
514:
515: BufferedWriter out = new BufferedWriter(
516: new FileWriter(fileResults[MAP_NAME]));
517: out.write(mapString);
518: out.flush();
519: out.close();
520: } catch (IOException e) {
521: error(Messages
522: .getErrorString(
523: "ChartComponent.ERROR_0001_CANT_WRITE_MAP", fileResults[MAP_NAME].getPath())); //$NON-NLS-1$
524: return false;
525: } catch (Exception e) {
526: error(e.getLocalizedMessage(), e);
527: return false;
528: }
529: }
530:
531: /*******************************************************************************************************
532: * Legitimate outputs for the ChartComponent in an action sequence:
533: *
534: * CHART_OUTPUT (chart-output)
535: * Stores the chart in the content repository as an IContentItem.
536: *
537: * CHART_FILE_NAME_OUTPUT (chart-filename)
538: * Returns the name of the chart file, including the file extension (with no path information)
539: * as a String.
540: *
541: * HTML_MAPPING_OUTPUT (chart-mapping)
542: * Returns the name of the file that the map has been saved to, including the file extension
543: * (with no path information) as a String.
544: *
545: * HTML_MAPPING_HTML (chart-map-html)
546: * Returns the chart image map HTML as a String.
547: *
548: * BASE_URL_OUTPUT (base-url)
549: * Returns the web app's base URL (ie., http://localhost:8080/pentaho) as a String.
550: *
551: * HTML_IMG_TAG (image-tag)
552: * Returns the HTML snippet including the image map, image (<IMG />) tag for the chart image
553: * with src, width, height and usemap attributes defined.
554: *
555: *******************************************************************************************************/
556:
557: // Now set the outputs
558: Set outputs = getOutputNames();
559:
560: if (outputs != null && outputs.size() > 0) {
561:
562: Iterator iter = outputs.iterator();
563: while (iter.hasNext()) {
564:
565: String outputName = (String) iter.next();
566: String outputValue = null;
567:
568: if (outputName.equals(CHART_FILE_NAME_OUTPUT)) {
569:
570: outputValue = fileResults[FILE_NAME].getName();
571:
572: } else if (outputName.equals(HTML_MAPPING_OUTPUT)) {
573:
574: outputValue = fileResults[MAP_NAME].getName();
575:
576: } else if (outputName.equals(HTML_MAPPING_HTML)) {
577:
578: outputValue = mapString;
579:
580: } else if (outputName.equals(BASE_URL_OUTPUT)) {
581:
582: outputValue = PentahoSystem
583: .getApplicationContext().getBaseUrl();
584:
585: } else if (outputName.equals(HTML_IMG_TAG)) {
586:
587: outputValue = mapString;
588:
589: outputValue += "<img border=\"0\" "; //$NON-NLS-1$
590: outputValue += "width=\"" + width + "\" "; //$NON-NLS-1$//$NON-NLS-2$
591: outputValue += "height=\"" + height + "\" "; //$NON-NLS-1$//$NON-NLS-2$
592: outputValue += "usemap=\"#" + fileResults[MAP_NAME].getName().substring(0, fileResults[MAP_NAME].getName().indexOf('.')) + "\" "; //$NON-NLS-1$//$NON-NLS-2$
593: outputValue += "src=\"" + PentahoSystem.getApplicationContext().getBaseUrl() + "getImage?image=" + fileResults[FILE_NAME].getName() + "\"/>"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
594:
595: }
596:
597: if (outputValue != null) {
598: setOutputValue(outputName, outputValue);
599: }
600: }
601: }
602:
603: break;
604:
605: /************************** OUTPUT_CHART && DEFAULT *************************************/
606: case JFreeChartEngine.OUTPUT_CHART:
607: // intentionally fall through to default
608:
609: default:
610:
611: String chartName = CHART_OUTPUT;
612: if (isDefinedInput(CHART_NAME_PROP)) {
613: chartName = getInputStringValue(CHART_NAME_PROP);
614: }
615: chart = JFreeChartEngine.getChart(dataDefinition, title,
616: "", width, height, this ); //$NON-NLS-1$
617: setOutputValue(chartName, chart);
618:
619: break;
620: }
621:
622: return true;
623: }
624:
625: public boolean init() {
626: // nothing to do here really
627: return true;
628: }
629:
630: /**
631: * @return String that represents the file path to a temporary file
632: */
633: protected File[] createTempFile(int outputType,
634: boolean includeMapFile) {
635: File[] results;
636: if (includeMapFile) {
637: results = new File[2];
638: } else {
639: results = new File[1];
640: }
641:
642: String extension = outputType == JFreeChartEngine.OUTPUT_SVG ? SVG_EXTENSION
643: : PNG_EXTENSION;
644:
645: try {
646: File file = File.createTempFile(FILENAME_PREFIX, extension,
647: new File(PentahoSystem.getApplicationContext()
648: .getFileOutputPath(TEMP_DIRECTORY)));
649: file.deleteOnExit();
650: results[FILE_NAME] = file;
651: if (includeMapFile) {
652: file = File.createTempFile(FILENAME_PREFIX,
653: MAP_EXTENSION, new File(PentahoSystem
654: .getApplicationContext()
655: .getFileOutputPath(TEMP_DIRECTORY)));
656: file.deleteOnExit();
657: results[MAP_NAME] = file;
658: }
659: } catch (IOException e) {
660: return null;
661: }
662: return results;
663: }
664:
665: protected String getSolutionRelativePath(String fullPath) {
666: String prefix = PentahoSystem.getApplicationContext()
667: .getSolutionPath(""); //$NON-NLS-1$
668: // Next line was added for PLATFORM-828
669: prefix = prefix.replaceAll("\\\\", "\\\\\\\\"); //$NON-NLS-1$ //$NON-NLS-2$
670: String result = fullPath.replaceFirst(prefix, ""); //$NON-NLS-1$
671: return result;
672: }
673: }
|