sernet.gs.service.AbstractReportTemplateService.java Source code

Java tutorial

Introduction

Here is the source code for sernet.gs.service.AbstractReportTemplateService.java

Source

/*******************************************************************************
 * Copyright (c) 2014 benjamin.
 *
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3
 * 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     benjamin <bw[at]sernet[dot]de> - initial API and implementation
 ******************************************************************************/
package sernet.gs.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOCase;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.RegexFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import sernet.verinice.interfaces.IReportDepositService;
import sernet.verinice.interfaces.IReportTemplateService;
import sernet.verinice.interfaces.ReportTemplateServiceException;
import sernet.verinice.interfaces.report.IOutputFormat;
import sernet.verinice.model.report.ExcelOutputFormat;
import sernet.verinice.model.report.HTMLOutputFormat;
import sernet.verinice.model.report.ODSOutputFormat;
import sernet.verinice.model.report.ODTOutputFormat;
import sernet.verinice.model.report.PDFOutputFormat;
import sernet.verinice.model.report.PropertyFileExistsException;
import sernet.verinice.model.report.ReportTemplate;
import sernet.verinice.model.report.ReportTemplateMetaData;
import sernet.verinice.model.report.WordOutputFormat;

/**
 * Provides report template metadata and report templates.
 *
 * <p>
 * The implementation is file based, thus it can run on server side and on
 * client side. The user of this class must provide the report directory path
 * and if this directory is handled by the {@link IReportDepositService}.
 * </p>
 *
 * <p>
 * As a side effect, this implementation creates default properties for all
 * rptdesign files without a properties file automatically, if they don't exist.
 * <p>
 *
 * @author Benjamin Weienfels <bw[at]sernet[dot]de>
 *
 */
abstract public class AbstractReportTemplateService implements IReportTemplateService {

    private final Logger LOG = Logger.getLogger(AbstractReportTemplateService.class);

    abstract public boolean isHandeledByReportDeposit();

    abstract public String getTemplateDirectory();

    public ReportTemplateMetaData getMetaData(File rptDesign, String locale) throws ReportTemplateServiceException {
        try {
            Properties props = null;
            if (checkReportMetaDataFile(rptDesign, locale)) {
                props = parseAndExtendMetaData(rptDesign, locale);
            } else {
                props = createDefaultProperties(rptDesign.getPath(), rptDesign.getName(), locale);
            }
            return createReportMetaData(props);
        } catch (IOException ex) {
            handleException("error while fetching/generating metadata", ex);
        } catch (PropertyFileExistsException ex) {
            handleException("error while fetching/generating metadata", ex);
        }

        return null;
    }

    protected void handleException(String msg, Exception ex) throws ReportTemplateServiceException {
        LOG.error(msg, ex);
        throw new ReportTemplateServiceException(ex);
    }

    public boolean checkReportMetaDataFile(File rptDesign, String locale) {
        File propertiesFile = getPropertiesFile(rptDesign, locale);
        return propertiesFile.exists();
    }

    protected Properties parseAndExtendMetaData(File rptDesign, String locale) throws IOException {
        File propFile = getPropertiesFile(rptDesign, locale);
        Properties props = new Properties();
        FileInputStream fis = new FileInputStream(propFile.getAbsoluteFile());
        props.load(fis);
        fis.close();

        String fileName = FilenameUtils.getName(rptDesign.getPath());
        boolean changed = false;
        if (!(props.containsKey(PROPERTIES_FILENAME))) {
            props.setProperty(PROPERTIES_FILENAME, fileName);
            changed = true;
        }
        if (!(props.containsKey(PROPERTIES_OUTPUTFORMATS))) {
            props.setProperty(PROPERTIES_OUTPUTFORMATS, StringUtils.join(OutputFormat.values(), ","));
            changed = true;
        }
        if (!(props.containsKey(PROPERTIES_OUTPUTNAME))) {
            props.setProperty(PROPERTIES_OUTPUTNAME, removeSuffix(fileName));
            changed = true;
        }

        if (changed) {
            OutputStream out = new FileOutputStream(propFile.getAbsoluteFile());
            props.store(out, String.format("Metadata for the report deposit %s",
                    FilenameUtils.getName(rptDesign.getPath())));
        }

        return props;
    }

    private String removeSuffix(String fileName) {
        return fileName.substring(0, fileName.lastIndexOf(IReportDepositService.EXTENSION_SEPARATOR_CHAR));
    }

    public void parseAndExtendMetaData(String[] rptDesignFiles, String locale) throws IOException {
        for (String rptDesignFile : rptDesignFiles) {
            parseAndExtendMetaData(new File(rptDesignFile), locale);
        }
    }

