org.opennms.features.vaadin.pmatrix.calculator.PmatrixDpdCalculatorRepository.java Source code

Java tutorial

Introduction

Here is the source code for org.opennms.features.vaadin.pmatrix.calculator.PmatrixDpdCalculatorRepository.java

Source

/*******************************************************************************
 * This file is part of OpenNMS(R).
 *
 * Copyright (C) 2010-2012 The OpenNMS Group, Inc.
 * OpenNMS(R) is Copyright (C) 1999-2012 The OpenNMS Group, Inc.
 *
 * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
 *
 * OpenNMS(R) 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 3 of the License,
 * or (at your option) any later version.
 *
 * OpenNMS(R) 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 OpenNMS(R).  If not, see:
 *      http://www.gnu.org/licenses/
 *
 * For more information contact:
 *     OpenNMS(R) Licensing <license@opennms.org>
 *     http://www.opennms.org/
 *     http://www.opennms.com/
 *******************************************************************************/

package org.opennms.features.vaadin.pmatrix.calculator;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import javax.annotation.PostConstruct;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

/**
 * PmatrixDpdCalculatorRepository is used to persist a dataPointMap of historic calculations
 */
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
@XmlType(name = "PmatrixDpdCalculatorRepository", propOrder = { "datePersisted", "dataPointMap" })
public class PmatrixDpdCalculatorRepository implements ResourceLoaderAware {
    private static final Logger LOG = LoggerFactory.getLogger(PmatrixDpdCalculatorRepository.class);

    static final String dateFormatString = "yyyymmddhhmmss";

    /**
     *  used by Spring ResourceLoaderAware interface
     */
    private ResourceLoader resourceLoader = null;

    /**
     * Maximum number of old archived files to keep before the oldest one is deleted
     */
    private int archiveFileMaxNumber = 1;

    /**
     * directory where the archive files are stored
     */
    private String archiveFileDirectoryLocation = null;

    /**
     * name of the current archive file. 
     * Note that the older archive files have a date appended to this name
     */
    private String archiveFileName = null;

    /**
     * if false no data history will be used
     * if true historic date will be loaded on startup from pmatrix.archive.fileName and saved by running application
     * to pmatrix.archive.fileName. Each time a new <archiveFileName>, is saved, the old file is renamed <archiveFileName><Date>
     */
    private boolean persistHistoricData = true;

    /**
     * set to true if repository has been successfully loaded from persistence file
     */
    private boolean repositoryLoaded = false;

    private Map<String, PmatrixDpdCalculator> dataPointMap = new HashMap<String, PmatrixDpdCalculator>();

    private Date datePersisted;

    /**
     * used by Spring ResourceLoaderAware interface to inject resource loader into bean
     */
    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    /**
     * @return the archiveFileLocation
     */
    public String getArchiveFileName() {
        return archiveFileName;
    }

    /**
     * Name of the file to use to load and save an archive
     * @param archiveFileName the archiveFileLocation to set
     */
    public void setArchiveFileName(String archiveFileName) {
        this.archiveFileName = archiveFileName;
    }

    /**
     * gets the location of the directory where the archive files are stored
     * @return the archiveFileDirectoryLocation
     */
    public String getArchiveFileDirectoryLocation() {
        return archiveFileDirectoryLocation;
    }

    /**
     * Sets the location of the directory where the archive files are stored
     * @param archiveFileDirectoryLocation the archiveFileDirectoryLocation to set
     */
    public void setArchiveFileDirectoryLocation(String archiveFileDirectoryLocation) {
        this.archiveFileDirectoryLocation = archiveFileDirectoryLocation;
    }

    /**
     * @return the archiveFileMaxNumber
     */
    public int getArchiveFileMaxNumber() {
        return archiveFileMaxNumber;
    }

    /**
     * @param archiveFileMaxNumber the archiveFileMaxNumber to set
     */
    public void setArchiveFileMaxNumber(int archiveFileMaxNumber) {
        this.archiveFileMaxNumber = archiveFileMaxNumber;
    }

