pt.lsts.neptus.mra.MRAFilesHandler.java Source code

Java tutorial

Introduction

Here is the source code for pt.lsts.neptus.mra.MRAFilesHandler.java

Source

/*
 * Copyright (c) 2004-2016 Universidade do Porto - Faculdade de Engenharia
 * Laboratrio de Sistemas e Tecnologia Subaqutica (LSTS)
 * All rights reserved.
 * Rua Dr. Roberto Frias s/n, sala I203, 4200-465 Porto, Portugal
 *
 * This file is part of Neptus, Command and Control Framework.
 *
 * Commercial Licence Usage
 * Licencees holding valid commercial Neptus licences may use this file
 * in accordance with the commercial licence agreement provided with the
 * Software or, alternatively, in accordance with the terms contained in a
 * written agreement between you and Universidade do Porto. For licensing
 * terms, conditions, and further information contact lsts@fe.up.pt.
 *
 * European Union Public Licence - EUPL v.1.1 Usage
 * Alternatively, this file may be used under the terms of the EUPL,
 * Version 1.1 only (the "Licence"), appearing in the file LICENSE.md
 * included in the packaging of this file. You may not use this work
 * except in compliance with the Licence. Unless required by applicable
 * law or agreed to in writing, software distributed under the Licence is
 * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF
 * ANY KIND, either express or implied. See the Licence for the specific
 * language governing permissions and limitations at
 * http://ec.europa.eu/idabc/eupl.html.
 *
 * For more information please see <http://lsts.fe.up.pt/neptus>.
 *
 * Author: hfq
 * Jan 21, 2014
 */
package pt.lsts.neptus.mra;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;

import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;

import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.io.FileUtils;

import pt.lsts.imc.lsf.LsfIndexListener;
import pt.lsts.neptus.NeptusLog;
import pt.lsts.neptus.i18n.I18n;
import pt.lsts.neptus.loader.FileHandler;
import pt.lsts.neptus.mra.importers.IMraLogGroup;
import pt.lsts.neptus.platform.OsInfo;
import pt.lsts.neptus.util.FileUtil;
import pt.lsts.neptus.util.GuiUtils;
import pt.lsts.neptus.util.MathMiscUtils;
import pt.lsts.neptus.util.RecentlyOpenedFilesUtil;
import pt.lsts.neptus.util.StreamUtil;
import pt.lsts.neptus.util.conf.ConfigFetch;
import pt.lsts.neptus.util.llf.LsfLogSource;
import pt.lsts.neptus.util.llf.LsfReport;
import pt.lsts.neptus.util.llf.LsfReportProperties;

/**
 * MRA Files Handler
 * - Extractors
 * - Open/Close log files
 * 
 * @author ZP
 * @author pdias (LSF)
 * @author jqcorreia
 * @author hfq
 */
public class MRAFilesHandler implements FileHandler {
    private static final String RECENTLY_OPENED_LOGS = "conf/mra_recent.xml";

    private LinkedHashMap<JMenuItem, File> miscFilesOpened = new LinkedHashMap<JMenuItem, File>();

    private NeptusMRA mra;

    private File tmpFile = null;
    private InputStream activeInputStream = null;

    /**
     * Constructor
     * 
     * @param mra
     */
    public MRAFilesHandler(NeptusMRA mra) {
        this.mra = mra;
    }

    /**
     * Does the necessary pre-processing of a log file based on it's extension
     * Currently supports gzip, bzip2 and no-compression formats.
     * @param fx
     * @return True on success, False on failure
     */
    public boolean openLog(File fx) {
        mra.getBgp().block(true);
        File fileToOpen = null;

        String errorMessage = "";

        if (fx.getName().toLowerCase().endsWith(FileUtil.FILE_TYPE_LSF_COMPRESSED)) {
            fileToOpen = extractGzip(fx);
        } else if (fx.getName().toLowerCase().endsWith(FileUtil.FILE_TYPE_LSF_COMPRESSED_BZIP2)) {
            fileToOpen = extractBzip2(fx);
        } else if (fx.getName().toLowerCase().endsWith(FileUtil.FILE_TYPE_LSF)) {
            fileToOpen = fx;
        }

        mra.getBgp().block(false);
        if (fileToOpen == null) {
            errorMessage = mra.getBgp().getText();
            GuiUtils.errorMessage(mra, I18n.text("Invalid LSF file"),
                    I18n.text("LSF file does not exist!") + "\n" + errorMessage);
            return false;
        }

        return openLSF(fileToOpen);
    }

