001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2005, 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-2005, 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.1 2005/10/25 20:58:06 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     *
053     */
054    
055    package org.jfree.chart.servlet;
056    
057    import java.io.BufferedInputStream;
058    import java.io.BufferedOutputStream;
059    import java.io.File;
060    import java.io.FileInputStream;
061    import java.io.FileNotFoundException;
062    import java.io.IOException;
063    import java.text.SimpleDateFormat;
064    import java.util.Date;
065    import java.util.TimeZone;
066    
067    import javax.servlet.http.HttpServletResponse;
068    import javax.servlet.http.HttpSession;
069    
070    import org.jfree.chart.ChartRenderingInfo;
071    import org.jfree.chart.ChartUtilities;
072    import org.jfree.chart.JFreeChart;
073    
074    /**
075     * Utility class used for servlet related JFreeChart operations.
076     *
077     * @author Richard Atkinson
078     */
079    public class ServletUtilities {
080    
081        /** The filename prefix. */
082        private static String tempFilePrefix = "jfreechart-";
083        
084        /** A prefix for "one time" charts. */
085        private static String tempOneTimeFilePrefix = "jfreechart-onetime-";
086        
087        /**
088         * Returns the prefix for the temporary file names generated by this class.
089         * 
090         * @return The prefix (never <code>null</code>).
091         */
092        public static String getTempFilePrefix() {
093            return ServletUtilities.tempFilePrefix;   
094        }
095        
096        /**
097         * Sets the prefix for the temporary file names generated by this class.
098         * 
099         * @param prefix  the prefix (<code>null</code> not permitted).
100         */
101        public static void setTempFilePrefix(String prefix) {
102            if (prefix == null) {
103                throw new IllegalArgumentException("Null 'prefix' argument.");   
104            }
105            ServletUtilities.tempFilePrefix = prefix;
106        }
107        
108        /**
109         * Returns the prefix for "one time" temporary file names generated by
110         * this class.
111         * 
112         * @return The prefix.
113         */
114        public static String getTempOneTimeFilePrefix() {
115            return ServletUtilities.tempOneTimeFilePrefix;
116        }
117        
118        /**
119         * Sets the prefix for the "one time" temporary file names generated by 
120         * this class.
121         * 
122         * @param prefix  the prefix (<code>null</code> not permitted).
123         */
124        public static void setTempOneTimeFilePrefix(String prefix) {
125            if (prefix == null) {
126                throw new IllegalArgumentException("Null 'prefix' argument.");   
127            }
128            ServletUtilities.tempOneTimeFilePrefix = prefix;
129        }
130        
131        /**
132         * Saves the chart as a PNG format file in the temporary directory.
133         *
134         * @param chart  the JFreeChart to be saved.
135         * @param width  the width of the chart.
136         * @param height  the height of the chart.
137         * @param session  the HttpSession of the client (if <code>null</code>, the
138         *                 temporary file is marked as "one-time" and deleted by 
139         *                 the {@link DisplayChart} servlet right after it is
140         *                 streamed to the client).
141         *
142         * @return The filename of the chart saved in the temporary directory.
143         *
144         * @throws IOException if there is a problem saving the file.
145         */
146        public static String saveChartAsPNG(JFreeChart chart, int width, int height,
147                                            HttpSession session) 
148                throws IOException {
149    
150            return ServletUtilities.saveChartAsPNG(
151                chart, width, height, null, session
152            );
153            
154        }
155    
156        /**
157         * Saves the chart as a PNG format file in the temporary directory and
158         * populates the {@link ChartRenderingInfo} object which can be used to 
159         * generate an HTML image map.
160         *
161         * @param chart  the chart to be saved (<code>null</code> not permitted).
162         * @param width  the width of the chart.
163         * @param height  the height of the chart.
164         * @param info  the ChartRenderingInfo object to be populated 
165         *              (<code>null</code> permitted).
166         * @param session  the HttpSession of the client (if <code>null</code>, the
167         *                 temporary file is marked as "one-time" and deleted by 
168         *                 the {@link DisplayChart} servlet right after it is
169         *                 streamed to the client).
170         *
171         * @return The filename of the chart saved in the temporary directory.
172         *
173         * @throws IOException if there is a problem saving the file.
174         */
175        public static String saveChartAsPNG(JFreeChart chart, int width, int height,
176                                            ChartRenderingInfo info, 
177                                            HttpSession session)
178                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(
189                prefix, ".png", new File(System.getProperty("java.io.tmpdir"))
190            );
191            ChartUtilities.saveChartAsPNG(tempFile, chart, width, height, info);
192            if (session != null) {
193                ServletUtilities.registerChartForDeletion(tempFile, session);
194            }
195            return tempFile.getName();
196    
197        }
198    
199        /**
200         * Saves the chart as a JPEG format file in the temporary directory.
201         *
202         * @param chart  the JFreeChart to be saved.
203         * @param width  the width of the chart.
204         * @param height  the height of the chart.
205         * @param session  the HttpSession of the client (if <code>null</code>, the
206         *                 temporary file is marked as "one-time" and deleted by 
207         *                 the {@link DisplayChart} servlet right after it is
208         *                 streamed to the client).
209         *
210         * @return The filename of the chart saved in the temporary directory.
211         *
212         * @throws IOException if there is a problem saving the file.
213         */
214        public static String saveChartAsJPEG(JFreeChart chart, int width, 
215                                             int height, HttpSession session) 
216                throws IOException {
217    
218            return ServletUtilities.saveChartAsJPEG(
219                chart, width, height, null, session
220            );
221            
222        }
223    
224        /**
225         * Saves the chart as a JPEG format file in the temporary directory and
226         * populates the ChartRenderingInfo object which can be used to generate
227         * an HTML image map.
228         *
229         * @param chart  the chart to be saved (<code>null</code> not permitted).
230         * @param width  the width of the chart
231         * @param height  the height of the chart
232         * @param info  the ChartRenderingInfo object to be populated
233         * @param session  the HttpSession of the client (if <code>null</code>, the
234         *                 temporary file is marked as "one-time" and deleted by 
235         *                 the {@link DisplayChart} servlet right after it is
236         *                 streamed to the client).
237         *
238         * @return The filename of the chart saved in the temporary directory
239         *
240         * @throws IOException if there is a problem saving the file.
241         */
242        public static String saveChartAsJPEG(JFreeChart chart, int width, 
243                                             int height, ChartRenderingInfo info, 
244                                             HttpSession session)
245                throws IOException {
246    
247            if (chart == null) {
248                throw new IllegalArgumentException("Null 'chart' argument.");   
249            }
250            
251            ServletUtilities.createTempDir();
252            String prefix = ServletUtilities.tempFilePrefix;
253            if (session == null) {
254                prefix = ServletUtilities.tempOneTimeFilePrefix;   
255            }
256            File tempFile = File.createTempFile(
257                prefix, ".jpeg", new File(System.getProperty("java.io.tmpdir"))
258            );
259            ChartUtilities.saveChartAsJPEG(tempFile, chart, width, height, info);
260            if (session != null) {
261                ServletUtilities.registerChartForDeletion(tempFile, session);
262            }
263            return tempFile.getName();
264    
265        }
266    
267        /**
268         * Creates the temporary directory if it does not exist.  Throws a 
269         * <code>RuntimeException</code> if the temporary directory is 
270         * <code>null</code>.  Uses the system property <code>java.io.tmpdir</code> 
271         * as the temporary directory.  This sounds like a strange thing to do but 
272         * my temporary directory was not created on my default Tomcat 4.0.3 
273         * installation.  Could save some questions on the forum if it is created 
274         * when not present.
275         */
276        protected static void createTempDir() {
277            String tempDirName = System.getProperty("java.io.tmpdir");
278            if (tempDirName == null) {
279                throw new RuntimeException(
280                    "Temporary directory system property (java.io.tmpdir) is null."
281                );
282            }
283    
284            // create the temporary directory if it doesn't exist
285            File tempDir = new File(tempDirName);
286            if (!tempDir.exists()) {
287                tempDir.mkdirs();
288            }
289        }
290    
291        /**
292         * Adds a {@link ChartDeleter} object to the session object with the name 
293         * <code>JFreeChart_Deleter</code> if there is not already one bound to the 
294         * session and adds the filename to the list of charts to be deleted.
295         *
296         * @param tempFile  the file to be deleted.
297         * @param session  the HTTP session of the client.
298         */
299        protected static void registerChartForDeletion(File tempFile, 
300                                                       HttpSession session) {
301    
302            //  Add chart to deletion list in session
303            if (session != null) {
304                ChartDeleter chartDeleter 
305                    = (ChartDeleter) session.getAttribute("JFreeChart_Deleter");
306                if (chartDeleter == null) {
307                    chartDeleter = new ChartDeleter();
308                    session.setAttribute("JFreeChart_Deleter", chartDeleter);
309                }
310                chartDeleter.addChart(tempFile.getName());
311            }
312            else {
313                System.out.println("Session is null - chart will not be deleted");
314            }
315        }
316    
317        /**
318         * Binary streams the specified file in the temporary directory to the
319         * HTTP response in 1KB chunks.
320         * 
321         * @param filename  the name of the file in the temporary directory.
322         * @param response  the HTTP response object.
323         * 
324         * @throws IOException  if there is an I/O problem.
325         */
326        public static void sendTempFile(String filename, 
327                                        HttpServletResponse response)
328            throws IOException {
329    
330            File file = new File(System.getProperty("java.io.tmpdir"), filename);
331            ServletUtilities.sendTempFile(file, response);
332        }
333    
334        /**
335         * Binary streams the specified file to the HTTP response in 1KB chunks.
336         *
337         * @param file  the file to be streamed.
338         * @param response  the HTTP response object.
339         *
340         * @throws IOException if there is an I/O problem.
341         */
342        public static void sendTempFile(File file, HttpServletResponse response)
343                throws IOException {
344    
345            String mimeType = null;
346            String filename = file.getName();
347            if (filename.length() > 5) {
348                if (filename.substring(filename.length() - 5, 
349                        filename.length()).equals(".jpeg")) {
350                    mimeType = "image/jpeg";
351                } 
352                else if (filename.substring(filename.length() - 4, 
353                        filename.length()).equals(".png")) {
354                    mimeType = "image/png";
355                }
356            }
357            ServletUtilities.sendTempFile(file, response, mimeType);
358        }
359    
360        /**
361         * Binary streams the specified file to the HTTP response in 1KB chunks.
362         *
363         * @param file  the file to be streamed.
364         * @param response  the HTTP response object.
365         * @param mimeType  the mime type of the file, null allowed.
366         *
367         * @throws IOException if there is an I/O problem.
368         */
369        public static void sendTempFile(File file, HttpServletResponse response,
370                                        String mimeType) throws IOException {
371    
372            if (file.exists()) {
373                BufferedInputStream bis = new BufferedInputStream(
374                    new FileInputStream(file)
375                );
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"
384                );
385                sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
386                response.setHeader(
387                    "Last-Modified", sdf.format(new Date(file.lastModified()))
388                );
389    
390                BufferedOutputStream bos = new BufferedOutputStream(
391                    response.getOutputStream()
392                );
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(
437                    inputString.substring(i + searchString.length()),
438                    searchString, replaceString
439                );
440            }
441    
442            return r;
443        }
444    
445    }