    /**
     * @return the persistHistoricData
     */
    public boolean isPersistHistoricData() {
        return persistHistoricData;
    }

    /**
     * @param persistHistoricData the persistHistoricData to set
     */
    public void setPersistHistoricData(boolean persistHistoricData) {
        this.persistHistoricData = persistHistoricData;
    }

    /**
     * Returns true if the repository loaded the archive file successfully
     * @return the repositoryLoaded
     */
    public boolean getRepositoryLoaded() {
        return repositoryLoaded;
    }

    /**
     * @return the datePersisted
     */
    @XmlElement
    public Date getDatePersisted() {
        return datePersisted;
    }

    /**
     * @param datePersisted the datePersisted to set
     */
    public void setDatePersisted(Date datePersisted) {
        this.datePersisted = datePersisted;
    }

    @XmlElement()
    public Map<String, PmatrixDpdCalculator> getDataPointMap() {
        return dataPointMap;
    }

    public void setDataPointMap(Map<String, PmatrixDpdCalculator> dataPointMap) {
        this.dataPointMap = dataPointMap;
    }

    /**
     * Causes the dataPointMap to be persisted to a file
     * @param file file definition to persist the data set to
     * @return true if dataPointMap persisted correctly, false if not
     */
    public boolean persist() {
        File currentArchiveFile = null;
        File tmpCurrentArchiveFile = null;
        Resource tmpResource = null;

        if (!persistHistoricData) {
            LOG.debug("not persisting data as persistHistoricData=false");
            return false;
        }

        if (archiveFileName == null || archiveFileDirectoryLocation == null) {
            LOG.error("cannot save historical data to file as incorrect file location:"
                    + " archiveFileDirectoryLocation=" + archiveFileDirectoryLocation + " archiveFileName="
                    + archiveFileName);
            return false;
        }

        // set the date on which this file was persisted
        datePersisted = new Date();

        // used to get file name suffix
        SimpleDateFormat dateFormatter = new SimpleDateFormat(dateFormatString);

        // persist data to temporary file <archiveFileName.tmp>
        String tmpArchiveFileName = archiveFileName + ".tmp";
        String tmpArchiveFileLocation = archiveFileDirectoryLocation + File.separator + tmpArchiveFileName;
        LOG.debug("historical data will be written to temporary file :" + tmpArchiveFileLocation);

        try {
            tmpResource = resourceLoader.getResource(tmpArchiveFileLocation);
            tmpCurrentArchiveFile = new File(tmpResource.getURL().getFile());
        } catch (IOException e) {
            LOG.error("cannot save historical data to file at archiveFileLocation='" + tmpArchiveFileLocation
                    + "' due to error:", e);
            return false;
        }

        LOG.debug(
                "persisting historical data to temporary file location:" + tmpCurrentArchiveFile.getAbsolutePath());

        // marshal the data
        PrintWriter writer = null;
        boolean marshalledCorrectly = false;
        try {
            // create  directory if doesn't exist
            File directory = new File(tmpCurrentArchiveFile.getParentFile().getAbsolutePath());
            directory.mkdirs();
            // create file if doesn't exist
            writer = new PrintWriter(tmpCurrentArchiveFile, "UTF-8");
            writer.close();

            // see http://stackoverflow.com/questions/1043109/why-cant-jaxb-find-my-jaxb-index-when-running-inside-apache-felix
            // need to provide bundles class loader
            ClassLoader cl = org.opennms.features.vaadin.pmatrix.model.DataPointDefinition.class.getClassLoader();
            JAXBContext jaxbContext = JAXBContext.newInstance(
                    "org.opennms.features.vaadin.pmatrix.model:org.opennms.features.vaadin.pmatrix.calculator", cl);

            //JAXBContext jaxbContext = JAXBContext.newInstance("org.opennms.features.vaadin.pmatrix.model:org.opennms.features.vaadin.pmatrix.calculator");

            Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
            jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");

            // TODO CHANGE output pretty printed
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            // marshal this Data Repository
            jaxbMarshaller.marshal(this, tmpCurrentArchiveFile);

            marshalledCorrectly = true;
        } catch (JAXBException e) {
            LOG.error("problem marshalling file: ", e);
        } catch (Exception e) {
            LOG.error("problem marshalling file: ", e);
        } finally {
            if (writer != null)
                writer.close();
        }
        if (marshalledCorrectly == false)
            return false;

        // marshaling succeeded so rename tmp file
        String archiveFileLocation = archiveFileDirectoryLocation + File.separator + archiveFileName;
        LOG.info("historical data will be written to:" + archiveFileLocation);

        Resource resource = resourceLoader.getResource(archiveFileLocation);

        if (resource.exists()) {
            String oldArchiveFileName = archiveFileName + "." + dateFormatter.format(datePersisted);
            String oldArchiveFileLocation = archiveFileDirectoryLocation + File.separator + oldArchiveFileName;
            LOG.info("previous historical file at archiveFileLocation='" + archiveFileLocation
                    + "' exists so being renamed to " + oldArchiveFileLocation);
            Resource oldresource = resourceLoader.getResource(oldArchiveFileLocation);
            try {
                currentArchiveFile = new File(resource.getURL().getFile());
                File oldArchiveFile = new File(oldresource.getURL().getFile());
                // rename current archive file to old archive file name
                if (!currentArchiveFile.renameTo(oldArchiveFile)) {
                    throw new IOException("cannot rename current archive file:"
                            + currentArchiveFile.getAbsolutePath() + " to " + oldArchiveFile.getAbsolutePath());
                }
                // rename temporary archive file to current archive file name
                if (!tmpCurrentArchiveFile.renameTo(currentArchiveFile)) {
                    throw new IOException("cannot rename temporary current archive file:"
                            + tmpCurrentArchiveFile.getAbsolutePath() + " to "
                            + currentArchiveFile.getAbsolutePath());
                }
            } catch (IOException e) {
                LOG.error("Problem archiving old persistance file", e);
            }
            // remove excess files
            try {
                Resource directoryResource = resourceLoader.getResource(archiveFileDirectoryLocation);
                File archiveFolder = new File(directoryResource.getURL().getFile());
                File[] listOfFiles = archiveFolder.listFiles();

                String filename;
                //this will sort earliest to latest date
                TreeMap<Date, File> sortedFiles = new TreeMap<Date, File>();

                for (int i = 0; i < listOfFiles.length; i++) {
                    if (listOfFiles[i].isFile()) {
                        filename = listOfFiles[i].getName();
                        if ((!filename.equals(archiveFileName)) && (!filename.equals(tmpArchiveFileName))
                                && (filename.startsWith(archiveFileName))) {
                            String beforeTimeString = archiveFileName + ".";
                            String timeSuffix = filename.substring(beforeTimeString.length());
                            if (!"".equals(timeSuffix)) {
                                Date fileCreatedate = null;
                                try {
                                    fileCreatedate = dateFormatter.parse(timeSuffix);
                                } catch (ParseException e) {
                                    LOG.debug("cant parse file name suffix to time for filename:" + filename, e);
                                }
                                if (fileCreatedate != null) {
                                    sortedFiles.put(fileCreatedate, listOfFiles[i]);
                                }
                            }
                        }
                    }
                }

                while (sortedFiles.size() > archiveFileMaxNumber) {
                    File removeFile = sortedFiles.remove(sortedFiles.firstKey());
                    LOG.debug("deleting archive file:'" + removeFile.getName()
                            + "' so that number of archive files <=" + archiveFileMaxNumber);
                    removeFile.delete();
                }
                for (File archivedFile : sortedFiles.values()) {
                    LOG.debug("not deleting archive file:'" + archivedFile.getName()
                            + "' so that number of archive files <=" + archiveFileMaxNumber);
                }

                return true;
            } catch (IOException e) {
                LOG.error("Problem removing old persistance files", e);
            }
        } else {
            // if resource doesn't exist just rename the new tmp file to the archive file name
            try {
                currentArchiveFile = new File(resource.getURL().getFile());
                // rename temporary archive file to current archive file name
                if (!tmpCurrentArchiveFile.renameTo(currentArchiveFile)) {
                    throw new IOException("cannot rename temporary current archive file:"
                            + tmpCurrentArchiveFile.getAbsolutePath() + " to "
                            + currentArchiveFile.getAbsolutePath());
                }
                return true;
            } catch (IOException e) {
                LOG.error("cannot rename temporary current archive ", e);
            }
        }

        return false;

    }

