edu.ku.brc.specify.tasks.subpane.JasperReportsCache.java Source code

Java tutorial

Introduction

Here is the source code for edu.ku.brc.specify.tasks.subpane.JasperReportsCache.java

Source

/* Copyright (C) 2015, University of Kansas Center for Research
 * 
 * Specify Software Project, specify@ku.edu, Biodiversity Institute,
 * 1345 Jayhawk Boulevard, Lawrence, Kansas, 66045, USA
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package edu.ku.brc.specify.tasks.subpane;

import java.io.File;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import edu.ku.brc.af.core.AppContextMgr;
import edu.ku.brc.af.core.AppResourceIFace;
import edu.ku.brc.af.prefs.AppPreferences;
import edu.ku.brc.helpers.XMLHelper;
import edu.ku.brc.specify.config.SpecifyAppContextMgr;
import edu.ku.brc.ui.UIHelper;
import edu.ku.brc.ui.UIRegistry;
import edu.ku.brc.util.DataCacheIFace;

/**
 * Cache for JasperReports. This class cal refresh the actual reports from the AppResourceManager and 
 * also check to see if they need to be recompiled.
 * 
 * @author rod
 *
 * @code_status Compete
 *
 * Apr 29, 2007
 *
 */
public class JasperReportsCache implements DataCacheIFace {
    // Static Data Members
    private static final Logger log = Logger.getLogger(LabelsPane.class);

    private static boolean reportsCacheWasCleared = false;
    private static JasperReportsCache instance = new JasperReportsCache();
    private static String reportsCacheName;

    /**
     * Constructor.
     */
    protected JasperReportsCache() {
        // XXX FOR WORKBENCH RELEASE ONLY (Maybe we need to keep this)
        reportsCacheName = "reportsCache_" + UIHelper.getOSType().toString();
    }

    /**
     * @return the instance
     */
    public static JasperReportsCache getInstance() {
        return instance;
    }

    /**
     * Returns the path to where the images are located that will be usd in the reports/labels.
     * This path comes from the preference REPORT_IMAGE_PATH
     * 
     * @return a path to the directory where the ijmages are stored
     */
    public static File getImagePath() {
        File imageDir;

        String imgPath = AppPreferences.getRemote().get("REPORT_IMAGE_PATH", null);
        if (UIHelper.isMacOS()) {
            String macPath = AppPreferences.getRemote().get("REPORT_IMAGE_PATH_MAC", "");
            if (StringUtils.isNotEmpty(macPath)) {
                imgPath = macPath;
            }
        } else if (UIHelper.isLinux()) {
            String linuxPath = AppPreferences.getRemote().get("REPORT_IMAGE_PATH_LINUX", "");
            if (StringUtils.isNotEmpty(linuxPath)) {
                imgPath = linuxPath;
            }
        }
        if (StringUtils.isNotEmpty(imgPath)) {
            imageDir = new File(imgPath);
        } else {
            imageDir = UIRegistry.getAppDataSubDir("report_images", false);
        }

        // XXXX RELEASE - This Reference to demo_files will need to be removed
        if (!imageDir.exists()) {
            imageDir = new File(UIRegistry.getDefaultWorkingPath() + File.separator + "demo_files");
        }

        return imageDir;
    }

    /**
     * @return
     */
    public static File getCachePath() {
        File path = UIRegistry.getAppDataSubDir(reportsCacheName, true);
        if (path == null) {
            String msg = "The reportsCache directory path is empty.";
            log.error(msg);
            throw new RuntimeException(msg);
        }
        return path;
    }

    /**
     * XXX This really needs to be moved to a more centralized storage
     *
     */
    public static File checkAndCreateReportsCache() {
        File path = getCachePath();

        // If the JVM version (Major Version) has changed the JasperReports need to be recompiled
        // so we remove all the ".jasper" files so they can be recompiled.
        // XXX isNewJavaVersionAtAppStart should be moved to a more generic place
        if (SpecifyAppContextMgr.isNewJavaVersionAtAppStart() && !reportsCacheWasCleared) {
            clearJasperFilesOnly(path);

            reportsCacheWasCleared = true;
        }

        return path;
    }

    /**
     * Clears the compiled files that are JVM dependent.
     * @param cachePath the path to the cache
     */
    protected static void clearJasperFilesOnly(final File cachePath) {
        try {
            for (Iterator<?> iter = FileUtils.iterateFiles(cachePath, new String[] { "jasper" }, false); iter
                    .hasNext();) {
                FileUtils.forceDelete((File) iter.next());
            }
        } catch (Exception ex) {
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(JasperReportsCache.class, ex);
            log.error(ex);
        }
    }