    private File getPropertiesFile(File rptDesign, String locale) {
        String path = rptDesign.getPath();
        return getPropertiesFile(path, locale);
    }

    protected File getPropertiesFile(String path, String locale) {

        locale = sanitizeLocale(locale, path);
        path = removeSuffix(path);
        String templateDir = getTemplateDirectory();
        if (!templateDir.endsWith(String.valueOf(File.separatorChar))) {
            templateDir = templateDir + File.separatorChar;
        }
        if (!path.contains(templateDir)) {
            path = templateDir + templateDir;
        }
        File propFile = new File(path + locale + IReportDepositService.EXTENSION_SEPARATOR_CHAR
                + IReportDepositService.PROPERTIES_FILE_EXTENSION);
        return propFile;
    }

    /**
     * Generates a properties file suffix. It does not take into account
     * regions, so the string is empty, when it is the default english or the
     * default is already in the properties path.
     *
     * <p>Examples</p>
     *
     * sanitizeLocale(de_DE, "path/report_de.properties") -> ""
     * sanitizeLocale(de, "path/report_de.properties") -> ""
     * sanitizeLocale(DE, "path/report_de.properties") -> ""
     * sanitizeLocale(DE, "path/report.properties") -> "_de"
     * sanitizeLocale(en_UK, "path/report.properties") -> ""
     *
     * As we do not deal with dialects like en_UK here, we just take the
     * leftside locale (e.g. "en")
     *
     *
     */
    private String sanitizeLocale(String locale, String path) {

        if (locale.length() > 2 && locale.contains(String.valueOf('_'))) {
            locale = locale.substring(0, locale.indexOf(String.valueOf('_')));
        }

        if (!"".equals(locale)) {
            if ("en".equals(locale.toLowerCase())
                    || path.contains("_" + locale + IReportDepositService.EXTENSION_SEPARATOR_CHAR
                            + IReportDepositService.PROPERTIES_FILE_EXTENSION)) {
                locale = "";
            } else {
                locale = "_" + locale.toLowerCase();
            }
        }

        return locale;
    }

    private Properties createDefaultProperties(String path, String name, String locale)
            throws IOException, PropertyFileExistsException {
        File propFile = getPropertiesFile(path, locale);
        if (propFile.exists()) {
            throw new PropertyFileExistsException();
        } else {
            Properties props = getDefaultProperties(name);
            FileOutputStream fos = new FileOutputStream(propFile);

            props.store(fos, "Default Properties for verinice-" + "Report " + name + "\nauto-generated content");
            fos.close();
            return props;
        }

    }

    private Properties getDefaultProperties(String name) {
        Properties props = new Properties();
        props.setProperty(PROPERTIES_FILENAME, name);
        props.setProperty(PROPERTIES_OUTPUTNAME, removeSuffix(name));
        props.setProperty(PROPERTIES_OUTPUTFORMATS, StringUtils.join(OutputFormat.values(), ','));
        return props;
    }

    private ReportTemplateMetaData createReportMetaData(Properties props) throws IOException {
        String outputformatsString = props.getProperty(IReportDepositService.PROPERTIES_OUTPUTFORMATS);
        StringTokenizer tokenizer = new StringTokenizer(outputformatsString, ",");
        ArrayList<OutputFormat> formats = new ArrayList<OutputFormat>(tokenizer.countTokens());
        while (tokenizer.hasMoreTokens()) {
            String token = tokenizer.nextToken().trim();
            formats.add(OutputFormat.valueOf(token.toUpperCase()));
        }

        String fileName = props.getProperty(IReportDepositService.PROPERTIES_FILENAME);
        String outputName = props.getProperty(IReportDepositService.PROPERTIES_OUTPUTNAME);
        OutputFormat[] outputFormats = formats.toArray(new OutputFormat[formats.size()]);
        String[] md5CheckSums = getCheckSums(fileName);

        return new ReportTemplateMetaData(fileName, outputName, outputFormats, isHandeledByReportDeposit(),
                md5CheckSums);
    }

    protected Map<String, byte[]> getPropertiesFiles(String fileName) throws IOException {
        Map<String, byte[]> propertiesFiles = new TreeMap<String, byte[]>();
        Iterator<File> iter = listPropertiesFiles(fileName);
        while (iter.hasNext()) {
            File f = iter.next();
            propertiesFiles.put(f.getName(), FileUtils.readFileToByteArray(f.getAbsoluteFile()));
        }

        return propertiesFiles;
    }

