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    }