org.opennms.features.vaadin.mibcompiler.MibCompilerPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.opennms.features.vaadin.mibcompiler.MibCompilerPanel.java

Source

/*******************************************************************************
 * This file is part of OpenNMS(R).
 *
 * Copyright (C) 2012-2014 The OpenNMS Group, Inc.
 * OpenNMS(R) is Copyright (C) 1999-2014 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 Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero 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.mibcompiler;

import java.io.File;
import java.util.List;

import org.opennms.core.utils.ConfigFileConstants;
import org.opennms.features.mibcompiler.api.MibParser;
import org.opennms.features.vaadin.api.Logger;
import org.opennms.features.vaadin.datacollection.DataCollectionWindow;
import org.opennms.features.vaadin.events.EventWindow;
import org.opennms.netmgt.config.api.DataCollectionConfigDao;
import org.opennms.netmgt.config.api.EventConfDao;
import org.opennms.netmgt.config.datacollection.DatacollectionGroup;
import org.opennms.netmgt.events.api.EventProxy;
import org.opennms.netmgt.xml.eventconf.Events;

import com.vaadin.event.Action;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Label;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Panel;
import com.vaadin.ui.Tree;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;

import org.slf4j.LoggerFactory;
import org.vaadin.dialogs.ConfirmDialog;

/**
 * The Class MIB Compiler Panel.
 * 
 * @author <a href="mailto:agalue@opennms.org">Alejandro Galue</a> 
 */
@SuppressWarnings("serial")
public class MibCompilerPanel extends Panel {

    /** The Constant LOG. */
    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(MibCompilerPanel.class);

    /** The Constant PENDING. */
    private static final String PENDING = "pending";

    /** The Constant COMPILED. */
    private static final String COMPILED = "compiled";

    /** The Constant MIB_FILE_EXTENTION. */
    private static final String MIB_FILE_EXTENTION = ".mib";

    /** The Constant MIBS_ROOT_DIR. */
    // TODO Make the MIBs directory configurable
    private static final File MIBS_ROOT_DIR = new File(ConfigFileConstants.getHome(),
            "share" + File.separatorChar + "mibs");

    /** The Constant MIBS_COMPILED_DIR. */
    private static final File MIBS_COMPILED_DIR = new File(MIBS_ROOT_DIR, COMPILED);

    /** The Constant MIBS_PENDING_DIR. */
    private static final File MIBS_PENDING_DIR = new File(MIBS_ROOT_DIR, PENDING);

    /** The Constant ACTION_EDIT. */
    private static final Action ACTION_EDIT = new Action("Edit MIB");

    /** The Constant ACTION_DELETE. */
    private static final Action ACTION_DELETE = new Action("Delete MIB");

    /** The Constant ACTION_VIEW. */
    private static final Action ACTION_VIEW = new Action("View MIB");

    /** The Constant ACTION_COMPILE. */
    private static final Action ACTION_COMPILE = new Action("Compile MIB");

    /** The Constant ACTION_EVENTS. */
    private static final Action ACTION_EVENTS = new Action("Generate Events");

    /** The Constant ACTION_COLLECT. */
    private static final Action ACTION_COLLECT = new Action("Generate Data Collection");

    /** The MIBs tree. */
    private final Tree mibsTree;

    /** The MIB parser. */
    private final MibParser mibParser;

    /** The Events Configuration DAO. */
    private EventConfDao eventsDao;

    /** The Events Proxy. */
    private EventProxy eventsProxy;

    /** The Data Collection Configuration DAO. */
    private DataCollectionConfigDao dataCollectionDao;

    /**
     * Instantiates a new MIB tree panel.
     *
     * @param dataCollectionDao the OpenNMS Data Collection Configuration DAO 
     * @param eventsDao the OpenNMS Events Configuration DAO
     * @param eventsProxy the OpenNMS Events Proxy
     * @param mibParser the MIB parser
     * @param logger the logger
     */
    public MibCompilerPanel(final DataCollectionConfigDao dataCollectionDao, final EventConfDao eventsDao,
            final EventProxy eventsProxy, final MibParser mibParser, final Logger logger) {
        super("MIB Compiler");

        if (dataCollectionDao == null)
            throw new RuntimeException("dataCollectionDao cannot be null.");
        if (eventsProxy == null)
            throw new RuntimeException("eventProxy cannot be null.");
        if (eventsDao == null)
            throw new RuntimeException("eventsDao cannot be null.");

        this.eventsDao = eventsDao;
        this.eventsProxy = eventsProxy;
        this.dataCollectionDao = dataCollectionDao;

        logger.info("Reading MIBs from " + MIBS_ROOT_DIR);

        // Make sure MIB directories exist

        if (!MIBS_COMPILED_DIR.exists()) {
            if (!MIBS_COMPILED_DIR.mkdirs()) {
                throw new RuntimeException(
                        "Unable to create directory for compiled MIBs (" + MIBS_COMPILED_DIR + ")");
            }
        }
        if (!MIBS_PENDING_DIR.exists()) {
            if (!MIBS_PENDING_DIR.mkdirs()) {
                throw new RuntimeException(
                        "Unable to create directory for pending MIBs (" + MIBS_PENDING_DIR + ")");
            }
        }

        // Parser Configuration

        this.mibParser = mibParser;
        mibParser.setMibDirectory(MIBS_COMPILED_DIR);

        // Initialize Toolbar

        MibUploadButton upload = new MibUploadButton(MIBS_PENDING_DIR, MIBS_COMPILED_DIR, logger) {
            @Override
            public void uploadHandler(String filename) {
                addTreeItem(filename, PENDING);
            }
        };

        VerticalLayout layout = new VerticalLayout();
        layout.addComponent(upload);

        // Initialize MIB Tree

        mibsTree = new Tree("MIB Tree");
        initMibTree(logger);
        final Label label = new Label(
                "<p>Use the right-click context menu over the MIB tree files, to display the compiler operations.</p>");
        label.setContentMode(ContentMode.HTML);

        layout.addComponent(label);
        layout.addComponent(mibsTree);

        // Panel Setup
        setSizeFull();
        addStyleName("light");
        layout.setComponentAlignment(upload, Alignment.TOP_RIGHT);
        layout.setExpandRatio(mibsTree, 1);

        setContent(layout);
    }