    /**
     * Abort al actions pending while opening a log file.
     */
    protected void abortPendingOpenLogActions() {
        if (activeInputStream != null) {
            try {
                activeInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            activeInputStream = null;
        }
        if (tmpFile != null) {
            if (tmpFile.exists()) {
                try {
                    tmpFile.delete();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Cleans up mraPanel and calls methos from MRAPanel to clean up visualizations and log source.
     */
    private void closeLogSource() {
        if (mra.getMraPanel() != null) {
            mra.getMraPanel().cleanup();
            mra.setMraPanel(null);
            mra.getContentPane().removeAll();
            NeptusLog.pub().info("Log source was closed.");
        }
    }

    /**
     * Open IMraLogGroup source
     * Enables SetMission and GenReport menu items.
     * @param source
     */
    private void openLogSource(IMraLogGroup source) {
        abortPendingOpenLogActions();
        closeLogSource();
        mra.getContentPane().removeAll();
        mra.setMraPanel(new MRAPanel(source, mra));
        mra.getContentPane().add(mra.getMraPanel());
        mra.invalidate();
        mra.validate();
        mra.getMRAMenuBar().getSetMissionMenuItem().setEnabled(true);
        mra.getMRAMenuBar().getGenReportMenuItem().setEnabled(true);
        mra.getMRAMenuBar().getGenReportCustomOptionsMenuItem().setEnabled(true);
    }

    /**
     * Open LSF Log file
     * @param f
     * @return
     */
    private boolean openLSF(File f) {
        mra.getBgp().block(true);
        mra.getBgp().setText(I18n.text("Loading LSF Data"));

        if (!f.exists()) {
            mra.getBgp().block(false);
            GuiUtils.errorMessage(mra, I18n.text("Invalid LSF file"), I18n.text("LSF file does not exist!"));
            return false;
        }

        final File lsfDir = f.getParentFile();

        //IMCDefinition.pathToDefaults = ConfigFetch.getDefaultIMCDefinitionsLocation();

        boolean alreadyConverted = false;
        if (lsfDir.isDirectory()) {
            if (new File(lsfDir, "mra/lsf.index").canRead())
                alreadyConverted = true;

        } else if (new File(lsfDir, "mra/lsf.index").canRead())
            alreadyConverted = true;

        if (alreadyConverted) {
            int option = GuiUtils.confirmDialogWithCancel(mra, I18n.text("Open Log"),
                    I18n.text("This log seems to have already been indexed. Index again?"));

            if (option == JOptionPane.YES_OPTION) {
                try {
                    FileUtils.deleteDirectory(new File(lsfDir, "mra"));
                } catch (Exception e) {
                    NeptusLog.pub().error("Error while trying to delete mra/ folder", e);
                }
            }

            if (option == JOptionPane.CANCEL_OPTION || option == JOptionPane.CLOSED_OPTION) {
                mra.getBgp().block(false);
                return false;
            }
        }

        mra.getBgp().setText(I18n.text("Loading LSF Data"));

        try {
            LsfLogSource source = new LsfLogSource(f, new LsfIndexListener() {

                @Override
                public void updateStatus(String messageToDisplay) {
                    mra.getBgp().setText(messageToDisplay);
                }
            });

            updateMissionFilesOpened(f);

            mra.getBgp().setText(I18n.text("Starting interface"));
            openLogSource(source);
            mra.getBgp().setText(I18n.text("Done"));

            mra.getBgp().block(false);
            return true;
        } catch (Exception e) {
            mra.getBgp().block(false);
            e.printStackTrace();
            GuiUtils.errorMessage(mra, I18n.text("Invalid LSF index"), I18n.text(e.getMessage()));
            return false;
        }
    }

    // --- Extractors ---
    /**
     * Extract GNU zip files
     * @param f input file
     * @return decompressed file
     */
    private File extractGzip(File f) {
        GzipCompressorInputStream gzDataLog = null;
        try {
            mra.getBgp().setText(I18n.text("Decompressing LSF Data..."));
            gzDataLog = new GzipCompressorInputStream(new FileInputStream(f), true);
            activeInputStream = gzDataLog;
            File outputFile = new File(f.getParent(), "Data.lsf");
            if (!outputFile.exists()) {
                outputFile.createNewFile();
            }

            FilterCopyDataMonitor fis = createCopyMonitor(gzDataLog);
            StreamUtil.copyStreamToFile(fis, outputFile);

            File res = new File(f.getParent(), "Data.lsf");

            return res;
        } catch (Exception ioe) {
            System.err.println("Exception has been thrown: " + ioe);
            mra.getBgp().setText(I18n.text("Decompressing LSF Data...") + "   " + ioe.getMessage());
            ioe.printStackTrace();
            return null;
        } finally {
            if (gzDataLog != null) {
                try {
                    gzDataLog.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Extract BZip files with BZip2 compressor.
     * @param f
     * @return decompressed file
     */
    private File extractBzip2(File f) {
        mra.getBgp().setText(I18n.text("Decompressing BZip2 LSF Data..."));
        BZip2CompressorInputStream bz2DataLog = null;
        try {
            FileInputStream fxInStream = new FileInputStream(f);
            bz2DataLog = new BZip2CompressorInputStream(fxInStream, true);
            activeInputStream = bz2DataLog;
            File outFile = new File(f.getParent(), "Data.lsf");
            if (!outFile.exists()) {
                outFile.createNewFile();
            }

            FilterCopyDataMonitor fis = createCopyMonitor(bz2DataLog);
            StreamUtil.copyStreamToFile(fis, outFile);

            return outFile;
        } catch (Exception e) {
            System.err.println("Exception has been thrown: " + e);
            mra.getBgp().setText(I18n.text("Decompressing LSF Data...") + "   " + e.getMessage());
            e.printStackTrace();
            return null;
        } finally {
            if (bz2DataLog != null) {
                try {
                    bz2DataLog.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * @param stream
     * @return
     */
    private FilterCopyDataMonitor createCopyMonitor(InputStream stream) {
        FilterCopyDataMonitor fis = new FilterCopyDataMonitor(stream) {
            long targetStep = 1 * 1024 * 1024;
            long target = targetStep;
            protected String decompressed = I18n.text("Decompressed") + " ";

            @Override
            public void updateValueInMessagePanel() {
                if (downloadedSize > target) {
                    mra.getBgp().setText(
                            decompressed + MathMiscUtils.parseToEngineeringRadix2Notation(downloadedSize, 2) + "B");
                    target += targetStep;
                }
            }
        };
        return fis;
    }

    /**
     * Decompresses bytes read from a input stream of data 
     * Monitors input data stream size
     * 
     * @author pdias
     */
    private abstract class FilterCopyDataMonitor extends FilterInputStream {

        public long downloadedSize = 0;

        /**
         * @param in
         */
        public FilterCopyDataMonitor(InputStream in) {
            super(in);
            downloadedSize = 0;
        }

        @Override
        public int read() throws IOException {
            int tmp = super.read();
            downloadedSize += (tmp == -1) ? 0 : 1;
            if (tmp != -1)
                updateValueInMessagePanel();
            return tmp;
        }

        @Override
        public int read(byte[] b, int off, int len) throws IOException {
            int tmp = super.read(b, off, len);
            downloadedSize += (tmp == -1) ? 0 : tmp;
            if (tmp != -1)
                updateValueInMessagePanel();
            return tmp;
        }

        public abstract void updateValueInMessagePanel();
    }

    // --- Generate PDF Reports --- 
    /**
     * Generates PDF report from log file.
     */
    public void generatePDFReport(final File f) {

        SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
            @Override
            protected Boolean doInBackground() throws Exception {
                //                GuiUtils.infoMessage(mra, I18n.text("Generating PDF Report..."), I18n.text("Generating PDF Report..."));
                mra.getMRAMenuBar().getReportMenuItem().setEnabled(false);
                LsfReportProperties.generatingReport = true;
                mra.getMraPanel().addStatusBarMsg("Generating Report...");
                return LsfReport.generateReport(mra.getMraPanel().getSource(), f, mra.getMraPanel());
            }

            @Override
            protected void done() {
                super.done();
                try {
                    get();
                } catch (Exception e) {
                    NeptusLog.pub().error(e);
                }
                try {
                    if (get()) {
                        GuiUtils.infoMessage(mra, I18n.text("Generate PDF Report"),
                                I18n.text("File saved to") + " " + f.getAbsolutePath());
                        final String pdfF = f.getAbsolutePath();
                        int resp = GuiUtils.confirmDialog(mra, I18n.text("Open PDF Report"),
                                I18n.text("Do you want to open PDF Report file?"));
                        if (resp == JOptionPane.YES_OPTION) {
                            new Thread() {
                                @Override
                                public void run() {
                                    openPDFInExternalViewer(pdfF);
                                };
                            }.start();
                        }
                    }
                } catch (Exception e) {
                    GuiUtils.errorMessage(mra, I18n.text("PDF Creation Process"),
                            "<html>" + I18n.text("PDF <b>was not</b> saved to file.") + "<br>" + I18n.text("Error")
                                    + ": " + e.getMessage() + "</html>");
                    e.printStackTrace();
                } finally {
                    mra.getBgp().block(false);
                    mra.getMRAMenuBar().getReportMenuItem().setEnabled(true);
                    LsfReportProperties.generatingReport = false;
                    mra.getMraPanel().reDrawStatusBar();
                }
            }
        };
        worker.execute();
    }

    /**
     * Opens generated pdf report on default OS viewer.
     * 
     * @param pdf
     */
    private void openPDFInExternalViewer(String pdf) {
        try {
            if (OsInfo.getName() == OsInfo.Name.WINDOWS) {
                Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + pdf);
            } else {
                String[] readers = { "xpdf", "kpdf", "FoxitReader", "evince", "acroread" };
                String reader = null;

                for (int count = 0; count < readers.length && reader == null; count++) {
                    if (Runtime.getRuntime().exec(new String[] { "which", readers[count] }).waitFor() == 0)
                        reader = readers[count];
                }
                if (reader == null)
                    throw new Exception(I18n.text("Could not find PDF reader"));
                else
                    Runtime.getRuntime().exec(new String[] { reader, pdf });
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        // GuiUtils.infoMessage(mra,  I18n.text("PDF Report Generated"),
        //         I18n.text("Opening file") +" "+ pdf);
    }

    // --- Recently opened files ---

    /**
     * Load Recently opened files from conf/mra_recent.xml
     */
    public void loadRecentlyOpenedFiles() {
        String recentlyOpenedFiles = ConfigFetch.resolvePath(RECENTLY_OPENED_LOGS);

        if (recentlyOpenedFiles == null || !new File(recentlyOpenedFiles).exists())
            return;

        Method methodUpdate = null;

        try {
            Class<?>[] params = { File.class };
            methodUpdate = this.getClass().getMethod("updateMissionFilesOpened", params);
            if (methodUpdate == null) {
                NeptusLog.pub().info("Method update = null");
            }
        } catch (Exception e) {
            NeptusLog.pub().error(this + "loadRecentlyOpenedFiles", e);
            return;
        }

        //        if (recentlyOpenedFiles == null) {
        //            JOptionPane.showInternalMessageDialog(mra, "Cannot Load");
        //            return;
        //        }

        //        if (!new File(recentlyOpenedFiles).exists())
        //            return;

        RecentlyOpenedFilesUtil.loadRecentlyOpenedFiles(recentlyOpenedFiles, methodUpdate, this);
    }

    /**
     * Updates misstion files opened
     * @param fx
     * @return
     */
    public boolean updateMissionFilesOpened(File fx) {
        RecentlyOpenedFilesUtil.updateFilesOpenedMenuItems(fx, getMiscFilesOpened(), new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                final File fx;
                Object key = e.getSource();
                File value = getMiscFilesOpened().get(key);
                if (value instanceof File) {
                    fx = (File) value;
                    Thread t = new Thread("Open Log") {
                        @Override
                        public void run() {
                            mra.getMraFilesHandler().openLog(fx);
                        };
                    };
                    t.start();
                } else
                    return;
            }
        });

        mra.getMRAMenuBar().getRecentlyOpenFilesMenu();
        storeRecentlyOpenedFiles();
        return true;
    }

    /**
     * Updates /conf/mra_recent.xml
     */
    private void storeRecentlyOpenedFiles() {
        String recentlyOpenedFiles;
        LinkedHashMap<JMenuItem, File> hMap;
        String header;

        recentlyOpenedFiles = ConfigFetch.resolvePathBasedOnConfigFile(RECENTLY_OPENED_LOGS);
        hMap = getMiscFilesOpened();
        header = I18n.text("Recently opened mission files") + ".";

        RecentlyOpenedFilesUtil.storeRecentlyOpenedFiles(recentlyOpenedFiles, hMap, header);
    }

    /**
     * @return the miscFilesOpened
     */
    public LinkedHashMap<JMenuItem, File> getMiscFilesOpened() {
        return miscFilesOpened;
    }

    /**
     * @param miscFilesOpened the miscFilesOpened to set
     */
    public void setMiscFilesOpened(LinkedHashMap<JMenuItem, File> miscFilesOpened) {
        this.miscFilesOpened = miscFilesOpened;
    }

    /* (non-Javadoc)
     * @see pt.lsts.neptus.loader.FileHandler#handleFile(java.io.File)
     */
    @Override
    public void handleFile(File f) {
        openLog(f);
    }

    /* (non-Javadoc)
     * @see pt.lsts.neptus.loader.FileHandler#getName()
     */
    @Override
    public String getName() {
        return null;
    }
}