org.pentaho.platform.uifoundation.component.xml.WidgetGridComponent.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.platform.uifoundation.component.xml.WidgetGridComponent.java

Source

/*!
 *
 * 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 (c) 2002-2018 Hitachi Vantara. All rights reserved.
 *
 */

package org.pentaho.platform.uifoundation.component.xml;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.pentaho.commons.connection.IPentahoMetaData;
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.IPentahoRequestContext;
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.solution.ActionInfo;
import org.pentaho.platform.engine.core.system.PentahoRequestContextHolder;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.engine.services.SolutionURIResolver;
import org.pentaho.platform.engine.services.actionsequence.ActionSequenceResource;
import org.pentaho.platform.engine.services.runtime.TemplateUtil;
import org.pentaho.platform.uifoundation.chart.DialWidgetDefinition;
import org.pentaho.platform.uifoundation.chart.JFreeChartEngine;
import org.pentaho.platform.uifoundation.chart.WidgetDefinition;
import org.pentaho.platform.uifoundation.messages.Messages;
import org.pentaho.platform.util.messages.LocaleHelper;
import org.pentaho.platform.util.xml.XMLParserFactoryProducer;
import org.pentaho.platform.util.xml.dom4j.XmlDom4JHelper;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

public class WidgetGridComponent extends XmlComponent {

    /**
     * 
     */
    private static final long serialVersionUID = -3952161695550067971L;

    private String definitionPath;

    private int widgetWidth;

    private int widgetHeight;

    private String solution = null;

    private String actionPath = null;

    private String actionName = null;

    private String valueItem = null;

    private String nameItem = null;

    private int columns = 0;

    private String instanceId = null;

    private String actionOutput = null;

    private String urlTemplate = null;

    private String style = null;

    private IRuntimeContext context;

    private static final Log logger = LogFactory.getLog(WidgetGridComponent.class);

    @Override
    public Log getLogger() {
        return WidgetGridComponent.logger;
    }

    /**
     * Creates a WidgetGrid
     * <p>
     * After creating an instance of this class <CODE>validate</CODE> should be called.
     * 
     * @param type
     *          The type of the widget, currently only TYPE_DIAL is supported
     * @param definitionPath
     *          The path and name of the XML definition of the dial
     * @param widgetWidth
     *          The width of the image to be created
     * @param widgetHeight
     *          The height of the image to be created
     * @param urlFactory
     *          The urlFactory for the content
     * @param messages
     *          The messages list for any logger messages
     */
    public WidgetGridComponent(final String definitionPath, final IPentahoUrlFactory urlFactory,
            final List messages) {
        super(urlFactory, messages, null);
        this.definitionPath = definitionPath;
        ActionInfo info = ActionInfo.parseActionString(definitionPath);
        if (info != null) {
            setSourcePath(info.getSolutionName() + File.separator + info.getPath());
        }
        setXsl("text/html", "DialWidget.xsl"); //$NON-NLS-1$ //$NON-NLS-2$    
    }

    /**
     * Sets the width (in pixels) of the widget images that will be created
     * 
     * @param widgetWidth
     */
    public void setWidgetWidth(final int widgetWidth) {
        this.widgetWidth = widgetWidth;
    }

    /**
     * Sets the height (in pixels) of the widget images that will be created
     * 
     * @param widgetHeight
     */
    public void setWidgetHeight(final int widgetHeight) {
        this.widgetHeight = widgetHeight;
    }

    /**
     * Sets the number of widgets that will be dispayed in a row before another row of widgets is created
     * 
     * @param instanceId
     */
    public void setColumns(final int columns) {
        this.columns = columns;
    }

    /**
     * Sets the instance id for this execution
     * 
     * @param instanceId
     *          The instance id of the parent object or process
     */
    public void setInstanceId(final String instanceId) {
        this.instanceId = instanceId;
    }