    @SuppressWarnings("unchecked")
    public Iterator<File> listPropertiesFiles(String fileName) {
        String baseName = removeSuffix(fileName);
        IOFileFilter filter = new RegexFileFilter(baseName + "\\_?.*\\.properties", IOCase.INSENSITIVE);
        Iterator<File> iter = FileUtils.iterateFiles(new File(getTemplateDirectory()), filter, null);
        return iter;
    }

    private String[] getCheckSums(String fileName) throws IOException {
        String filePath;
        if (!fileName.contains(getTemplateDirectory())) {
            filePath = getTemplateDirectory() + File.separatorChar + fileName;
        } else {
            filePath = fileName;
        }
        Iterator<File> iter = listPropertiesFiles(fileName);

        List<String> md5CheckSums = new ArrayList<String>();
        md5CheckSums.add(DigestUtils.md5Hex(FileUtils.readFileToByteArray(new File(filePath))));

        while (iter.hasNext()) {
            File f = iter.next();
            md5CheckSums.add(DigestUtils.md5Hex(FileUtils.readFileToByteArray(f)));
        }

        return md5CheckSums.toArray(new String[md5CheckSums.size()]);
    }

    public Set<ReportTemplateMetaData> getReportTemplates(String[] rptDesignFiles, String locale)
            throws ReportTemplateServiceException {
        Set<ReportTemplateMetaData> set = new HashSet<ReportTemplateMetaData>();

        for (String designFilePath : rptDesignFiles) {
            set.add(getMetaData(new File(designFilePath), locale));
        }
        return set;
    }

    public Set<ReportTemplateMetaData> getReportTemplates(String locale) throws ReportTemplateServiceException {
        return getReportTemplates(getReportTemplateFileNames(), locale);
    }

    @SuppressWarnings({ "unchecked" })
    public String[] getReportTemplateFileNames() {
        List<String> list = new ArrayList<String>();
        IOFileFilter filter = new SuffixFileFilter("rptdesign", IOCase.INSENSITIVE);
        Iterator<File> iter = FileUtils.iterateFiles(new File(getTemplateDirectory()), filter, null);
        while (iter.hasNext()) {
            list.add(iter.next().getAbsolutePath());
        }
        return list.toArray(new String[list.size()]);
    }

    public IOutputFormat getOutputFormat(OutputFormat formatLabel) {
        switch (formatLabel) {
        case PDF:
            return new PDFOutputFormat();
        case HTML:
            return new HTMLOutputFormat();
        case ODS:
            return new ODSOutputFormat();
        case ODT:
            return new ODTOutputFormat();
        case XLS:
            return new ExcelOutputFormat();
        case DOC:
            return new WordOutputFormat();
        default:
            return null;
        }

    }

    public IOutputFormat[] getOutputFormats(OutputFormat[] formatLabel) {
        List<IOutputFormat> list = new ArrayList<IOutputFormat>(formatLabel.length);
        for (OutputFormat s : formatLabel) {
            IOutputFormat format = getOutputFormat(s);
            if (format != null) {
                list.add(format);
            } else {
                LOG.warn("Report output format:\t" + s + " not available in verinice");
            }
        }
        return list.toArray(new IOutputFormat[list.size()]);
    }

    @Override
    public ReportTemplate getReportTemplate(ReportTemplateMetaData metadata, String locale)
            throws ReportTemplateServiceException {
        try {

            String filePath = getTemplateDirectory() + File.separatorChar + metadata.getFilename();
            byte[] rptdesign = FileUtils.readFileToByteArray(new File(filePath));

            Map<String, byte[]> propertiesFile = getPropertiesFiles(metadata.getFilename());

            return new ReportTemplate(metadata, rptdesign, propertiesFile);
        } catch (IOException ex) {
            handleException("error while fetching template", ex);
        }

        return null;
    }

    @Override
    public Set<ReportTemplateMetaData> getServerReportTemplates(String locale)
            throws ReportTemplateServiceException {
        return getReportTemplateMetaData(getServerRptDesigns(), locale);
    }

    @Override
    public Set<ReportTemplateMetaData> getReportTemplateMetaData(String[] rptDesignFiles, String locale)
            throws ReportTemplateServiceException {
        return getReportTemplates(rptDesignFiles, locale);
    }

    @SuppressWarnings("unchecked")
    private String[] getServerRptDesigns() throws ReportTemplateServiceException {
        List<String> list = new ArrayList<String>(0);
        // // DirFilter = null means no subdirectories
        IOFileFilter filter = new SuffixFileFilter("rptdesign", IOCase.INSENSITIVE);
        Iterator<File> iter = FileUtils.iterateFiles(new File(getTemplateDirectory()), filter, null);
        while (iter.hasNext()) {
            list.add(iter.next().getAbsolutePath());
        }
        return list.toArray(new String[list.size()]);
    }

}