/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, version 2 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.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 General Public License for more details.
*
*
* Copyright 2006 - 2013 Pentaho Corporation. All rights reserved.
*/
package org.pentaho.platform.uifoundation.chart;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.commons.connection.IPentahoResultSet;
import org.pentaho.platform.api.engine.IActionParameter;
import org.pentaho.platform.api.engine.ILogger;
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.engine.core.output.SimpleOutputHandler;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.engine.services.runtime.TemplateUtil;
import org.pentaho.platform.uifoundation.component.xml.XmlComponent;
import org.pentaho.platform.uifoundation.messages.Messages;
import org.pentaho.platform.util.messages.LocaleHelper;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
// ESCA-JAVA0100:
// ESCA-JAVA0136:
// ESCA-JAVA0054:
public abstract class AbstractChartComponent extends XmlComponent {
private static final long serialVersionUID = -3700747149855352376L;
/**
* XML Node for the chart configuration
*/
public static final String CHART_NODE_NAME = "chart"; //$NON-NLS-1$
/**
* XML node for the URL Template
*/
public static final String URLTEMPLATE_NODE_NAME = "url-template"; //$NON-NLS-1$
/**
* XML node for the series name
*/
public static final String PARAM2_NODE_NAME = "series-name"; //$NON-NLS-1$
/**
* Index into array of the filename
*/
public static final int FILENAME_INDEX = 0;
/**
* Index into array of the filename without the extension
*/
public static final int FILENAME_WITHOUT_EXTENSION_INDEX = 1;
protected String definitionPath;
protected int width = -1;
protected int height = -1;
protected String title;
protected Object values;
protected boolean byRow = true;
protected String actionPath;
protected String actionOutput;
protected String instanceId = null;
protected IRuntimeContext context;
protected String urlTemplate = null;
protected List<String> outerParamNames = new ArrayList<String>();
protected String paramName; // Assumes 1 parameter subclasses may need more
protected static int chartCount = 0;
protected static Log logger = null;
protected AbstractChartComponent( final String definitionPath, final int width, final int height,
final IPentahoUrlFactory urlFactory, final List messages ) {
this( urlFactory, messages );
this.definitionPath = definitionPath;
this.width = width;
this.height = height;
setSourcePath( definitionPath );
}
/**
* @param definitionPath
* @param urlFactory
* @param messages
*/
protected AbstractChartComponent( final String definitionPath, final IPentahoUrlFactory urlFactory,
final ArrayList messages ) {
this( urlFactory, messages );
this.definitionPath = definitionPath;
setSourcePath( definitionPath );
}
protected AbstractChartComponent( final IPentahoUrlFactory urlFactory, final List messages ) {
super( urlFactory, messages, null );
setXsl( "text/html", "Chart.xsl" ); //$NON-NLS-1$ //$NON-NLS-2$
AbstractChartComponent.logger = LogFactory.getLog( this.getClass() );
}
/**
* @param chartDefinition
* String that represents a file in the solution to create the chart from.
* @return
*/
public abstract boolean setDataAction( String chartDefinition );
/**
* Sets the action to be executed to get the data for the pies
*
* @param solution
* @param actionPath
* @param actionName
* @param actionOutput
*/
public void setDataAction( final String actionPath, final String actionOutput ) {
this.actionPath = actionPath;
this.actionOutput = actionOutput;
}
/**
* Gets a IPentahoResultSet from the action output
*
* @return IPentahoResultSet
*/
public IPentahoResultSet getActionData() {
// create an instance of the solution engine to execute the specified
// action
ISolutionEngine solutionEngine = PentahoSystem.get( ISolutionEngine.class, getSession() );
solutionEngine.setLoggingLevel( ILogger.DEBUG );
solutionEngine.init( getSession() );
HashMap parameterProviders = getParameterProviders();
OutputStream outputStream = null;
SimpleOutputHandler outputHandler = null;
outputHandler = new SimpleOutputHandler( outputStream, false );
ArrayList messages = new ArrayList();
String processId = this.getClass().getName();
context = solutionEngine.execute( actionPath, processId, false, true, instanceId, false, //$NON-NLS-1$ //$NON-NLS-2$
parameterProviders, outputHandler, null, urlFactory, messages );
if ( context == null ) {
// this went badly wrong
return null;
}
if ( actionOutput != null ) {
if ( context.getOutputNames().contains( actionOutput ) ) {
IActionParameter output = context.getOutputParameter( actionOutput );
IPentahoResultSet results = output.getValueAsResultSet();
if ( results != null ) {
results = results.memoryCopy();
}
return results;
} else {
// this is an error
return null;
}
} else {
for ( Object objAp : context.getOutputNames() ) {
IActionParameter output = (IActionParameter) objAp;
if ( output.getType().equalsIgnoreCase( IActionParameter.TYPE_RESULT_SET ) ) {
IPentahoResultSet results = output.getValueAsResultSet();
if ( results != null ) {
results = results.memoryCopy();
}
return results;
}
}
}
return null;
}
@Override
public Log getLogger() {
return AbstractChartComponent.logger;
}
/**
* @return String that represents the file path to a temporary file
*/
protected String[] createTempFile() {
// create temporary file names
String solutionDir = "system/tmp/"; //$NON-NLS-1$
String fileNamePrefix = "tmp_chart_"; //$NON-NLS-1$
String extension = ".png"; //$NON-NLS-1$
String fileName = null;
String filePathWithoutExtension = null;
try {
File file = PentahoSystem.getApplicationContext().createTempFile( getSession(), fileNamePrefix, extension, true );
fileName = file.getName();
filePathWithoutExtension = solutionDir + fileName.substring( 0, fileName.indexOf( '.' ) );
} catch ( IOException e ) {
getLogger().error(
Messages.getInstance().getErrorString( "AbstractChartComponent.ERROR_0001_CANT_CREATE_TEMP_CHART" ), e ); //$NON-NLS-1$
}
String[] value = new String[2];
value[AbstractChartComponent.FILENAME_INDEX] = fileName;
value[AbstractChartComponent.FILENAME_WITHOUT_EXTENSION_INDEX] = filePathWithoutExtension;
return value;
}
protected void applyOuterURLTemplateParam() {
if ( outerParamNames == null ) {
return;
}
for ( String outerParamName : outerParamNames ) {
Object value = null;
if ( ( context != null ) && context.getInputNames().contains( outerParamName ) ) {
value = context.getInputParameterValue( outerParamName );
}
if ( value == null ) {
return;
}
try {
if ( value.getClass().isArray() ) {
if ( Array.getLength( value ) > 0 ) {
String[] encodedVals = new String[Array.getLength( value )];
for ( int i = 0; i < Array.getLength( value ); ++i ) // ESCA-JAVA0049:
{
encodedVals[i] = URLEncoder.encode( Array.get( value, i ).toString(), LocaleHelper.getSystemEncoding() );
}
// TODO Sleeze Alert!!! This is a temporary hack for making the
// URLs generated support multiple selections. A JIRA case PLATFORM-393
// has been generated to address this issue.
//
// For now, applyTemplate looks for an "&" or "?" preceding and following the param, uses all
// the characters between them as the template and repeats it once for each param value
// separating them with '&'
urlTemplate = TemplateUtil.applyTemplate( urlTemplate, outerParamName, encodedVals );
}
} else {
String encodedVal = URLEncoder.encode( value.toString(), LocaleHelper.getSystemEncoding() );
urlTemplate = TemplateUtil.applyTemplate( urlTemplate, outerParamName, encodedVal );
}
//encodedVal = URLEncoder.encode(stringVal, LocaleHelper.getSystemEncoding()); //$NON-NLS-1$
} catch ( UnsupportedEncodingException e ) {
getLogger().error(
Messages.getInstance().getErrorString( "AbstractChartComponent.ERROR_0002_URL_ENCODE_FAILED" ), e ); //$NON-NLS-1$
}
}
}
/**
*
*/
public void dispose() {
if ( context != null ) {
context.dispose();
}
}
/**
* @return Returns the actionOutput.
*/
public String getActionOutput() {
return actionOutput;
}
/**
* @param actionOutput
* The actionOutput to set.
*/
public void setActionOutput( final String actionOutput ) {
this.actionOutput = actionOutput;
}
/**
* @return Returns the actionPath.
*/
public String getActionPath() {
return actionPath;
}
/**
* @param actionPath
* The actionPath to set.
*/
public void setActionPath( final String actionPath ) {
this.actionPath = actionPath;
}
/**
* @return Returns the context.
*/
public IRuntimeContext getContext() {
return context;
}
/**
* @param context
* The context to set.
*/
public void setContext( final IRuntimeContext context ) {
this.context = context;
}
/**
* @return Returns the definitionPath.
*/
public String getDefinitionPath() {
return definitionPath;
}
/**
* @param definitionPath
* The definitionPath to set.
*/
public void setDefinitionPath( final String definitionPath ) {
this.definitionPath = definitionPath;
}
/**
* @return Returns the height.
*/
public int getHeight() {
return height;
}
/**
* @param height
* The height to set.
*/
public void setHeight( final int height ) {
this.height = height;
}
/**
* @return Returns the instanceId.
*/
public String getInstanceId() {
return instanceId;
}
/**
* @param instanceId
* The instanceId to set.
*/
public void setInstanceId( final String instanceId ) {
this.instanceId = instanceId;
}
/**
* @return Returns the title.
*/
public String getTitle() {
return title;
}
/**
* @param title
* The title to set.
*/
public void setTitle( final String title ) {
this.title = title;
}
/**
* @return Returns the urlTemplate.
*/
public String getUrlTemplate() {
return urlTemplate;
}
/**
* @param urlTemplate
* The urlTemplate to set.
*/
public void setUrlTemplate( final String urlTemplate ) {
this.urlTemplate = urlTemplate;
}
/**
* @return Returns the values.
*/
public Object getValues() {
return values;
}
/**
* @param values
* The values to set.
*/
public void setValues( final Object values ) {
this.values = values;
}
/**
* @return Returns the width.
*/
public int getWidth() {
return width;
}
/**
* @param width
* The width to set.
*/
public void setWidth( final int width ) {
this.width = width;
}
/**
* @param logger
* The logger to set.
*/
public void setLogger( final Log logger ) {
AbstractChartComponent.logger = logger;
}
/**
* @return Returns the byRow.
*/
public boolean isByRow() {
return byRow;
}
/**
* @param byRow
* The byRow to set.
*/
public void setByRow( final boolean byRow ) {
this.byRow = byRow;
}
/**
* @return Returns the paramName.
*/
public String getParamName() {
return paramName;
}
/**
* @param paramName
* The paramName to set.
*/
public void setParamName( final String paramName ) {
this.paramName = paramName;
}
/**
* @return Returns the outerParamNames. private List getOuterParamNames() { return outerParamNames; }
*/
/**
* @param outerParamName
* The outerParamNames name to add to the outParamNames list.
*/
public void addOuterParamName( final String outerParamName ) {
outerParamNames.add( outerParamName );
}
}