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    }