001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2006, by Object Refinery Limited and Contributors.
006 *
007 * Project Info: http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022 * USA.
023 *
024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 * ---------------------
028 * ServletUtilities.java
029 * ---------------------
030 * (C) Copyright 2002-2006, by Richard Atkinson and Contributors.
031 *
032 * Original Author: Richard Atkinson;
033 * Contributor(s): J?rgen Hoffman;
034 * David Gilbert (for Object Refinery Limited);
035 * Douglas Clayton;
036 *
037 * $Id: ServletUtilities.java,v 1.3.2.3 2006/09/13 15:42:38 mungady Exp $
038 *
039 * Changes
040 * -------
041 * 19-Aug-2002 : Version 1;
042 * 20-Apr-2003 : Added additional sendTempFile method to allow MIME type
043 * specification and modified original sendTempFile method to
044 * automatically set MIME type for JPEG and PNG files
045 * 23-Jun-2003 : Added additional sendTempFile method at the request of
046 * J?rgen Hoffman;
047 * 07-Jul-2003 : Added more header information to streamed images;
048 * 19-Aug-2003 : Forced images to be stored in the temporary directory defined
049 * by System property java.io.tmpdir, rather than default (RA);
050 * 24-Mar-2004 : Added temp filename prefix attribute (DG);
051 * 09-Mar-2005 : Added "one time" file option (DG);
052 * ------------- JFREECHART 1.0.0 RELEASED ------------------------------------
053 * 10-Jan-2006 : Updated API docs and reformatted (DG);
054 * 13-Sep-2006 : Format date in response header in English, not locale default
055 * (see bug 1557141) (DG);
056 *
057 */
058
059 package org.jfree.chart.servlet;
060
061
062 import java.io.BufferedInputStream;
063 import java.io.BufferedOutputStream;
064 import java.io.File;
065 import java.io.FileInputStream;
066 import java.io.FileNotFoundException;
067 import java.io.IOException;
068 import java.text.SimpleDateFormat;
069 import java.util.Date;
070 import java.util.Locale;
071 import java.util.TimeZone;
072
073 import javax.servlet.http.HttpServletResponse;
074 import javax.servlet.http.HttpSession;
075
076 import org.jfree.chart.ChartRenderingInfo;
077 import org.jfree.chart.ChartUtilities;
078 import org.jfree.chart.JFreeChart;
079
080 /**
081 * Utility class used for servlet related JFreeChart operations.
082 */
083 public class ServletUtilities {
084
085 /** The filename prefix. */
086 private static String tempFilePrefix = "jfreechart-";
087
088 /** A prefix for "one time" charts. */
089 private static String tempOneTimeFilePrefix = "jfreechart-onetime-";
090
091 /**
092 * Returns the prefix for the temporary file names generated by this class.
093 *
094 * @return The prefix (never <code>null</code>).
095 */
096 public static String getTempFilePrefix() {
097 return ServletUtilities.tempFilePrefix;
098 }
099
100 /**
101 * Sets the prefix for the temporary file names generated by this class.
102 *
103 * @param prefix the prefix (<code>null</code> not permitted).
104 */
105 public static void setTempFilePrefix(String prefix) {
106 if (prefix == null) {
107 throw new IllegalArgumentException("Null 'prefix' argument.");
108 }
109 ServletUtilities.tempFilePrefix = prefix;
110 }
111
112 /**
113 * Returns the prefix for "one time" temporary file names generated by
114 * this class.
115 *
116 * @return The prefix.
117 */
118 public static String getTempOneTimeFilePrefix() {
119 return ServletUtilities.tempOneTimeFilePrefix;
120 }
121
122 /**
123 * Sets the prefix for the "one time" temporary file names generated by
124 * this class.
125 *
126 * @param prefix the prefix (<code>null</code> not permitted).
127 */
128 public static void setTempOneTimeFilePrefix(String prefix) {
129 if (prefix == null) {
130 throw new IllegalArgumentException("Null 'prefix' argument.");
131 }
132 ServletUtilities.tempOneTimeFilePrefix = prefix;
133 }
134
135 /**
136 * Saves the chart as a PNG format file in the temporary directory.
137 *
138 * @param chart the JFreeChart to be saved.
139 * @param width the width of the chart.
140 * @param height the height of the chart.
141 * @param session the HttpSession of the client (if <code>null</code>, the
142 * temporary file is marked as "one-time" and deleted by
143 * the {@link DisplayChart} servlet right after it is
144 * streamed to the client).
145 *
146 * @return The filename of the chart saved in the temporary directory.
147 *
148 * @throws IOException if there is a problem saving the file.
149 */
150 public static String saveChartAsPNG(JFreeChart chart, int width, int height,
151 HttpSession session) throws IOException {
152
153 return ServletUtilities.saveChartAsPNG(chart, width, height, null,
154 session);
155
156 }
157
158 /**
159 * Saves the chart as a PNG format file in the temporary directory and
160 * populates the {@link ChartRenderingInfo} object which can be used to
161 * generate an HTML image map.
162 *
163 * @param chart the chart to be saved (<code>null</code> not permitted).
164 * @param width the width of the chart.
165 * @param height the height of the chart.
166 * @param info the ChartRenderingInfo object to be populated
167 * (<code>null</code> permitted).
168 * @param session the HttpSession of the client (if <code>null</code>, the
169 * temporary file is marked as "one-time" and deleted by
170 * the {@link DisplayChart} servlet right after it is
171 * streamed to the client).
172 *
173 * @return The filename of the chart saved in the temporary directory.
174 *
175 * @throws IOException if there is a problem saving the file.
176 */
177 public static String saveChartAsPNG(JFreeChart chart, int width, int height,
178 ChartRenderingInfo info, HttpSession session) throws IOException {
179
180 if (chart == null) {
181 throw new IllegalArgumentException("Null 'chart' argument.");
182 }
183 ServletUtilities.createTempDir();
184 String prefix = ServletUtilities.tempFilePrefix;
185 if (session == null) {
186 prefix = ServletUtilities.tempOneTimeFilePrefix;
187 }
188 File tempFile = File.createTempFile(prefix, ".png",
189 new File(System.getProperty("java.io.tmpdir")));
190 ChartUtilities.saveChartAsPNG(tempFile, chart, width, height, info);
191 if (session != null) {
192 ServletUtilities.registerChartForDeletion(tempFile, session);
193 }
194 return tempFile.getName();
195
196 }
197
198 /**
199 * Saves the chart as a JPEG format file in the temporary directory.
200 * <p>
201 * SPECIAL NOTE: Please avoid using JPEG as an image format for charts,
202 * it is a "lossy" format that introduces visible distortions in the
203 * resulting image - use PNG instead. In addition, note that JPEG output
204 * is supported by JFreeChart only for JRE 1.4.2 or later.
205 *
206 * @param chart the JFreeChart to be saved.
207 * @param width the width of the chart.
208 * @param height the height of the chart.
209 * @param session the HttpSession of the client (if <code>null</code>, the
210 * temporary file is marked as "one-time" and deleted by
211 * the {@link DisplayChart} servlet right after it is
212 * streamed to the client).
213 *
214 * @return The filename of the chart saved in the temporary directory.
215 *
216 * @throws IOException if there is a problem saving the file.
217 */
218 public static String saveChartAsJPEG(JFreeChart chart, int width,
219 int height, HttpSession session)
220 throws IOException {
221
222 return ServletUtilities.saveChartAsJPEG(chart, width, height, null,
223 session);
224
225 }
226
227 /**
228 * Saves the chart as a JPEG format file in the temporary directory and
229 * populates the <code>ChartRenderingInfo</code> object which can be used
230 * to generate an HTML image map.
231 * <p>
232 * SPECIAL NOTE: Please avoid using JPEG as an image format for charts,
233 * it is a "lossy" format that introduces visible distortions in the
234 * resulting image - use PNG instead. In addition, note that JPEG output
235 * is supported by JFreeChart only for JRE 1.4.2 or later.
236 *
237 * @param chart the chart to be saved (<code>null</code> not permitted).
238 * @param width the width of the chart
239 * @param height the height of the chart
240 * @param info the ChartRenderingInfo object to be populated
241 * @param session the HttpSession of the client (if <code>null</code>, the
242 * temporary file is marked as "one-time" and deleted by
243 * the {@link DisplayChart} servlet right after it is
244 * streamed to the client).
245 *
246 * @return The filename of the chart saved in the temporary directory
247 *
248 * @throws IOException if there is a problem saving the file.
249 */
250 public static String saveChartAsJPEG(JFreeChart chart, int width,
251 int height, ChartRenderingInfo info, HttpSession session)
252 throws IOException {
253
254 if (chart == null) {
255 throw new IllegalArgumentException("Null 'chart' argument.");
256 }
257
258 ServletUtilities.createTempDir();
259 String prefix = ServletUtilities.tempFilePrefix;
260 if (session == null) {
261 prefix = ServletUtilities.tempOneTimeFilePrefix;
262 }
263 File tempFile = File.createTempFile(prefix, ".jpeg",
264 new File(System.getProperty("java.io.tmpdir")));
265 ChartUtilities.saveChartAsJPEG(tempFile, chart, width, height, info);
266 if (session != null) {
267 ServletUtilities.registerChartForDeletion(tempFile, session);
268 }
269 return tempFile.getName();
270
271 }
272
273 /**
274 * Creates the temporary directory if it does not exist. Throws a
275 * <code>RuntimeException</code> if the temporary directory is
276 * <code>null</code>. Uses the system property <code>java.io.tmpdir</code>
277 * as the temporary directory. This sounds like a strange thing to do but
278 * my temporary directory was not created on my default Tomcat 4.0.3
279 * installation. Could save some questions on the forum if it is created
280 * when not present.
281 */
282 protected static void createTempDir() {
283 String tempDirName = System.getProperty("java.io.tmpdir");
284 if (tempDirName == null) {
285 throw new RuntimeException("Temporary directory system property "
286 + "(java.io.tmpdir) is null.");
287 }
288
289 // create the temporary directory if it doesn't exist
290 File tempDir = new File(tempDirName);
291 if (!tempDir.exists()) {
292 tempDir.mkdirs();
293 }
294 }
295
296 /**
297 * Adds a {@link ChartDeleter} object to the session object with the name
298 * <code>JFreeChart_Deleter</code> if there is not already one bound to the
299 * session and adds the filename to the list of charts to be deleted.
300 *
301 * @param tempFile the file to be deleted.
302 * @param session the HTTP session of the client.
303 */
304 protected static void registerChartForDeletion(File tempFile,
305 HttpSession session) {
306
307 // Add chart to deletion list in session
308 if (session != null) {
309 ChartDeleter chartDeleter
310 = (ChartDeleter) session.getAttribute("JFreeChart_Deleter");
311 if (chartDeleter == null) {
312 chartDeleter = new ChartDeleter();
313 session.setAttribute("JFreeChart_Deleter", chartDeleter);
314 }
315 chartDeleter.addChart(tempFile.getName());
316 }
317 else {
318 System.out.println("Session is null - chart will not be deleted");
319 }
320 }
321
322 /**
323 * Binary streams the specified file in the temporary directory to the
324 * HTTP response in 1KB chunks.
325 *
326 * @param filename the name of the file in the temporary directory.
327 * @param response the HTTP response object.
328 *
329 * @throws IOException if there is an I/O problem.
330 */
331 public static void sendTempFile(String filename,
332 HttpServletResponse response) throws IOException {
333
334 File file = new File(System.getProperty("java.io.tmpdir"), filename);
335 ServletUtilities.sendTempFile(file, response);
336 }
337
338 /**
339 * Binary streams the specified file to the HTTP response in 1KB chunks.
340 *
341 * @param file the file to be streamed.
342 * @param response the HTTP response object.
343 *
344 * @throws IOException if there is an I/O problem.
345 */
346 public static void sendTempFile(File file, HttpServletResponse response)
347 throws IOException {
348
349 String mimeType = null;
350 String filename = file.getName();
351 if (filename.length() > 5) {
352 if (filename.substring(filename.length() - 5,
353 filename.length()).equals(".jpeg")) {
354 mimeType = "image/jpeg";
355 }
356 else if (filename.substring(filename.length() - 4,
357 filename.length()).equals(".png")) {
358 mimeType = "image/png";
359 }
360 }
361 ServletUtilities.sendTempFile(file, response, mimeType);
362 }
363
364 /**
365 * Binary streams the specified file to the HTTP response in 1KB chunks.
366 *
367 * @param file the file to be streamed.
368 * @param response the HTTP response object.
369 * @param mimeType the mime type of the file, null allowed.
370 *
371 * @throws IOException if there is an I/O problem.
372 */
373 public static void sendTempFile(File file, HttpServletResponse response,
374 String mimeType) throws IOException {
375
376 if (file.exists()) {
377 BufferedInputStream bis = new BufferedInputStream(
378 new FileInputStream(file));
379
380 // Set HTTP headers
381 if (mimeType != null) {
382 response.setHeader("Content-Type", mimeType);
383 }
384 response.setHeader("Content-Length", String.valueOf(file.length()));
385 SimpleDateFormat sdf = new SimpleDateFormat(
386 "EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
387 sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
388 response.setHeader("Last-Modified",
389 sdf.format(new Date(file.lastModified())));
390
391 BufferedOutputStream bos = new BufferedOutputStream(
392 response.getOutputStream());
393 byte[] input = new byte[1024];
394 boolean eof = false;
395 while (!eof) {
396 int length = bis.read(input);
397 if (length == -1) {
398 eof = true;
399 }
400 else {
401 bos.write(input, 0, length);
402 }
403 }
404 bos.flush();
405 bis.close();
406 bos.close();
407 }
408 else {
409 throw new FileNotFoundException(file.getAbsolutePath());
410 }
411 return;
412 }
413
414 /**
415 * Perform a search/replace operation on a String
416 * There are String methods to do this since (JDK 1.4)
417 *
418 * @param inputString the String to have the search/replace operation.
419 * @param searchString the search String.
420 * @param replaceString the replace String.
421 *
422 * @return The String with the replacements made.
423 */
424 public static String searchReplace(String inputString,
425 String searchString,
426 String replaceString) {
427
428 int i = inputString.indexOf(searchString);
429 if (i == -1) {
430 return inputString;
431 }
432
433 String r = "";
434 r += inputString.substring(0, i) + replaceString;
435 if (i + searchString.length() < inputString.length()) {
436 r += searchReplace(inputString.substring(i + searchString.length()),
437 searchString, replaceString);
438 }
439
440 return r;
441 }
442
443 }