001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2008, 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-2008, 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 }