    /**
     * Causes the historical dataPointMap to load from a file determined by archiveFileLocation
     * @param archiveFile file definition to persist the data set to
     * @return true if dataPointMap loaded correctly, false if not
     */
    @PostConstruct
    public boolean load() {

        repositoryLoaded = false;

        if (!persistHistoricData) {
            LOG.info("not loading persisted data as persistHistoricData=false");
            return false;
        }

        if (archiveFileName == null || archiveFileDirectoryLocation == null) {
            LOG.error("not using historical data from file as incorrect file location:"
                    + " archiveFileDirectoryLocation=" + archiveFileDirectoryLocation + " archiveFileName="
                    + archiveFileName);
            return false;
        }

        String archiveFileLocation = archiveFileDirectoryLocation + File.separator + archiveFileName;

        File archiveFile = null;

        try {
            Resource resource = resourceLoader.getResource(archiveFileLocation);
            if (!resource.exists()) {
                LOG.warn("cannot load historical data as file at archiveFileLocation='" + archiveFileLocation
                        + "' does not exist");
                return false;
            }

            archiveFile = new File(resource.getURL().getFile());
        } catch (IOException e) {
            LOG.error("cannot load historical data from file at archiveFileLocation='" + archiveFileLocation
                    + "' due to error:", e);
            return false;
        } catch (Exception e) {
            LOG.error("cannot load historical data from file at archiveFileLocation='" + archiveFileLocation
                    + "' due to error:", e);
            return false;
        }

        try {

            //TODO CHANGE TO PACKAGE
            //         JAXBContext jaxbContext = JAXBContext.newInstance(
            //               PmatrixDpdCalculatorImpl.class,
            //               PmatrixDpdCalculatorEmaImpl.class,
            //               PmatrixDpdCalculatorRepository.class,
            //               org.opennms.features.vaadin.pmatrix.model.NameValuePair.class);

            // see http://stackoverflow.com/questions/1043109/why-cant-jaxb-find-my-jaxb-index-when-running-inside-apache-felix
            // need to provide bundles class loader
            ClassLoader cl = org.opennms.features.vaadin.pmatrix.model.DataPointDefinition.class.getClassLoader();
            JAXBContext jaxbContext = JAXBContext.newInstance(
                    "org.opennms.features.vaadin.pmatrix.model:org.opennms.features.vaadin.pmatrix.calculator", cl);

            //JAXBContext jaxbContext = JAXBContext.newInstance("org.opennms.features.vaadin.pmatrix.model:org.opennms.features.vaadin.pmatrix.calculator");

            Unmarshaller jaxbUnMarshaller = jaxbContext.createUnmarshaller();

            Object unmarshalledObject = jaxbUnMarshaller.unmarshal(archiveFile);

            if (unmarshalledObject instanceof PmatrixDpdCalculatorRepository) {
                PmatrixDpdCalculatorRepository pdcr = (PmatrixDpdCalculatorRepository) unmarshalledObject;
                dataPointMap = pdcr.getDataPointMap();

                LOG.info("successfully unmarshalled historical pmatrix data from file location:"
                        + archiveFile.getAbsolutePath());
                repositoryLoaded = true;
                return true;
            } else {
                LOG.error("cant unmarshal received object:" + unmarshalledObject);
            }

        } catch (JAXBException e) {
            LOG.error("problem unmarshalling file: " + archiveFile.getAbsolutePath(), e);
        } catch (Exception e) {
            LOG.error("problem unmarshalling file: " + archiveFile.getAbsolutePath(), e);
        }
        return false;

    }
}