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 }