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