    /**
     * Initialize the MIB tree.
     *
     * @param logger the logger
     */
    private void initMibTree(final Logger logger) {
        File[] folders = new File[] { MIBS_COMPILED_DIR, MIBS_PENDING_DIR };
        for (File folder : folders) {
            addTreeItem(folder.getName(), null);
        }
        for (File folder : folders) {
            String[] files = folder.list();
            if (files == null)
                continue;
            for (String file : files) {
                addTreeItem(file, folder.getName());
            }
        }

        mibsTree.expandItemsRecursively(COMPILED);
        mibsTree.expandItemsRecursively(PENDING);

        mibsTree.addActionHandler(new Action.Handler() {

            @Override
            public Action[] getActions(Object target, Object sender) {
                if (target == null) {
                    return new Action[] {};
                }
                Object parent = mibsTree.getParent(target);
                if (parent == null) {
                    return new Action[] {};
                }
                if (parent.equals(COMPILED)) {
                    return new Action[] { ACTION_EVENTS, ACTION_COLLECT, ACTION_VIEW, ACTION_DELETE };
                } else {
                    return new Action[] { ACTION_EDIT, ACTION_DELETE, ACTION_COMPILE };
                }
            }

            @Override
            public void handleAction(Action action, Object sender, Object target) {
                final String fileName = (String) target;
                if (action == ACTION_DELETE) {
                    ConfirmDialog.show(getUI(), "Are you sure?",
                            "Do you really want to delete " + fileName + "?\nThis cannot be undone.", "Yes", "No",
                            new ConfirmDialog.Listener() {
                                public void onClose(ConfirmDialog dialog) {
                                    if (dialog.isConfirmed()) {
                                        String source = mibsTree.getParent(fileName).toString();
                                        File file = new File(
                                                PENDING.equals(source) ? MIBS_PENDING_DIR : MIBS_COMPILED_DIR,
                                                fileName);
                                        if (file.delete()) {
                                            mibsTree.removeItem(fileName);
                                            logger.info("MIB " + file + " has been successfully removed.");
                                        } else {
                                            Notification.show("Can't delete " + file);
                                        }
                                    }
                                }
                            });
                }
                if (action == ACTION_EDIT) {
                    Window w = new FileEditorWindow(new File(MIBS_PENDING_DIR, fileName), logger, false);
                    getUI().addWindow(w);
                }
                if (action == ACTION_VIEW) {
                    Window w = new FileEditorWindow(new File(MIBS_COMPILED_DIR, fileName), logger, true);
                    getUI().addWindow(w);
                }
                if (action == ACTION_COMPILE) {
                    if (parseMib(logger, new File(MIBS_PENDING_DIR, fileName))) {
                        // Renaming the file to be sure that the target name is correct and always has a file extension.
                        final String mibFileName = mibParser.getMibName() + MIB_FILE_EXTENTION;
                        final File currentFile = new File(MIBS_PENDING_DIR, fileName);
                        final File suggestedFile = new File(MIBS_COMPILED_DIR, mibFileName);
                        if (suggestedFile.exists()) {
                            ConfirmDialog.show(getUI(), "Are you sure?", "The MIB " + mibFileName
                                    + " already exist on the compiled directory?<br/>Override the existing file could break other compiled mibs, so proceed with caution.<br/>This cannot be undone.",
                                    "Yes", "No", new ConfirmDialog.Listener() {
                                        public void onClose(ConfirmDialog dialog) {
                                            if (dialog.isConfirmed()) {
                                                renameFile(logger, currentFile, suggestedFile);
                                            }
                                        }
                                    });
                        } else {
                            renameFile(logger, currentFile, suggestedFile);
                        }
                    }
                }
                if (action == ACTION_EVENTS) {
                    generateEvents(logger, fileName);
                }
                if (action == ACTION_COLLECT) {
                    generateDataCollection(logger, fileName);
                }
            }
        });
    }

