/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.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 Lesser General Public License for more details. * * Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.platform.plugin.action.jfreechart; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.dom4j.Element; import org.dom4j.Node; import org.jfree.chart.ChartRenderingInfo; import org.jfree.chart.ChartUtilities; import org.jfree.chart.JFreeChart; import org.jfree.chart.entity.StandardEntityCollection; import org.jfree.chart.imagemap.ImageMapUtilities; import org.jfree.chart.imagemap.StandardToolTipTagFragmentGenerator; import org.jfree.data.general.Dataset; import org.pentaho.commons.connection.IPentahoResultSet; import org.pentaho.platform.api.engine.IActionSequenceResource; import org.pentaho.platform.api.engine.IApplicationContext; import org.pentaho.platform.api.engine.IPentahoRequestContext; import org.pentaho.platform.api.repository.IContentItem; import org.pentaho.platform.api.util.XmlParseException; import org.pentaho.platform.engine.core.system.PentahoRequestContextHolder; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.services.solution.ComponentBase; import org.pentaho.platform.engine.services.solution.PentahoEntityResolver; import org.pentaho.platform.plugin.action.messages.Messages; import org.pentaho.platform.uifoundation.chart.BarLineChartDefinition; import org.pentaho.platform.uifoundation.chart.CategoryDatasetChartDefinition; import org.pentaho.platform.uifoundation.chart.ChartDefinition; import org.pentaho.platform.uifoundation.chart.DialWidgetDefinition; import org.pentaho.platform.uifoundation.chart.JFreeChartEngine; import org.pentaho.platform.uifoundation.chart.PentahoChartURLTagFragmentGenerator; import org.pentaho.platform.uifoundation.chart.PieDatasetChartDefinition; import org.pentaho.platform.uifoundation.chart.TimeSeriesCollectionChartDefinition; import org.pentaho.platform.uifoundation.chart.TimeTableXYDatasetChartDefinition; import org.pentaho.platform.uifoundation.chart.XYSeriesCollectionChartDefinition; import org.pentaho.platform.uifoundation.chart.XYZSeriesCollectionChartDefinition; import org.pentaho.platform.util.xml.dom4j.XmlDom4JHelper; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Iterator; import java.util.List; import java.util.Set; public class ChartComponent extends ComponentBase { private static final long serialVersionUID = 9050456842938084174L; private static final String CHART_NAME_PROP = "chart-name"; //$NON-NLS-1$ private static final String CHART_OUTPUT = "chart-object"; //$NON-NLS-1$ private static final String CHART_TYPE = "CHART-OBJECT"; //$NON-NLS-1$ private static final String CHART_DATA_PROP = "chart-data"; //$NON-NLS-1$ // Root xml tag for chart attributes when chart is generated via an action sequence private static final String CHART_ATTRIBUTES_PROP = "chart-attributes"; //$NON-NLS-1$ // This member added for compatibility to dashboard chart definitions // Root xml tag for chart attributes when chart is generated via a dashboard private static final String ALTERNATIVE_CHART_ATTRIBUTES_PROP = "chart"; //$NON-NLS-1$ private static final String BY_ROW_PROP = "by-row"; //$NON-NLS-1$ private static final String URL_TEMPLATE = "url-template"; //$NON-NLS-1$ private static final String PARAMETER_NAME = "paramName"; //$NON-NLS-1$ private static final String OUTER_PARAMETER_NAME = "series-name"; //$NON-NLS-1$ private static final String OUTPUT_TYPE_PROP = "output-type"; //$NON-NLS-1$ private static final String CHART_FILE_NAME_OUTPUT = "chart-filename"; //$NON-NLS-1$ private static final String HTML_MAPPING_OUTPUT = "chart-mapping"; //$NON-NLS-1$ private static final String HTML_MAPPING_HTML = "chart-map-html"; //$NON-NLS-1$ private static final String BASE_URL_OUTPUT = "base-url"; //$NON-NLS-1$ private static final String CONTEXT_PATH_OUTPUT = "context-path"; //$NON-NLS-1$ private static final String FULLY_QUALIFIED_SERVER_URL_OUTPUT = "fully-qualified-server-url"; //$NON-NLS-1$ private static final String HTML_IMG_TAG = "image-tag"; //$NON-NLS-1$ private static final String SVG_TYPE = "SVG"; //$NON-NLS-1$ private static final String PNG_BYTES_TYPE = "png-bytes"; //$NON-NLS-1$ private static final String TEMP_DIRECTORY = "system/tmp/"; //$NON-NLS-1$ private static final String FILENAME_PREFIX = "tmp_chart_"; //$NON-NLS-1$ private static final String USE_BASE_URL_TAG = "use-base-url"; //$NON-NLS-1$ private static final String URL_TARGET_TAG = "url-target"; //$NON-NLS-1$ private static final String PNG_EXTENSION = ".png"; //$NON-NLS-1$ private static final String SVG_EXTENSION = ".svg"; //$NON-NLS-1$ private static final String MAP_EXTENSION = ".map"; //$NON-NLS-1$ private static final String KEEP_TEMP_FILE_PROP = "keep_temp_file"; //$NON-NLS-1$ private static final int FILE_NAME = 0; private static final int MAP_NAME = 1; public static final String FOREGROUND_ALPHA = "foreground-alpha"; //$NON-NLS-1$ public static final String BACKGROUND_ALPHA = "background-alpha"; //$NON-NLS-1$ @Override public Log getLogger() { return LogFactory.getLog( ChartComponent.class ); } @Override protected boolean validateSystemSettings() { // This component does not have any system settings to validate return true; } @Override protected boolean validateAction() { // See if we have chart data if ( !isDefinedInput( ChartComponent.CHART_DATA_PROP ) ) { inputMissingError( ChartComponent.CHART_DATA_PROP ); return false; } // See if we have chart attributes if ( !isDefinedInput( ChartComponent.CHART_ATTRIBUTES_PROP ) ) { if ( !isDefinedResource( ChartComponent.CHART_ATTRIBUTES_PROP ) ) { inputMissingError( ChartComponent.CHART_ATTRIBUTES_PROP ); return false; } } // Anything else should be optional return true; } @Override public void done() { } @Override protected boolean executeAction() { int height = -1; int width = -1; String title = ""; //$NON-NLS-1$ Node chartDocument = null; IPentahoResultSet data = (IPentahoResultSet) getInputValue( ChartComponent.CHART_DATA_PROP ); if ( !data.isScrollable() ) { getLogger().debug( "ResultSet is not scrollable. Copying into memory" ); //$NON-NLS-1$ IPentahoResultSet memSet = data.memoryCopy(); data.close(); data = memSet; } String urlTemplate = (String) getInputValue( ChartComponent.URL_TEMPLATE ); Node chartAttributes = null; String chartAttributeString = null; // Attempt to get chart attributes as an input string or as a resource file // If these don't trip, then we assume the chart attributes are defined in // the component-definition of the chart action. if ( getInputNames().contains( ChartComponent.CHART_ATTRIBUTES_PROP ) ) { chartAttributeString = getInputStringValue( ChartComponent.CHART_ATTRIBUTES_PROP ); } else if ( isDefinedResource( ChartComponent.CHART_ATTRIBUTES_PROP ) ) { IActionSequenceResource resource = getResource( ChartComponent.CHART_ATTRIBUTES_PROP ); chartAttributeString = getResourceAsString( resource ); } // Realize chart attributes as an XML document if ( chartAttributeString != null ) { try { chartDocument = XmlDom4JHelper.getDocFromString( chartAttributeString, new PentahoEntityResolver() ); } catch ( XmlParseException e ) { getLogger() .error( Messages.getInstance().getString( "ChartComponent.ERROR_0005_CANT_DOCUMENT_FROM_STRING" ), e ); //$NON-NLS-1$ return false; } chartAttributes = chartDocument.selectSingleNode( ChartComponent.CHART_ATTRIBUTES_PROP ); // This line of code handles a discrepancy between the schema of a chart definition // handed to a dashboard versus a ChartComponent schema. The top level node for the dashboard charts // is <chart>, whereas the ChartComponent expects <chart-attributes>. // TODO: // This discrepancy should be resolved when we have ONE chart solution. if ( chartAttributes == null ) { chartAttributes = chartDocument.selectSingleNode( ChartComponent.ALTERNATIVE_CHART_ATTRIBUTES_PROP ); } } // Default chart attributes are in the component-definition section of the action definition. if ( chartAttributes == null ) { chartAttributes = getComponentDefinition( true ).selectSingleNode( ChartComponent.CHART_ATTRIBUTES_PROP ); } // URL click-through attributes (useBaseURL, target) are only processed IF we // have an urlTemplate attribute if ( ( urlTemplate == null ) || ( urlTemplate.length() == 0 ) ) { if ( chartAttributes.selectSingleNode( ChartComponent.URL_TEMPLATE ) != null ) { urlTemplate = chartAttributes.selectSingleNode( ChartComponent.URL_TEMPLATE ).getText(); } } // These parameters are replacement variables parsed into the // urlTemplate specifically when we have a URL that is a drill-through // link in a chart intended to drill down into the chart data. String parameterName = (String) getInputValue( ChartComponent.PARAMETER_NAME ); if ( ( parameterName == null ) || ( parameterName.length() == 0 ) ) { if ( chartAttributes.selectSingleNode( ChartComponent.PARAMETER_NAME ) != null ) { parameterName = chartAttributes.selectSingleNode( ChartComponent.PARAMETER_NAME ).getText(); } } // These parameters are replacement variables parsed into the // urlTemplate specifically when we have a URL that is a drill-through // link in a chart intended to drill down into the chart data. String outerParameterName = (String) getInputValue( ChartComponent.OUTER_PARAMETER_NAME ); if ( ( outerParameterName == null ) || ( outerParameterName.length() == 0 ) ) { if ( chartAttributes.selectSingleNode( ChartComponent.OUTER_PARAMETER_NAME ) != null ) { outerParameterName = chartAttributes.selectSingleNode( ChartComponent.OUTER_PARAMETER_NAME ).getText(); } } String chartType = chartAttributes.selectSingleNode( ChartDefinition.TYPE_NODE_NAME ).getText(); // --------------- This code allows inputs to override the chartAttributes // of width, height, and title Object widthObj = getInputValue( ChartDefinition.WIDTH_NODE_NAME ); if ( widthObj != null ) { width = Integer.parseInt( widthObj.toString() ); if ( width != -1 ) { if ( chartAttributes.selectSingleNode( ChartDefinition.WIDTH_NODE_NAME ) == null ) { ( (Element) chartAttributes ).addElement( ChartDefinition.WIDTH_NODE_NAME ); } chartAttributes.selectSingleNode( ChartDefinition.WIDTH_NODE_NAME ).setText( Integer.toString( width ) ); } } Object heightObj = getInputValue( ChartDefinition.HEIGHT_NODE_NAME ); if ( heightObj != null ) { height = Integer.parseInt( heightObj.toString() ); if ( height != -1 ) { if ( chartAttributes.selectSingleNode( ChartDefinition.HEIGHT_NODE_NAME ) == null ) { ( (Element) chartAttributes ).addElement( ChartDefinition.HEIGHT_NODE_NAME ); } chartAttributes.selectSingleNode( ChartDefinition.HEIGHT_NODE_NAME ).setText( Integer.toString( height ) ); } } Object titleObj = getInputValue( ChartDefinition.TITLE_NODE_NAME ); if ( titleObj != null ) { if ( chartAttributes.selectSingleNode( ChartDefinition.TITLE_NODE_NAME ) == null ) { ( (Element) chartAttributes ).addElement( ChartDefinition.TITLE_NODE_NAME ); } chartAttributes.selectSingleNode( ChartDefinition.TITLE_NODE_NAME ).setText( titleObj.toString() ); } // ----------------End of Override // ---------------Feed the Title and Subtitle information through the input substitution Node titleNode = chartAttributes.selectSingleNode( ChartDefinition.TITLE_NODE_NAME ); if ( titleNode != null ) { String titleStr = titleNode.getText(); if ( titleStr != null ) { title = titleStr; String newTitle = applyInputsToFormat( titleStr ); titleNode.setText( newTitle ); } } List subtitles = chartAttributes.selectNodes( ChartDefinition.SUBTITLE_NODE_NAME ); if ( ( subtitles == null ) || ( subtitles.isEmpty() ) ) { Node subTitlesNode = chartAttributes.selectSingleNode( ChartDefinition.SUBTITLES_NODE_NAME ); if ( subTitlesNode != null ) { subtitles = chartAttributes.selectNodes( ChartDefinition.SUBTITLE_NODE_NAME ); } } else { // log a deprecation warning for this property... getLogger().warn( Messages.getInstance().getString( "CHART.WARN_DEPRECATED_CHILD", ChartDefinition.SUBTITLE_NODE_NAME, ChartDefinition.SUBTITLES_NODE_NAME ) ); //$NON-NLS-1$ getLogger().warn( Messages.getInstance() .getString( "CHART.WARN_PROPERTY_WILL_NOT_VALIDATE", ChartDefinition.SUBTITLE_NODE_NAME ) ); //$NON-NLS-1$ } if ( subtitles != null ) { for ( Iterator iter = subtitles.iterator(); iter.hasNext(); ) { Node subtitleNode = (Node) iter.next(); if ( subtitleNode != null ) { String subtitleStr = subtitleNode.getText(); if ( subtitleStr != null ) { String newSubtitle = applyInputsToFormat( subtitleStr ); subtitleNode.setText( newSubtitle ); } } } } // ----------------End of Format // Determine if we are going to read the chart data set by row or by column boolean byRow = false; if ( getInputStringValue( ChartComponent.BY_ROW_PROP ) != null ) { byRow = Boolean.valueOf( getInputStringValue( ChartComponent.BY_ROW_PROP ) ).booleanValue(); } // TODO Figure out why these overrides are called here. Seems like we are doing the same thing we just did above, // but // could possibly step on the height and width values set previously. if ( height == -1 ) { height = (int) getInputLongValue( ChartComponent.CHART_ATTRIBUTES_PROP + "/" + ChartDefinition.HEIGHT_NODE_NAME, 50 ); //$NON-NLS-1$ } if ( width == -1 ) { width = (int) getInputLongValue( ChartComponent.CHART_ATTRIBUTES_PROP + "/" + ChartDefinition.WIDTH_NODE_NAME, 100 ); //$NON-NLS-1$ } if ( title.length() <= 0 ) { title = getInputStringValue( ChartComponent.CHART_ATTRIBUTES_PROP + "/" + ChartDefinition.TITLE_NODE_NAME ); //$NON-NLS-1$ } // Select the right dataset to use based on the chart type // Default to category dataset String datasetType = ChartDefinition.CATEGORY_DATASET_STR; boolean isStacked = false; Node datasetTypeNode = chartAttributes.selectSingleNode( ChartDefinition.DATASET_TYPE_NODE_NAME ); if ( datasetTypeNode != null ) { datasetType = datasetTypeNode.getText(); } Dataset dataDefinition = null; if ( ChartDefinition.XY_SERIES_COLLECTION_STR.equalsIgnoreCase( datasetType ) ) { dataDefinition = new XYSeriesCollectionChartDefinition( data, byRow, chartAttributes, getSession() ); } else if ( ChartDefinition.TIME_SERIES_COLLECTION_STR.equalsIgnoreCase( datasetType ) ) { Node stackedNode = chartAttributes.selectSingleNode( ChartDefinition.STACKED_NODE_NAME ); if ( stackedNode != null ) { isStacked = Boolean.valueOf( stackedNode.getText() ).booleanValue(); } if ( ( isStacked ) && ( ChartDefinition.AREA_CHART_STR.equalsIgnoreCase( chartType ) ) ) { dataDefinition = new TimeTableXYDatasetChartDefinition( data, byRow, chartAttributes, getSession() ); } else { dataDefinition = new TimeSeriesCollectionChartDefinition( data, byRow, chartAttributes, getSession() ); } } else if ( ChartDefinition.PIE_CHART_STR.equalsIgnoreCase( chartType ) ) { dataDefinition = new PieDatasetChartDefinition( data, byRow, chartAttributes, getSession() ); } else if ( ChartDefinition.DIAL_CHART_STR.equalsIgnoreCase( chartType ) ) { dataDefinition = new DialWidgetDefinition( data, byRow, chartAttributes, width, height, getSession() ); } else if ( ChartDefinition.BAR_LINE_CHART_STR.equalsIgnoreCase( chartType ) ) { dataDefinition = new BarLineChartDefinition( data, byRow, chartAttributes, getSession() ); } else if ( ChartDefinition.BUBBLE_CHART_STR.equalsIgnoreCase( chartType ) ) { dataDefinition = new XYZSeriesCollectionChartDefinition( data, byRow, chartAttributes, getSession() ); } else { dataDefinition = new CategoryDatasetChartDefinition( data, byRow, chartAttributes, getSession() ); } // Determine what we are sending back - Default to OUTPUT_PNG output // OUTPUT_PNG = the chart gets written to a file in .png format // OUTPUT_SVG = the chart gets written to a file in .svg (XML) format // OUTPUT_CHART = the chart in a byte stream gets stored as as an IContentItem // OUTPUT_PNG_BYTES = the chart gets sent as a byte stream in .png format int outputType = JFreeChartEngine.OUTPUT_PNG; if ( getInputStringValue( ChartComponent.OUTPUT_TYPE_PROP ) != null ) { if ( ChartComponent.SVG_TYPE.equalsIgnoreCase( getInputStringValue( ChartComponent.OUTPUT_TYPE_PROP ) ) ) { outputType = JFreeChartEngine.OUTPUT_SVG; } else if ( ChartComponent.CHART_TYPE.equalsIgnoreCase( getInputStringValue( ChartComponent. OUTPUT_TYPE_PROP ) ) ) { outputType = JFreeChartEngine.OUTPUT_CHART; } else if ( ChartComponent.PNG_BYTES_TYPE .equalsIgnoreCase( getInputStringValue( ChartComponent.OUTPUT_TYPE_PROP ) ) ) { outputType = JFreeChartEngine.OUTPUT_PNG_BYTES; } } boolean keepTempFile = false; if ( isDefinedInput( KEEP_TEMP_FILE_PROP ) ) { keepTempFile = getInputBooleanValue( KEEP_TEMP_FILE_PROP, false ); } JFreeChart chart = null; switch ( outputType ) { /**************************** OUTPUT_PNG_BYTES *********************************************/ case JFreeChartEngine.OUTPUT_PNG_BYTES: chart = JFreeChartEngine.getChart( dataDefinition, title, "", width, height, this ); //$NON-NLS-1$ // TODO Shouldn't the mime types and other strings here be constant somewhere? Where do we // put this type of general info ? String mimeType = "image/png"; //$NON-NLS-1$ IContentItem contentItem = getOutputItem( "chartdata", mimeType, ".png" ); //$NON-NLS-1$ //$NON-NLS-2$ contentItem.setMimeType( mimeType ); try { OutputStream output = contentItem.getOutputStream( getActionName() ); ChartUtilities.writeChartAsPNG( output, chart, width, height ); } catch ( Exception e ) { error( Messages.getInstance().getErrorString( "ChartComponent.ERROR_0004_CANT_CREATE_IMAGE" ), e ); //$NON-NLS-1$ return false; } break; /**************************** OUTPUT_SVG && OUTPUT_PNG *************************************/ case JFreeChartEngine.OUTPUT_SVG: // intentionally fall through to PNG case JFreeChartEngine.OUTPUT_PNG: // Don't include the map in a file if HTML_MAPPING_HTML is specified, as that // param sends the map back on the outputstream as a string boolean createMapFile = !isDefinedOutput( ChartComponent.HTML_MAPPING_HTML ); boolean hasTemplate = urlTemplate != null && urlTemplate.length() > 0; File[] fileResults = createTempFile( outputType, hasTemplate, !keepTempFile ); if ( fileResults == null ) { error( Messages.getInstance().getErrorString( "ChartComponent.ERROR_0003_CANT_CREATE_TEMP_FILES" ) ); //$NON-NLS-1$ return false; } String chartId = fileResults[ChartComponent.FILE_NAME].getName().substring( 0, fileResults[ChartComponent.FILE_NAME].getName().indexOf( '.' ) ); String filePathWithoutExtension = ChartComponent.TEMP_DIRECTORY + chartId; PrintWriter printWriter = new PrintWriter( new StringWriter() ); ChartRenderingInfo info = new ChartRenderingInfo( new StandardEntityCollection() ); JFreeChartEngine.saveChart( dataDefinition, title, "", filePathWithoutExtension, width, height, outputType, printWriter, info, this ); //$NON-NLS-1$ // Creating the image map boolean useBaseUrl = true; String urlTarget = "pentaho_popup"; //$NON-NLS-1$ // Prepend the base url to the front of every drill through link if ( chartAttributes.selectSingleNode( ChartComponent.USE_BASE_URL_TAG ) != null ) { Boolean booleanValue = new Boolean( chartAttributes.selectSingleNode( ChartComponent.USE_BASE_URL_TAG ).getText() ); useBaseUrl = booleanValue.booleanValue(); } // What target for link? _parent, _blank, etc. if ( chartAttributes.selectSingleNode( ChartComponent.URL_TARGET_TAG ) != null ) { urlTarget = chartAttributes.selectSingleNode( ChartComponent.URL_TARGET_TAG ).getText(); } String mapString = null; if ( hasTemplate ) { try { String mapId = fileResults[ChartComponent.MAP_NAME].getName().substring( 0, fileResults[ChartComponent.MAP_NAME].getName().indexOf( '.' ) ); mapString = ImageMapUtilities.getImageMap( mapId, info, new StandardToolTipTagFragmentGenerator(), new PentahoChartURLTagFragmentGenerator( urlTemplate, urlTarget, useBaseUrl, dataDefinition, parameterName, outerParameterName ) ); if ( createMapFile ) { BufferedWriter out = new BufferedWriter( new FileWriter( fileResults[ChartComponent.MAP_NAME] ) ); out.write( mapString ); out.flush(); out.close(); } } catch ( IOException e ) { error( Messages.getInstance().getErrorString( "ChartComponent.ERROR_0001_CANT_WRITE_MAP", fileResults[ChartComponent.MAP_NAME].getPath() ) ); //$NON-NLS-1$ return false; } catch ( Exception e ) { error( e.getLocalizedMessage(), e ); return false; } } /******************************************************************************************************* * Legitimate outputs for the ChartComponent in an action sequence: * * CHART_OUTPUT (chart-output) Stores the chart in the content repository as an IContentItem. * * CHART_FILE_NAME_OUTPUT (chart-filename) Returns the name of the chart file, including the file extension * (with no path information) as a String. * * HTML_MAPPING_OUTPUT (chart-mapping) Returns the name of the file that the map has been saved to, including * the file extension (with no path information) as a String. Will be empty if url-template is undefined * * HTML_MAPPING_HTML (chart-map-html) Returns the chart image map HTML as a String. Will be empty if * url-template is undefined * * BASE_URL_OUTPUT (base-url) Returns the web app's base URL (ie., http://localhost:8080/pentaho) as a String. * * HTML_IMG_TAG (image-tag) Returns the HTML snippet including the image map, image (<IMG />) tag for the chart * image with src, width, height and usemap attributes defined. Usemap will not be included if url-template is * undefined. * *******************************************************************************************************/ // Now set the outputs Set outputs = getOutputNames(); if ( ( outputs != null ) && ( outputs.size() > 0 ) ) { Iterator iter = outputs.iterator(); while ( iter.hasNext() ) { String outputName = (String) iter.next(); String outputValue = null; if ( outputName.equals( ChartComponent.CHART_FILE_NAME_OUTPUT ) ) { outputValue = fileResults[ChartComponent.FILE_NAME].getName(); } else if ( outputName.equals( ChartComponent.HTML_MAPPING_OUTPUT ) ) { if ( hasTemplate ) { outputValue = fileResults[ChartComponent.MAP_NAME].getName(); } } else if ( outputName.equals( ChartComponent.HTML_MAPPING_HTML ) ) { outputValue = mapString; } else if ( outputName.equals( ChartComponent.BASE_URL_OUTPUT ) ) { IPentahoRequestContext requestContext = PentahoRequestContextHolder.getRequestContext(); outputValue = requestContext.getContextPath(); } else if ( outputName.equals( ChartComponent.CONTEXT_PATH_OUTPUT ) ) { IPentahoRequestContext requestContext = PentahoRequestContextHolder.getRequestContext(); outputValue = requestContext.getContextPath(); } else if ( outputName.equals( ChartComponent.FULLY_QUALIFIED_SERVER_URL_OUTPUT ) ) { IApplicationContext applicationContext = PentahoSystem.getApplicationContext(); if ( applicationContext != null ) { outputValue = applicationContext.getFullyQualifiedServerURL(); } else { IPentahoRequestContext requestContext = PentahoRequestContextHolder.getRequestContext(); outputValue = requestContext.getContextPath(); } } else if ( outputName.equals( ChartComponent.HTML_IMG_TAG ) ) { outputValue = hasTemplate ? mapString : ""; //$NON-NLS-1$ outputValue += "<img border=\"0\" "; //$NON-NLS-1$ outputValue += "width=\"" + width + "\" "; //$NON-NLS-1$//$NON-NLS-2$ outputValue += "height=\"" + height + "\" "; //$NON-NLS-1$//$NON-NLS-2$ if ( hasTemplate ) { outputValue += "usemap=\"#" + fileResults[ChartComponent.MAP_NAME].getName().substring( 0, fileResults[ ChartComponent.MAP_NAME ].getName().indexOf( '.' ) ) + "\" "; //$NON-NLS-1$//$NON-NLS-2$ } IPentahoRequestContext requestContext = PentahoRequestContextHolder.getRequestContext(); String contextPath = requestContext.getContextPath(); outputValue += "src=\"" + contextPath + "getImage?image=" + fileResults[ChartComponent.FILE_NAME].getName() + "\"/>"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ } if ( outputValue != null ) { setOutputValue( outputName, outputValue ); } } } break; /************************** OUTPUT_CHART && DEFAULT *************************************/ case JFreeChartEngine.OUTPUT_CHART: // intentionally fall through to default default: String chartName = ChartComponent.CHART_OUTPUT; if ( isDefinedInput( ChartComponent.CHART_NAME_PROP ) ) { chartName = getInputStringValue( ChartComponent.CHART_NAME_PROP ); } chart = JFreeChartEngine.getChart( dataDefinition, title, "", width, height, this ); //$NON-NLS-1$ setOutputValue( chartName, chart ); break; } return true; } @Override public boolean init() { // nothing to do here really return true; } /** * @return String that represents the file path to a temporary file */ protected File[] createTempFile( final int outputType, final boolean includeMapFile, boolean trackFile ) { File[] results; if ( includeMapFile ) { results = new File[2]; } else { results = new File[1]; } String extension = outputType == JFreeChartEngine.OUTPUT_SVG ? ChartComponent.SVG_EXTENSION : ChartComponent.PNG_EXTENSION; try { File file = PentahoSystem.getApplicationContext().createTempFile( getSession(), ChartComponent.FILENAME_PREFIX, extension, trackFile ); results[ChartComponent.FILE_NAME] = file; if ( includeMapFile ) { file = PentahoSystem.getApplicationContext().createTempFile( getSession(), ChartComponent.FILENAME_PREFIX, ChartComponent.MAP_EXTENSION, trackFile ); results[ChartComponent.MAP_NAME] = file; } } catch ( IOException e ) { return null; } return results; } }