    001    /* ===========================================================
    002     * JFreeChart : a free chart library for the Java(tm) platform
    003     * ===========================================================
    004     *
    005     * (C) Copyright 2000-2007, 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-2007, 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    }