    /**
     * Rename file.
     *
     * @param logger the logger
     * @param currentFile the current file
     * @param suggestedFile the suggested file
     */
    private void renameFile(Logger logger, File currentFile, File suggestedFile) {
        logger.info("Renaming file " + currentFile.getName() + " to " + suggestedFile.getName());
        mibsTree.removeItem(currentFile.getName());
        addTreeItem(suggestedFile.getName(), COMPILED);
        if (!currentFile.renameTo(suggestedFile)) {
            LOG.warn("Could not rename file: {}", currentFile.getPath());
        }
    }

    /**
     * Adds the tree item.
     *
     * @param label the label
     * @param parent the parent
     */
    // FIXME: It sounds reasonable to sort the tree after adding a new MIB ?
    private void addTreeItem(final String label, final String parent) {
        mibsTree.addItem(label);
        if (parent == null) {
            LOG.debug("Adding root directory {}", label);
            mibsTree.setChildrenAllowed(parent, true);
        } else {
            LOG.debug("Adding item {} to {} folder", label, parent);
            mibsTree.setParent(label, parent);
            mibsTree.setChildrenAllowed(label, false);
        }
    }

    /**
     * Parses the MIB.
     *
     * @param logger the logger
     * @param mibFile the MIB file
     * @return true, if successful
     */
    private boolean parseMib(final Logger logger, final File mibFile) {
        logger.info("Parsing MIB file " + mibFile);
        if (mibParser.parseMib(mibFile)) {
            logger.info("MIB parsed successfuly.");
            return true;
        } else {
            List<String> dependencies = mibParser.getMissingDependencies();
            if (dependencies.isEmpty()) {
                // FIXME Is this the best way to add a custom CSS ?
                String preStyle = "white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;";
                logger.error("Problem found when compiling the MIB: <pre style=\"" + preStyle + "\">"
                        + mibParser.getFormattedErrors() + "</pre>");
            } else {
                logger.error("Dependencies required: <b>" + dependencies + "</b>");
            }
        }
        return false;
    }

    /**
     * Generate events.
     *
     * @param logger the logger
     * @param fileName the file name
     */
    private void generateEvents(final Logger logger, final String fileName) {
        if (parseMib(logger, new File(MIBS_COMPILED_DIR, fileName))) {
            final EventUeiWindow w = new EventUeiWindow("uei.opennms.org/traps/" + mibParser.getMibName()) {
                @Override
                public void changeUeiHandler(String ueiBase) {
                    showEventsWindow(logger, fileName, ueiBase);
                }
            };
            getUI().addWindow(w);
        }
    }

    /**
     * Shows the events window.
     *
     * @param logger the logger
     * @param fileName the file name
     * @param ueiBase the UEI base
     */
    private void showEventsWindow(final Logger logger, final String fileName, final String ueiBase) {
        final Events events = mibParser.getEvents(ueiBase);
        if (events == null) {
            Notification.show("The MIB couldn't be processed for events because: " + mibParser.getFormattedErrors(),
                    Notification.Type.ERROR_MESSAGE);
        } else {
            if (events.getEventCount() > 0) {
                try {
                    logger.info("Found " + events.getEventCount() + " events.");
                    final String eventsFileName = fileName.replaceFirst("\\..*$", ".events.xml");
                    final File configDir = new File(ConfigFileConstants.getHome(),
                            "etc" + File.separatorChar + "events");
                    final File eventFile = new File(configDir, eventsFileName);
                    final EventWindow w = new EventWindow(eventsDao, eventsProxy, eventFile, events, logger);
                    getUI().addWindow(w);
                } catch (Throwable t) {
                    Notification.show(t.getMessage(), Notification.Type.ERROR_MESSAGE);
                }
            } else {
                Notification.show("The MIB doesn't contain any notification/trap",
                        Notification.Type.WARNING_MESSAGE);
            }
        }
    }

    /**
     * Generate data collection.
     *
     * @param logger the logger
     * @param fileName the file name
     */
    private void generateDataCollection(final Logger logger, final String fileName) {
        if (parseMib(logger, new File(MIBS_COMPILED_DIR, fileName))) {
            final DatacollectionGroup dcGroup = mibParser.getDataCollection();
            if (dcGroup == null) {
                Notification.show("The MIB couldn't be processed for data collection because: "
                        + mibParser.getFormattedErrors(), Notification.Type.ERROR_MESSAGE);
            } else {
                if (dcGroup.getGroups().size() > 0) {
                    try {
                        final String dataFileName = fileName.replaceFirst("\\..*$", ".xml");
                        final DataCollectionWindow w = new DataCollectionWindow(mibParser, dataCollectionDao,
                                dataFileName, dcGroup, logger);
                        getUI().addWindow(w);
                    } catch (Throwable t) {
                        Notification.show(t.getMessage(), Notification.Type.ERROR_MESSAGE);
                    }
                } else {
                    Notification.show("The MIB doesn't contain any metric for data collection.",
                            Notification.Type.WARNING_MESSAGE);
                }
            }
        }
    }

}