    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    }