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