    /**
     * Checks to see if any files in the database need to be copied to the database. A file may not
     * exist or be out of date.
     */
    public static void refreshCacheFromDatabase() {
        refreshCacheFromDatabase("jrxml/label");
        refreshCacheFromDatabase("jrxml/report");
        refreshCacheFromDatabase("jrxml/subreport");
    }

    /**
     * Checks to see if any files in the database need to be copied to the database. A file may not
     * exist or be out of date.
     */
    protected static void refreshCacheFromDatabase(final String mimeType) {
        File cachePath = getCachePath();

        Hashtable<String, File> hash = new Hashtable<String, File>();
        for (File f : cachePath.listFiles()) {
            //log.info("Report Cache File["+f.getName()+"]");
            hash.put(f.getName(), f);
        }

        for (AppResourceIFace ap : AppContextMgr.getInstance().getResourceByMimeType(mimeType)) {
            // Check to see if the resource or file has changed.
            boolean updateCache = false;
            File fileFromJasperCache = hash.get(ap.getName());
            if (fileFromJasperCache == null) {
                updateCache = true;

            } else {
                Date fileDate = new Date(fileFromJasperCache.lastModified());
                Timestamp apTime = ap.getTimestampModified() == null ? ap.getTimestampCreated()
                        : ap.getTimestampModified();
                updateCache = apTime == null || fileDate.getTime() < apTime.getTime();
            }

            // If it has changed then copy the contents into the cache and delete the compiled file
            // so it forces it to be recompiled.
            if (updateCache) {
                File localFilePath = new File(cachePath.getAbsoluteFile() + File.separator + ap.getName());
                try {
                    XMLHelper.setContents(localFilePath, ap.getDataAsString());

                    File compiledFile = getCompiledFile(localFilePath);
                    if (compiledFile.exists()) {
                        compiledFile.delete();
                    }

                } catch (Exception ex) {
                    edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                    edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(JasperReportsCache.class, ex);
                    throw new RuntimeException(ex);
                }
            }
        }
    }

    /**
     * @param file the jrxml file
     * @return the xxxx.jasper file name (the compiled name)
     */
    protected static File getCompiledFile(final File file) {
        String fileName = file.getName();

        String compiledName = FilenameUtils.getBaseName(fileName) + ".jasper";

        return new File(getCachePath().getAbsoluteFile() + File.separator + compiledName);
    }

    /**
     * @return the reportsCacheWasCleared
     */
    public static boolean isReportsCacheWasCleared() {
        return reportsCacheWasCleared;
    }

    /**
     * Starts the report creation process
     * @param fileName the XML file name of the report definition
     * @param recrdSet the recordset to use to fill the labels
     */
    public static ReportCompileInfo checkReport(final File file) {
        File cachePath = getCachePath();
        String fileName = file.getName();
        File compiledPath = getCompiledFile(file);

        AppResourceIFace appRes = AppContextMgr.getInstance().getResource(fileName);

        File reportFileFromCache = new File(cachePath.getAbsoluteFile() + File.separator + fileName);

        // Check to see if it needs to be recompiled, if it doesn't need compiling then
        // call "compileComplete" directly to have it start filling the labels
        // otherswise create the compiler runnable and have it be compiled 
        // asynchronously

        Timestamp apTime = appRes.getTimestampModified() == null ? appRes.getTimestampCreated()
                : appRes.getTimestampModified();
        boolean needsCompiling = apTime == null || !compiledPath.exists()
                || apTime.getTime() > reportFileFromCache.lastModified();

        //log.debug(appRes.getTimestampModified().getTime()+" > "+reportFileFromCache.lastModified() +"  "+(appRes.getTimestampModified().getTime() > reportFileFromCache.lastModified()));
        //log.debug(compiledPath.exists());
        //log.debug("needsCompiling "+needsCompiling);
        return new ReportCompileInfo(reportFileFromCache, compiledPath, needsCompiling);
    }

    public static void clearCache() {
        try {
            FileUtils.cleanDirectory(getCachePath());

        } catch (Exception ex) {
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(JasperReportsCache.class, ex);
            log.error(ex);
        }
    }
    //------------------------------------------------------
    // DataCacheIFace Interface
    //------------------------------------------------------

    /* (non-Javadoc)
     * @see edu.ku.brc.util.DataCacheIFace#clear()
     */
    public void clear() {
        clearCache();
    }

    /* (non-Javadoc)
     * @see edu.ku.brc.util.DataCacheIFace#shutdown()
     */
    public void shutdown() throws Exception {
        //TODO Auto-generated method stub
    }
}