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