    001/* ===========================================================
    002 * JFreeChart : a free chart library for the Java(tm) platform
    003 * ===========================================================
    004 *
    005 * (C) Copyright 2000-2011, 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 * [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-2008, 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
    057package org.jfree.chart.servlet;
    058
    059import java.io.BufferedInputStream;
    060import java.io.BufferedOutputStream;
    061import java.io.File;
    062import java.io.FileInputStream;
    063import java.io.FileNotFoundException;
    064import java.io.IOException;
    065import java.text.SimpleDateFormat;
    066import java.util.Date;
    067import java.util.Locale;
    068import java.util.TimeZone;
    069
    070import javax.servlet.http.HttpServletResponse;
    071import javax.servlet.http.HttpSession;
    072
    073import org.jfree.chart.ChartRenderingInfo;
    074import org.jfree.chart.ChartUtilities;
    075import org.jfree.chart.JFreeChart;
    076
    077/**
    078 * Utility class used for servlet related JFreeChart operations.
    079 */
    080public 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}