    public boolean setDataAction(final String widgetGridDataDefinition) {
        try {
            Document dataActionDocument = null;
            try {
                org.dom4j.io.SAXReader reader = XMLParserFactoryProducer.getSAXReader(new SolutionURIResolver());
                dataActionDocument = reader.read(
                        ActionSequenceResource.getInputStream(widgetGridDataDefinition, LocaleHelper.getLocale()));
            } catch (Throwable t) {
                return false;
            }
            Node dataNode = dataActionDocument.selectSingleNode("widgetgrid/data"); //$NON-NLS-1$
            solution = XmlDom4JHelper.getNodeText("data-solution", dataNode); //$NON-NLS-1$
            actionPath = XmlDom4JHelper.getNodeText("data-path", dataNode); //$NON-NLS-1$
            actionName = XmlDom4JHelper.getNodeText("data-action", dataNode); //$NON-NLS-1$
            actionOutput = XmlDom4JHelper.getNodeText("data-output", dataNode); //$NON-NLS-1$
            valueItem = XmlDom4JHelper.getNodeText("data-value", dataNode); //$NON-NLS-1$
            nameItem = XmlDom4JHelper.getNodeText("data-name", dataNode); //$NON-NLS-1$
            widgetWidth = (int) XmlDom4JHelper.getNodeText("widgetgrid/width", dataActionDocument, 125); //$NON-NLS-1$
            widgetHeight = (int) XmlDom4JHelper.getNodeText("widgetgrid/height", dataActionDocument, 125); //$NON-NLS-1$
            columns = (int) XmlDom4JHelper.getNodeText("widgetgrid/columns", dataActionDocument, 2); //$NON-NLS-1$
            style = XmlDom4JHelper.getNodeText("widgetgrid/style", dataActionDocument); //$NON-NLS-1$
        } catch (Exception e) {
            error(Messages.getInstance().getErrorString("WidgetGrid.ERROR_0003_DEFINITION_NOT_VALID", //$NON-NLS-1$
                    widgetGridDataDefinition), e);
            return false;
        }
        return true;
    }

    /**
     * Sets the action to be executed to get the data for the widgets
     * 
     * @param solution
     * @param actionPath
     * @param actionName
     * @param actionOutput
     * @param nameItem
     * @param valueItem
     */
    public void setDataAction(final String solution, final String actionPath, final String actionName,
            final String actionOutput, final String nameItem, final String valueItem) {
        this.solution = solution;
        this.actionPath = actionPath;
        this.actionName = actionName;
        this.actionOutput = actionOutput;
        this.valueItem = valueItem;
        this.nameItem = nameItem;
    }

    public void setDrillUrlTemplate(final String urlTemplate) {
        this.urlTemplate = urlTemplate;
    }

    @Override
    public boolean validate() {
        return true;
    }

    @Override
    public Document getXmlContent() {

        // get the data to populate the widgets
        IPentahoResultSet resultSet = null;
        if (solution != null) {
            resultSet = getActionData();
        }

        // create the widget to use
        // load the XML document that defines the dial
        Document dialDefinition = null;
        try {
            org.dom4j.io.SAXReader reader = new org.dom4j.io.SAXReader();
            reader.setEntityResolver(new SolutionURIResolver());
            dialDefinition = reader
                    .read(ActionSequenceResource.getInputStream(definitionPath, LocaleHelper.getLocale()));
        } catch (Throwable t) {
            // XML document can't be read. We'll just return a null document.
        }

        // create a dial definition from the XML definition
        WidgetDefinition widgetDefinition = new DialWidgetDefinition(dialDefinition, 0, widgetWidth, widgetHeight,
                getSession());

        return createDials(resultSet, widgetDefinition);
    }

