/*! * 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.chartbeans; import org.apache.commons.io.IOUtils; import org.pentaho.actionsequence.dom.ActionSequenceDocument; import org.pentaho.actionsequence.dom.IActionSequenceInput; import org.pentaho.actionsequence.dom.IActionSequenceInputSource; import org.pentaho.actionsequence.dom.IActionSequenceOutput; import org.pentaho.actionsequence.dom.actions.ActionDefinition; import org.pentaho.actionsequence.dom.actions.MQLAction; import org.pentaho.chart.model.ChartDataDefinition; import org.pentaho.chart.model.ChartModel; import org.pentaho.chart.model.util.ChartSerializer; import org.pentaho.chart.model.util.ChartSerializer.ChartSerializationFormat; import org.pentaho.chart.plugin.jfreechart.JFreeChartPlugin; import org.pentaho.chart.plugin.openflashchart.OpenFlashChartPlugin; import org.pentaho.platform.api.engine.ILogger; import org.pentaho.platform.api.engine.IOutputHandler; import org.pentaho.platform.api.engine.IParameterProvider; import org.pentaho.platform.api.engine.IPentahoRequestContext; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.api.engine.IPentahoUrlFactory; import org.pentaho.platform.api.engine.IRuntimeContext; import org.pentaho.platform.api.engine.ISolutionEngine; import org.pentaho.platform.config.messages.Messages; import org.pentaho.platform.engine.core.output.SimpleOutputHandler; import org.pentaho.platform.engine.core.solution.SimpleParameterProvider; import org.pentaho.platform.engine.core.system.PentahoRequestContextHolder; import org.pentaho.platform.engine.core.system.PentahoSystem; import org.pentaho.platform.engine.services.runtime.TemplateUtil; import org.pentaho.platform.plugin.action.pentahometadata.ActionDefinitionEncoder; import org.pentaho.platform.util.UUIDUtil; import org.pentaho.platform.util.web.SimpleUrlFactory; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.Random; import java.util.Set; import static org.pentaho.actionsequence.dom.IActionSequenceDocument.*; public class DefaultChartBeansGenerator implements IChartBeansGenerator { private Random random = new Random(); private static final String DEFAULT_HTML_TEMPLATE = "<html><head><title>Command: doChart</title>{0}</head><body style='margin:0;' scroll='no'>{1}</body></html>"; //$NON-NLS-1$ private static final String JFREE_CHART_HTML_TEMPLATE = "<html><head><title>Pentaho Chart</title></head><body style='margin:0;' scroll='no'>{imageMap}<img border=\"0\" " + "width=\"{chartWidth}\" height=\"{chartHeight}\" src=\"{contextPath}getImage?image={imageFile}\" " + "{useMap}/></body></html>"; //$NON-NLS-1$ private static String DEFAULT_flashScriptFragment = "<input type=\"hidden\"/><script defer='defer' type=\"text/javascript\">function {dataFunction}() { return " + "/*JSON*/\"{chartJson}\"/*END_JSON*/;}</script>"; //$NON-NLS-1$ private static String DEFAULT_flashObjectFragment = "<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" " //$NON-NLS-1$ + "codebase=\"http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0\" " //$NON-NLS-1$ + "width=\"{chart-width}\" height=\"{chart-height}\" id=\"ofco{chartId}\" align=\"middle\"> " //$NON-NLS-1$ + "<param name=\"allowScriptAccess\" value=\"sameDomain\" /> " //$NON-NLS-1$ + "<param name=\"wmode\" value=\"opaque\">" //$NON-NLS-1$ + "<param name=\"movie\" value=\"{ofc-url}?get-data={dataFunction}\" /> " //$NON-NLS-1$ + "<param name=\"quality\" value=\"high\" /> " //$NON-NLS-1$ + "<embed src=\"{ofc-url}?get-data={dataFunction}\" wmode=\"opaque\" quality=\"high\" bgcolor=\"#FFFFFF\" " //$NON-NLS-1$ + "width=\"{chart-width}\" height=\"{chart-height}\" id=\"ofce{chartId}\" align=\"middle\" " + "allowScriptAccess=\"sameDomain\" type=\"application/x-shockwave-flash\" " //$NON-NLS-1$ + "pluginspage=\"http://www.macromedia.com/go/getflashplayer\" /></object>"; //$NON-NLS-1$ public DefaultChartBeansGenerator() { } /** * The engine that processes the parameters from the specific interface methods and writes a chart to the output * stream or returns an input stream for reading. * * @param pentahoSession * @param serializedChartDataDefinition * @param serializedChartModel * @param chartWidth * @param chartHeight * @param outputStream * @return * @throws IOException */ private InputStream internalCreateChart( IPentahoSession pentahoSession, Map<String, Object> parameterMap, String serializedChartDataDefinition, String serializedChartModel, int chartWidth, int chartHeight, String contentLinkingTemplate, OutputStream outputStream ) throws IOException { InputStream result = null; ByteArrayOutputStream resultOutputStream = null; OutputStream out = null; // Make code more readable by defining the output result boolean returnInputStream = outputStream == null ? true : false; // If the caller sends a null OutputStream, then we will return an InputStream if ( returnInputStream ) { resultOutputStream = new ByteArrayOutputStream(); out = new BufferedOutputStream( resultOutputStream ); } else { out = outputStream; } // Setup parameters to be passed to the xaction Map<String, Object> params = new HashMap<String, Object>(); params.put( "chart-model-json", serializedChartModel ); //$NON-NLS-1$ params.put( "chart-width", chartWidth ); //$NON-NLS-1$ params.put( "chart-height", chartHeight ); //$NON-NLS-1$ // De-serialize the chartDataDefintion and extract relevant parts ChartDataDefinition chartDataDefinition = ChartSerializer.deSerializeDataDefinition( serializedChartDataDefinition, ChartSerializationFormat.JSON ); if ( chartDataDefinition.getQuery() != null ) { params.put( "query", chartDataDefinition.getQuery() ); //$NON-NLS-1$ } if ( chartDataDefinition.getDomainColumn() != null ) { params.put( "series-column", chartDataDefinition.getDomainColumn() ); //$NON-NLS-1$ } if ( chartDataDefinition.getCategoryColumn() != null && !chartDataDefinition.getCategoryColumn().equals( "None" ) ) { params.put( "category-column", chartDataDefinition.getCategoryColumn() ); //$NON-NLS-1$ } if ( chartDataDefinition.getRangeColumn() != null ) { params.put( "value-column", chartDataDefinition.getRangeColumn() ); //$NON-NLS-1$ } if ( chartDataDefinition.getScalingFactor() != null ) { params.put( "scaling-factor", chartDataDefinition.getScalingFactor().toString() ); //$NON-NLS-1$ } createAndRunActionSequence( pentahoSession, params, parameterMap, contentLinkingTemplate, out ); if ( out instanceof BufferedOutputStream ) { out.flush(); } if ( returnInputStream ) { result = new ByteArrayInputStream( resultOutputStream.toByteArray() ); return ( result ); } return null; } protected void createAndRunActionSequence( final IPentahoSession pentahoSession, final Map<String, Object> params, final Map<String, Object> defaultParameterMap, String contentLinkingTemplate, final OutputStream out ) { SimpleParameterProvider parameterProvider = new SimpleParameterProvider( params ); // add the default parameter values for ( Map.Entry<String, Object> entry : defaultParameterMap.entrySet() ) { parameterProvider.setParameter( entry.getKey(), entry.getValue() ); } Map<String, IParameterProvider> parameterProviders = new HashMap<String, IParameterProvider>(); parameterProviders.put( IParameterProvider.SCOPE_REQUEST, parameterProvider ); SimpleOutputHandler outputHandler = new SimpleOutputHandler( out, true ); outputHandler.setOutputPreference( IOutputHandler.OUTPUT_TYPE_DEFAULT ); ActionSequenceDocument doc = createActionSequenceDocument( defaultParameterMap.keySet(), contentLinkingTemplate ); runActionSequence( pentahoSession, parameterProviders, outputHandler, doc ); try { out.flush(); out.close(); } catch ( IOException e ) { e.printStackTrace(); } } /** * Executes an action sequence from an <code>ActionSequenceDocument</code>. * * @param pentahoSession * current <code>IPentahoSession</code> * @param parameterProviders * map of parameter providers; there should a single entry with "request" as the key * @param outputHandler * output handler * @param doc * action sequence document * @throws RuntimeException * if anything goes wrong */ protected void runActionSequence( final IPentahoSession pentahoSession, final Map<String, IParameterProvider> parameterProviders, final IOutputHandler outputHandler, final ActionSequenceDocument doc ) throws RuntimeException { // Get the solution engine ISolutionEngine solutionEngine = PentahoSystem.get( ISolutionEngine.class, pentahoSession ); if ( solutionEngine == null ) { throw new RuntimeException( "solutionEngine is null" ); //$NON-NLS-1$ } solutionEngine.setLoggingLevel( ILogger.DEBUG ); solutionEngine.init( pentahoSession ); IPentahoRequestContext requestContext = PentahoRequestContextHolder.getRequestContext(); String contextPath = requestContext.getContextPath(); IPentahoUrlFactory urlFactory = new SimpleUrlFactory( contextPath ); //$NON-NLS-1$ IRuntimeContext runtime; IParameterProvider requestParmProvider = parameterProviders.get( "request" ); if ( requestParmProvider.hasParameter( "obj_id" ) ) { final String obj_id = (String) requestParmProvider.getParameter( "obj_id" ); final String msg_name = (String) requestParmProvider.getParameter( "message_name" ); final String job_id = (String) requestParmProvider.getParameter( "job_id" ); runtime = solutionEngine.execute( doc.toString(), obj_id, job_id, false, true, //$NON-NLS-1$ //$NON-NLS-2$ msg_name, true, parameterProviders, outputHandler, null, urlFactory, new ArrayList() ); //$NON-NLS-1$ } else { runtime = solutionEngine.execute( doc.toString(), "chartbeans_mql", "myprocessid", false, true, //$NON-NLS-1$ //$NON-NLS-2$ "myinstanceid", true, parameterProviders, outputHandler, null, urlFactory, new ArrayList() ); //$NON-NLS-1$ } if ( ( runtime != null ) && ( runtime.getStatus() != IRuntimeContext.RUNTIME_STATUS_SUCCESS ) ) { StringBuilder buf = new StringBuilder(); boolean firstIteration = true; for ( Object /* String */message : runtime.getMessages() ) { if ( message instanceof Exception ) { Exception ex = (Exception) message; if ( ex.getCause() instanceof RuntimeException ) { throw (RuntimeException) ex.getCause(); } } if ( !firstIteration ) { buf.append( " \\\\ " ); //$NON-NLS-1$ } buf.append( message ); } String errorStr; if ( buf.indexOf( "action_sequence_failed" ) > -1 && buf.indexOf( "MQLRelationalDataComponent" ) > -1 ) { errorStr = Messages.getInstance().getString( "DefaultChartBeansGenerator.ERROR_0001_SECURITY_ERROR" ); } else { errorStr = Messages.getInstance().getString( "DefaultChartBeansGenerator.ERROR_0002_UNKNOWN_ERROR" ); } throw new RuntimeException( errorStr ); } } /** * Creates an <code>ActionSequenceDocument</code> that will run an MQL query and pipe the results in the ChartBeans * <code>ChartComponent</code>. * * @param parameterNameSet * set of parameter names that appear in the MQL query * @return doc */ protected ActionSequenceDocument createActionSequenceDocument( final Set<String> parameterNameSet, String contentLinkingTemplate ) { ActionSequenceDocument actionSequenceDocument = new ActionSequenceDocument(); actionSequenceDocument.setTitle( "chartbeans_mql.xaction" ); //$NON-NLS-1$ actionSequenceDocument.setVersion( "1" ); //$NON-NLS-1$ actionSequenceDocument.setLoggingLevel( "debug" ); //$NON-NLS-1$ actionSequenceDocument.setAuthor( "Dashboard" ); //$NON-NLS-1$ actionSequenceDocument.setDescription( "Generate a chart through ChartBeans from an MQL statement." ); //$NON-NLS-1$ actionSequenceDocument.setHelp( "Pass in an MQL statement that returns a table of three columns. The first column " //$NON-NLS-1$ + "is the series, the second is the category and the third is the data." ); //$NON-NLS-1$ actionSequenceDocument.setHelp( "" ); //$NON-NLS-1$ actionSequenceDocument.setResultType( "rule" ); //$NON-NLS-1$ IActionSequenceInput queryInput = actionSequenceDocument.createInput( "query", STRING_TYPE ); //$NON-NLS-1$ IActionSequenceInput chartModelJsonInput = actionSequenceDocument.createInput( "chart-model-json", STRING_TYPE ); //$NON-NLS-1$ IActionSequenceInput chartWidthInput = actionSequenceDocument.createInput( "chart-width", INTEGER_TYPE ); //$NON-NLS-1$ chartWidthInput.addSource( REQUEST_INPUT_SOURCE, "chart-width" ); //$NON-NLS-1$ chartWidthInput.setDefaultValue( "1" ); //$NON-NLS-1$ IActionSequenceInput chartHeightInput = actionSequenceDocument.createInput( "chart-height", INTEGER_TYPE ); //$NON-NLS-1$ chartHeightInput.addSource( REQUEST_INPUT_SOURCE, "chart-height" ); //$NON-NLS-1$ chartHeightInput.setDefaultValue( "1" ); //$NON-NLS-1$ IActionSequenceInput seriesColumnInput = actionSequenceDocument.createInput( "series-column", STRING_TYPE ); //$NON-NLS-1$ seriesColumnInput.setDefaultValue( "1" ); //$NON-NLS-1$ IActionSequenceInput categoryColumnInput = actionSequenceDocument.createInput( "category-column", STRING_TYPE ); //$NON-NLS-1$ // set a default value of empty string to avoid an error when rendering pie charts (which don't have a category // column categoryColumnInput.setDefaultValue( "2" ); //$NON-NLS-1$ IActionSequenceInput valueColumnInput = actionSequenceDocument.createInput( "value-column", STRING_TYPE ); //$NON-NLS-1$ valueColumnInput.setDefaultValue( "0" ); //$NON-NLS-1$ IActionSequenceInput scalingFactorInput = actionSequenceDocument.createInput( "scaling-factor", STRING_TYPE ); //$NON-NLS-1$ // add inputs from parameterNameSet; these parameters will appear as placeholders in the query input for ( String parameterName : parameterNameSet ) { IActionSequenceInput input = actionSequenceDocument.createInput( ActionDefinitionEncoder.encodeBlankSpaces( parameterName ), STRING_TYPE ); IActionSequenceInputSource[] sources = input.getSources(); if ( sources.length > 0 ) { input.getSources()[0].setName( parameterName ); } else { input.addSource( "request", parameterName ); } } IActionSequenceOutput outputStreamOutput = actionSequenceDocument.createOutput( "outputstream", CONTENT_TYPE ); //$NON-NLS-1$ outputStreamOutput.addDestination( RESPONSE_OUTPUT_DESTINATION, "content" ); //$NON-NLS-1$ MQLAction mqlAction = (MQLAction) actionSequenceDocument.addAction( MQLAction.class ); mqlAction.setActionInputValue( "query", queryInput ); //$NON-NLS-1$ // add inputs from parameterNameSet to this action for ( String parameterName : parameterNameSet ) { mqlAction.addInput( ActionDefinitionEncoder.encodeBlankSpaces( parameterName ), STRING_TYPE ); } mqlAction.setOutputResultSet( "chartdata" ); //$NON-NLS-1$ mqlAction.setComponentDefinition( "live", Boolean.TRUE.toString() ); //$NON-NLS-1$ mqlAction.setComponentDefinition( "display-names", Boolean.FALSE.toString() ); //$NON-NLS-1$ ActionDefinition pojoAction = (ActionDefinition) actionSequenceDocument.addAction( ActionDefinition.class ); pojoAction.setComponentName( "ChartBeansComponent" ); //$NON-NLS-1$ if ( contentLinkingTemplate != null ) { pojoAction.setComponentDefinition( "contentLinkingTemplate", contentLinkingTemplate ); } pojoAction.setActionInputValue( "chart-model-json", chartModelJsonInput ); //$NON-NLS-1$ pojoAction.addInput( "chartdata", RESULTSET_TYPE ); //$NON-NLS-1$ pojoAction.setActionInputValue( "chart-width", chartWidthInput ); //$NON-NLS-1$ pojoAction.setActionInputValue( "chart-height", chartHeightInput ); //$NON-NLS-1$ pojoAction.setActionInputValue( "series-column", seriesColumnInput ); //$NON-NLS-1$ pojoAction.setActionInputValue( "category-column", categoryColumnInput ); //$NON-NLS-1$ pojoAction.setActionInputValue( "value-column", valueColumnInput ); //$NON-NLS-1$ pojoAction.setActionInputValue( "scaling-factor", scalingFactorInput ); //$NON-NLS-1$ pojoAction.addOutput( "outputstream", CONTENT_TYPE ); //$NON-NLS-1$ return actionSequenceDocument; } public String buildEmptyOpenFlashChartHtmlFragment( String msg ) { // populate the flash html template Properties props = new Properties(); props.setProperty( "dataFunction", "getChartData" + Integer.toString( random.nextInt( 100000 ) ) ); // + chartId); //$NON-NLS-1$ //$NON-NLS-2$ props.setProperty( "chartJson", "{}" ); //$NON-NLS-1$ //$NON-NLS-2$ String flashHtml = MessageFormat.format( getHtmlTemplate(), new String[] { TemplateUtil.applyTemplate( getFlashScriptFragment(), props, null ), msg } ); return flashHtml; } /** * Does this method belong in ChartBeansGeneratorUtil? ChartBeansGeneratorUtil may be more of a convenience for * executing the default ActionSequence, if this is to hold true, this method probably needs a new home more central * to the ChartBeans code. Returns a complete HTML document that references an Open Flash Chart SWF resource that * resides on the server along with the data that should be displayed in the chart (via a JavaScript function that * returns a JSON string). * <p> * Only exposed for debugging (i.e. hosted mode) purposes. * </p> */ public String buildOpenFlashChartHtmlFragment( String openFlashChartJson, String swfUrl, String chartWidth, String chartHeight ) { // generate a unique name for the function String chartId = UUIDUtil.getUUIDAsString().replaceAll( "[^\\w]", "" ); //$NON-NLS-1$ //$NON-NLS-2$ // populate the flash html template Properties props = new Properties(); props.setProperty( "chartId", chartId ); //$NON-NLS-1$ props.setProperty( "dataFunction", "getChartData" + Integer.toString( random.nextInt( 100000 ) ) ); // + chartId); //$NON-NLS-1$ //$NON-NLS-2$ props.setProperty( "chart-width", chartWidth ); //$NON-NLS-1$ props.setProperty( "chart-height", chartHeight ); //$NON-NLS-1$ props.setProperty( "ofc-url", swfUrl ); //$NON-NLS-1$ props.setProperty( "chartJson", openFlashChartJson ); //$NON-NLS-1$ String flashHtml = MessageFormat.format( getHtmlTemplate(), new String[] { TemplateUtil.applyTemplate( getFlashScriptFragment(), props, null ), TemplateUtil.applyTemplate( getFlashObjectFragment(), props, null ) } ); return flashHtml; } public String buildJFreeChartHtmlFragment( File imageFile, String imageMap, String imageMapName, int chartWidth, int chartHeight, String contextPath ) { Properties props = new Properties(); props.setProperty( "imageMap", imageMap != null ? imageMap : "" ); //$NON-NLS-1$ //$NON-NLS-2$ props.setProperty( "useMap", imageMapName != null ? "usemap=\"#" + imageMapName + "\"" : "" ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ props.setProperty( "contextPath", contextPath ); //$NON-NLS-1$ props.setProperty( "chartWidth", Integer.toString( chartWidth ) ); //$NON-NLS-1$ props.setProperty( "chartHeight", Integer.toString( chartHeight ) ); //$NON-NLS-1$ props.setProperty( "imageFile", imageFile.getName() ); //$NON-NLS-1$ return TemplateUtil.applyTemplate( JFREE_CHART_HTML_TEMPLATE, props, null ); } public String createChartAsHtml( IPentahoSession userSession, Map<String, Object> parameterMap, String serializedChartDataDefinition, String serializedChartModel, int chartWidth, int chartHeight, String contentLinkingTemplate ) throws IOException { ChartModel chartModel = ChartSerializer.deSerialize( serializedChartModel, ChartSerializationFormat.JSON ); String html = null; if ( chartModel.getChartEngineId() == null ) { // Load default value from system setting or take hard coded // Hard coded final fall back is Open Flash Chart String defaultChartEngine = PentahoSystem.getSystemSetting( "chartbeans/chartbeans_config.xml", "default-chart-engine", OpenFlashChartPlugin.PLUGIN_ID ); //$NON-NLS-1$ //$NON-NLS-2$ if ( defaultChartEngine == null ) { defaultChartEngine = OpenFlashChartPlugin.PLUGIN_ID; } chartModel.setChartEngineId( defaultChartEngine ); } // Check for render engine override String override = (String) parameterMap.get( "renderEngine" ); if ( override != null ) { chartModel.setChartEngineId( override ); } serializedChartModel = ChartSerializer.serialize( chartModel, ChartSerializationFormat.JSON ); if ( contentLinkingTemplate == null ) { // use old version html = createChartAsHtml( userSession, parameterMap, serializedChartDataDefinition, serializedChartModel, chartWidth, chartHeight ); } else { // with content linking final String ENCODING = "UTF-8"; //$NON-NLS-1$ InputStream is = this.internalCreateChart( userSession, parameterMap, serializedChartDataDefinition, serializedChartModel, chartWidth, chartHeight, contentLinkingTemplate, null ); html = IOUtils.toString( is, ENCODING ); // copy(is, writer); } return html; } public String createChartAsHtml( IPentahoSession userSession, Map<String, Object> parameterMap, String serializedChartDataDefinition, String serializedChartModel, int chartWidth, int chartHeight ) throws IOException { ChartModel chartModel = ChartSerializer.deSerialize( serializedChartModel, ChartSerializationFormat.JSON ); String html = null; if ( chartModel.getChartEngineId() == null ) { // Load default value from system setting or take hard coded // Hard coded final fall back is Open Flash Chart String defaultChartEngine = PentahoSystem.getSystemSetting( "chartbeans/chartbeans_config.xml", "default-chart-engine", OpenFlashChartPlugin.PLUGIN_ID ); //$NON-NLS-1$ //$NON-NLS-2$ if ( defaultChartEngine == null ) { defaultChartEngine = OpenFlashChartPlugin.PLUGIN_ID; } chartModel.setChartEngineId( defaultChartEngine ); } // Check for render engine override String override = (String) parameterMap.get( "renderEngine" ); if ( override != null ) { chartModel.setChartEngineId( override ); } serializedChartModel = ChartSerializer.serialize( chartModel, ChartSerializationFormat.JSON ); if ( JFreeChartPlugin.PLUGIN_ID.equals( chartModel.getChartEngineId() ) ) { final String SOLUTION_TMP_DIR = "system/tmp/"; //$NON-NLS-1$ File chartFileOnServer = new File( new File( PentahoSystem.getApplicationContext().getFileOutputPath( SOLUTION_TMP_DIR ) ), java.util.UUID.randomUUID().toString() ); BufferedOutputStream bos = null; try { bos = new BufferedOutputStream( new FileOutputStream( chartFileOnServer ) ); this.internalCreateChart( userSession, parameterMap, serializedChartDataDefinition, serializedChartModel, chartWidth, chartHeight, null, bos ); } finally { IOUtils.closeQuietly( bos ); } IPentahoRequestContext requestContext = PentahoRequestContextHolder.getRequestContext(); String contextPath = requestContext.getContextPath(); String url = contextPath + "/"; //$NON-NLS-1$ //$NON-NLS-2$ final String IMAGE_URL_TEMPLATE = "{0}getImage?image={1}"; //$NON-NLS-1$ final String imageUrl = MessageFormat.format( IMAGE_URL_TEMPLATE, new String[] { url, chartFileOnServer.getName() } ); html = this.mergeStaticImageHtmlTemplate( imageUrl ); } else if ( OpenFlashChartPlugin.PLUGIN_ID.equals( chartModel.getChartEngineId() ) ) { ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(); this.internalCreateChart( userSession, parameterMap, serializedChartDataDefinition, serializedChartModel, chartWidth, chartHeight, null, tmpOut ); final String ENCODING = "UTF-8"; //$NON-NLS-1$ ByteArrayInputStream in = new ByteArrayInputStream( tmpOut.toByteArray() ); IOUtils.closeQuietly( tmpOut ); html = IOUtils.toString( in, ENCODING ); IOUtils.closeQuietly( in ); } else { throw new IllegalArgumentException( "unrecognized chart engine" ); //$NON-NLS-1$ } return html; } public String mergeOpenFlashChartHtmlTemplate( String openFlashChartJson, String swfUrl ) { return buildOpenFlashChartHtmlFragment( openFlashChartJson, swfUrl, "100%", "100%" ); //$NON-NLS-1$ //$NON-NLS-2$ } public String mergeJFreeChartHtmlTemplate( File imageFile, String imageMap, String imageMapName, int chartWidth, int chartHeight, String contextPath ) { return buildJFreeChartHtmlFragment( imageFile, imageMap, imageMapName, chartWidth, chartHeight, contextPath ); } public String mergeStaticImageHtmlTemplate( String imageUrl ) { final String BODY_TEMPLATE = "<img src=\"{0}\" />"; //$NON-NLS-1$ final String body = MessageFormat.format( BODY_TEMPLATE, new String[] { imageUrl } ); return MessageFormat.format( getHtmlTemplate(), new String[] { "", body } ); //$NON-NLS-1$ } public String getHtmlTemplate() { return DEFAULT_HTML_TEMPLATE; } public String getFlashScriptFragment() { return DEFAULT_flashScriptFragment; } public String getFlashObjectFragment() { return DEFAULT_flashObjectFragment; } }