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 Aug 15, 2005
014: * @author James Dixon
015: */
016:
017: package org.pentaho.ui.component;
018:
019: import java.io.File;
020: import java.io.IOException;
021: import java.io.PrintWriter;
022: import java.io.StringWriter;
023: import java.util.List;
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026: import org.dom4j.Document;
027: import org.dom4j.DocumentHelper;
028: import org.dom4j.Element;
029: import org.pentaho.messages.Messages;
030: import org.pentaho.plugin.jfreechart.DialWidgetDefinition;
031: import org.pentaho.plugin.jfreechart.WidgetDefinition;
032: import org.pentaho.core.solution.ActionResource;
033: import org.pentaho.core.solution.IActionResource;
034: import org.pentaho.core.system.PentahoSystem;
035: import org.pentaho.core.ui.IPentahoUrlFactory;
036: import org.pentaho.plugin.jfreechart.JFreeChartEngine;
037: import org.pentaho.ui.XmlComponent;
038:
039: /**
040: * This class is a Pentaho user interface component. <p/> It generates dial
041: * images that can be embedded into JSPs, portals or other HTML supporting user
042: * interface. <p/>
043: * <ol>
044: * <li> The creating object sets the width, height, the type of the dial, and
045: * the name of the dial.xml file that contains the definition of the dial.</li>
046: * <li> This class creates an instance of a DialWidgetDefinition using the
047: * specified XML definition file. The XML files are located in the solution
048: * folders and have .dial.xml extenstions. The dial XML files define the
049: * attributes that define how the dial looks. </li>
050: * <li> It uses the JFreeChartEngine to create an image of the dial.</li>
051: * <li> Once the image has been created this class creates an XML document
052: * describing the dial
053: * <li> It uses an XSL to tranforms the XML description into HTML.
054: * </ol>
055: * This is an example image
056: */
057: public class DashboardWidgetComponent extends XmlComponent {
058:
059: /**
060: *
061: */
062: private static final long serialVersionUID = 3060729271469984040L;
063:
064: public static final int TYPE_DIAL = 1;
065:
066: public static final int TYPE_THERMOMETER = 2;
067:
068: private static final Log logger = LogFactory
069: .getLog(DashboardWidgetComponent.class);
070:
071: private int type;
072:
073: private double value = TYPE_DIAL;
074:
075: private String definitionPath;
076:
077: private String title = ""; //$NON-NLS-1$
078:
079: private String units = ""; //$NON-NLS-1$
080:
081: private int width;
082:
083: private int height;
084:
085: /**
086: * Creates a DashboardWidgetComponent.
087: * <p>
088: * After creating an instance of this class <CODE>validate</CODE> should
089: * be called.
090: *
091: * @param type
092: * The type of the widget, currently only TYPE_DIAL is supported
093: * @param definitionPath
094: * The path and name of the XML definition of the dial
095: * @param width
096: * The width of the image to be created
097: * @param height
098: * The height of the image to be created
099: * @param urlFactory
100: * The urlFactory for the content
101: * @param messages
102: * The messages list for any logger messages
103: */
104: public DashboardWidgetComponent(int type, String definitionPath,
105: int width, int height, IPentahoUrlFactory urlFactory,
106: List messages) {
107: super (urlFactory, messages, null);
108: this .type = type;
109: this .definitionPath = definitionPath;
110: this .width = width;
111: this .height = height;
112: PentahoSystem.ActionInfo info = PentahoSystem
113: .parseActionString(definitionPath);
114: if (info != null) {
115: setSourcePath(info.getSolutionName() + File.separator
116: + info.getPath());
117: }
118: // Set the XSL file to be used to generate the HTML
119: setXsl("text/html", "DialWidget.xsl"); //$NON-NLS-1$ //$NON-NLS-2$
120: }
121:
122: /**
123: * Sets the value to be displayed by the dial.
124: *
125: * @param value
126: * The dial value
127: */
128: public void setValue(double value) {
129: this .value = value;
130: }
131:
132: /**
133: * Sets the title for the dial
134: *
135: * @param title
136: * The title of the dial
137: */
138: public void setTitle(String title) {
139: this .title = title;
140: }
141:
142: /**
143: * Sets the unit for the dial value
144: *
145: * @param units
146: * The dial units
147: */
148: public void setUnits(String units) {
149: this .units = units;
150: }
151:
152: /**
153: * Gets the logger for his component.
154: *
155: * @return logger This component's logger
156: */
157: public Log getLogger() {
158: return logger;
159: }
160:
161: /**
162: * Validate that this component can generate the requested dial
163: */
164: public boolean validate() {
165: // TODO
166: return true;
167: }
168:
169: /**
170: * Create a dial image.
171: * <ul>
172: * <li>Load the specified XML document describing the dial definition</li>
173: * <li>Create a dial definition object from the XML definition</li>
174: * <li>Use the JFreeChartEngine to create a dial image</li>
175: * <li>Create an XML document describing the dial</li>
176: * <li>Return the XML document</li>
177: * </ul>
178: *
179: * @return The XML document describing this dial
180: */
181: public Document getXmlContent() {
182:
183: WidgetDefinition widget = null;
184: if (type == TYPE_DIAL) {
185:
186: // load the XML document that defines the dial
187: ActionResource resource = new ActionResource(title,
188: IActionResource.SOLUTION_FILE_RESOURCE, "text/xml", //$NON-NLS-1$
189: definitionPath);
190: Document dialDefinition = null;
191: try {
192: dialDefinition = PentahoSystem.getSolutionRepository(
193: getSession()).getResourceAsDocument(resource);
194: } catch (IOException e) {
195: error(
196: Messages
197: .getErrorString(
198: "Widget.ERROR_0002_INVALID_RESOURCE", definitionPath), e); //$NON-NLS-1$
199: }
200:
201: if (dialDefinition == null) {
202: error(Messages
203: .getErrorString(
204: "Widget.ERROR_0002_INVALID_RESOURCE", definitionPath)); //$NON-NLS-1$
205: return null;
206: }
207: // create a dial definition from the XML definition
208: widget = new DialWidgetDefinition(dialDefinition, 0, width,
209: height, getSession());
210:
211: if (widget != null) {
212: // set the value to be displayed on the dial
213: widget.setValue(new Double(value));
214:
215: } else {
216: error(Messages
217: .getString("Widget.ERROR_0001_COULD_NOT_CREATE")); //$NON-NLS-1$
218: return null;
219: }
220: }
221: /*
222: * else if( type == TYPE_THERMOMETER ) { // load the XML document that
223: * defines the thermometer
224: *
225: * ActionResource resource = new ActionResource( title,
226: * IActionResource.SOLUTION_FILE_RESOURCE, "text/xml", //$NON-NLS-1$
227: * PentahoSystem.getApplicationContext().getSolutionPath( definitionPath ) );
228: * //$NON-NLS-1$ Document thermometerDefinition = null; try {
229: * thermometerDefinition = PentahoSystem.getResourceAsDocument( resource ); }
230: * catch (IOException e) {} // create a dial definition from the XML
231: * definition widget = createThermometer( thermometerDefinition );
232: *
233: * if( widget != null ) { // set the value to be displayed on the dial
234: * widget.setValue( new Double(value) ); // Set the XSL file to be used
235: * to generate the HTML setXsl( "text/html", "DialWidget.xsl" );
236: * //$NON-NLS-1$ //$NON-NLS-2$ } else { error(
237: * Messages.getString("Widget.ERROR_0001_COULD_NOT_CREATE") );
238: * //$NON-NLS-1$ return null; } }
239: */
240: if (widget == null) {
241: error(Messages
242: .getString("Widget.ERROR_0001_COULD_NOT_CREATE")); //$NON-NLS-1$
243: return null;
244: }
245: // create an image for the dial using the JFreeChart engine
246: StringWriter stringWriter = new StringWriter();
247: PrintWriter printWriter = new PrintWriter(stringWriter);
248: // create temporary file names
249: String solutionDir = "system/tmp/"; //$NON-NLS-1$
250: String fileNamePrefix = "tmp_pie_"; //$NON-NLS-1$
251: String extension = ".png"; //$NON-NLS-1$
252: String fileName = null;
253: String filePathWithoutExtension = null;
254: try {
255: File file = File.createTempFile(fileNamePrefix, extension,
256: new File(PentahoSystem.getApplicationContext()
257: .getFileOutputPath(solutionDir)));
258: file.deleteOnExit();
259: fileName = file.getName();
260: filePathWithoutExtension = solutionDir
261: + fileName.substring(0, fileName.indexOf('.'));
262: } catch (IOException e) {
263: // TODO Auto-generated catch block
264: e.printStackTrace();
265: }
266: String dialTitle = ""; //$NON-NLS-1$
267: JFreeChartEngine.saveChart(widget, dialTitle, units,
268: filePathWithoutExtension, width, height,
269: JFreeChartEngine.OUTPUT_PNG, printWriter, this );
270:
271: // Create a document that describes the result
272: Document result = DocumentHelper.createDocument();
273: String baseUrl = PentahoSystem.getApplicationContext()
274: .getBaseUrl();
275: setXslProperty("baseUrl", baseUrl); //$NON-NLS-1$
276:
277: Element root = result.addElement("widget"); //$NON-NLS-1$
278: root.addElement("title").setText(title); //$NON-NLS-1$
279: root.addElement("units").setText(units); //$NON-NLS-1$
280: root.addElement("width").setText(Integer.toString(width)); //$NON-NLS-1$
281: root.addElement("height").setText(Integer.toString(height)); //$NON-NLS-1$
282: Element valueNode = root.addElement("value");//$NON-NLS-1$
283: valueNode.setText(Double.toString(value));
284: valueNode
285: .addAttribute(
286: "in-image", Boolean.toString(widget.getValueFont() != null)); //$NON-NLS-1$
287: root.addElement("image").setText(fileName); //$NON-NLS-1$
288: return result;
289:
290: }
291:
292: public void dispose() {
293:
294: }
295:
296: }
|