    protected Document createDials(final IPentahoResultSet resultSet, final WidgetDefinition widgetDefinition) {

        if (resultSet == null) {
            error(Messages.getInstance().getErrorString("WidgetGrid.ERROR_0001_NO_RESULTS_FROM_ACTION")); //$NON-NLS-1$
            return null;
        }

        if (valueItem == null) {
            error(Messages.getInstance().getErrorString("WidgetGrid.ERROR_0002_NO_VALUE_ITEM")); //$NON-NLS-1$
        }

        // Create a document that describes the result
        Document result = DocumentHelper.createDocument();
        IPentahoRequestContext requestContext = PentahoRequestContextHolder.getRequestContext();
        setXslProperty("baseUrl", requestContext.getContextPath()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        setXslProperty("fullyQualifiedServerUrl", //$NON-NLS-1$
                PentahoSystem.getApplicationContext().getFullyQualifiedServerURL()); //$NON-NLS-2$ //$NON-NLS-3$

        Element root = result.addElement("widgets"); //$NON-NLS-1$

        IPentahoMetaData metaData = resultSet.getMetaData();
        // TODO support multiple column headers / row headers
        // TODO support an iteration across columns for a given row

        // find the column that we have been told to you
        Object[][] columnHeaders = metaData.getColumnHeaders();
        int nameColumnNo = -1;
        int valueColumnNo = -1;
        for (int idx = 0; idx < columnHeaders[0].length; idx++) {
            if (columnHeaders[0][idx].toString().equalsIgnoreCase(nameItem)) {
                nameColumnNo = idx;
            }
            if (columnHeaders[0][idx].toString().equalsIgnoreCase(valueItem)) {
                valueColumnNo = idx;
            }
        }

        if (nameColumnNo == -1) {
            // we did not find the specified name column
            error(Messages.getInstance().getErrorString("WidgetGrid.ERROR_0004_NAME_COLUMN_MISSING", nameItem)); //$NON-NLS-1$
            return null;
        }

        if (valueColumnNo == -1) {
            // we did not find the specified name column
            error(Messages.getInstance().getErrorString("WidgetGrid.ERROR_0005_VALUE_COLUMN_MISSING", valueItem)); //$NON-NLS-1$
            return null;
        }

        double value;
        String name;
        Object[] row = resultSet.next();
        while (row != null) {
            name = row[nameColumnNo].toString();
            try {
                value = Double.parseDouble(row[valueColumnNo].toString());
                createDial(value, name, root, widgetDefinition);
            } catch (Exception e) {
                //ignore
            }

            row = resultSet.next();
        }
        setXslProperty("urlTarget", "pentaho_popup"); //$NON-NLS-1$ //$NON-NLS-2$
        setXslProperty("columns", Integer.toString(columns)); //$NON-NLS-1$
        if (style != null) {
            setXslProperty("style", style); //$NON-NLS-1$
        }
        return result;
    }

    protected void createDial(final double value, final String name, final Element root,
            final WidgetDefinition widgetDefinition) {

        widgetDefinition.setValue(new Double(value));

        StringWriter stringWriter = new StringWriter();
        PrintWriter printWriter = new PrintWriter(stringWriter);

        // TODO get units from somewhere
        String units = ""; //$NON-NLS-1$
        String dialName = ""; //$NON-NLS-1$
        // create temporary file names
        String solutionDir = "system/tmp/"; //$NON-NLS-1$
        String fileNamePrefix = "tmp_pie_"; //$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) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        JFreeChartEngine.saveChart(widgetDefinition, dialName, units, filePathWithoutExtension, widgetWidth,
                widgetHeight, JFreeChartEngine.OUTPUT_PNG, printWriter, this);

        Element widgetNode = root.addElement("widget"); //$NON-NLS-1$

        widgetNode.addElement("title").setText(name); //$NON-NLS-1$
        widgetNode.addElement("units").setText(units); //$NON-NLS-1$
        widgetNode.addElement("width").setText(Integer.toString(widgetWidth)); //$NON-NLS-1$
        widgetNode.addElement("height").setText(Integer.toString(widgetHeight)); //$NON-NLS-1$
        Element valueNode = widgetNode.addElement("value"); //$NON-NLS-1$
        valueNode.setText(Double.toString(value));
        valueNode.addAttribute("in-image", Boolean.toString(widgetDefinition.getValueFont() != null)); //$NON-NLS-1$
        root.addElement("image").setText(fileName); //$NON-NLS-1$
        widgetNode.addElement("image").setText(fileName); //$NON-NLS-1$

        // apply the current data item name to the URL template
        String drillUrl = TemplateUtil.applyTemplate(urlTemplate, nameItem, name);

        // now apply any parameters to the URL template
        drillUrl = TemplateUtil.applyTemplate(drillUrl, context);

        widgetNode.addElement("urlDrill").setText(drillUrl); //$NON-NLS-1$

    }

    public void dispose() {
        if (context != null) {
            context.dispose();
        }
    }

    protected 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();

        String actionSeqPath = ActionInfo.buildSolutionPath(solution, actionPath, actionName);

        context = solutionEngine.execute(actionSeqPath, processId, false, true, instanceId, false,
                parameterProviders, outputHandler, null, urlFactory, messages);

        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 {
            // return the first list that we find...
            Iterator it = context.getOutputNames().iterator();
            while (it.hasNext()) {
                IActionParameter output = (IActionParameter) it.next();
                if (output.getType().equalsIgnoreCase(IActionParameter.TYPE_RESULT_SET)) {
                    IPentahoResultSet results = output.getValueAsResultSet();
                    if (results != null) {
                        results = results.memoryCopy();
                    }
                    return results;
                }
            }
        }
        return null;
    }

}