org.opennms.features.vaadin.jmxconfiggenerator.ui.ResultView.java Source code

Java tutorial

Introduction

Here is the source code for org.opennms.features.vaadin.jmxconfiggenerator.ui.ResultView.java

Source

/*******************************************************************************
 * This file is part of OpenNMS(R).
 *
 * Copyright (C) 2013-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.jmxconfiggenerator.ui;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.opennms.netmgt.vaadin.core.UIHelper;
import org.opennms.features.vaadin.jmxconfiggenerator.Config;
import org.opennms.features.vaadin.jmxconfiggenerator.JmxConfigGeneratorUI;
import org.opennms.features.vaadin.jmxconfiggenerator.data.UiModel;
import org.opennms.features.vaadin.jmxconfiggenerator.data.UiModel.OutputDataKey;

import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.server.DownloadStream;
import com.vaadin.server.FileDownloader;
import com.vaadin.server.Resource;
import com.vaadin.server.StreamResource;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.Label;
import com.vaadin.ui.Notification;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.Reindeer;

/**
 * Represents the result view. It shows all generated configurations (including
 * some description texts) to the user.
 * 
 * @author Markus von Rden <mvr@opennms.com>
 */
public class ResultView extends VerticalLayout implements Button.ClickListener, View {

    /**
     * The name of the downlaodable zip archive.
     */
    private static String DOWNLOAD_FILE_NAME = "jmx-config-files.zip";

    /**
     * The TabSheet for the config and description content.
     */
    private TabSheet tabSheet = new TabSheet();

    /**
     * Stores the content.
     */
    private Map<UiModel.OutputDataKey, TabContent> tabContentMap = new HashMap<>();

    /**
     * Panel for previous and download buttons.
     */
    private final ButtonPanel buttonPanel = new ButtonPanel(this);

    private final FileDownloader fileDownloader;

    public ResultView() {
        // available content
        tabContentMap.put(OutputDataKey.JmxDataCollectionConfig,
                new TabContent(OutputDataKey.JmxDataCollectionConfig));
        tabContentMap.put(OutputDataKey.SnmpGraphProperties, new TabContent(OutputDataKey.SnmpGraphProperties));
        tabContentMap.put(OutputDataKey.CollectdConfigSnippet, new TabContent(OutputDataKey.CollectdConfigSnippet));

        // we have to sort the keys, because map.keySet or map.values do not return a sorted
        // collection which results in non deterministic ui results.
        List<OutputDataKey> keyList = new ArrayList<>(tabContentMap.keySet());
        Collections.sort(keyList, new Comparator<OutputDataKey>() {
            @Override
            public int compare(OutputDataKey o1, OutputDataKey o2) {
                return o1.name().compareTo(o2.name());
            }
        });

        // add all tabs
        for (OutputDataKey eachKey : keyList) {
            TabContent eachContent = tabContentMap.get(eachKey);
            tabSheet.addTab(eachContent, eachContent.getCaption());
        }

        tabSheet.setSizeFull();
        tabSheet.setSelectedTab(0); // select first component!
        tabSheet.addStyleName(Reindeer.TABSHEET_BORDERLESS);

        buttonPanel.getNext().setCaption("download all");
        buttonPanel.getNext().setDescription("Download a zip file containing the JMX datacollection configuration");
        buttonPanel.getNext().setIcon(Config.Icons.BUTTON_SAVE);

        // this is a dummy resource as we are going to set the real
        // resource when entering the view.
        fileDownloader = new FileDownloader(new Resource() {
            @Override
            public String getMIMEType() {
                return "application/unknown";
            }
        });
        fileDownloader.extend(buttonPanel.getNext());

        setSizeFull();

        addComponent(tabSheet);
        addComponent(buttonPanel);
        setExpandRatio(tabSheet, 1);
    }

    @Override
    public void buttonClick(ClickEvent event) {
        if (event.getSource().equals(buttonPanel.getPrevious())) {
            UIHelper.getCurrent(JmxConfigGeneratorUI.class).updateView(UiState.MbeansView);
        }
    }

    /**
     * Creates a map with the content for the zip file to create.
     */
    private Map<String, String> createZipContentMap() {
        // key: filename, value: file content
        Map<String, String> zipContentMap = new HashMap<>();
        // create map for the downloadable zip file
        for (OutputDataKey eachKey : tabContentMap.keySet()) {
            // config file
            zipContentMap.put(eachKey.getDownloadFilename(), tabContentMap.get(eachKey).getConfigContent());
        }
        return zipContentMap;
    }

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent event) {
        UiModel newValue = UIHelper.getCurrent(JmxConfigGeneratorUI.class).getUiModel();
        if (newValue == null)
            return;
        for (Entry<UiModel.OutputDataKey, String> eachEntry : newValue.getOutputMap().entrySet()) {
            if (tabContentMap.get(eachEntry.getKey()) != null) {
                tabContentMap.get(eachEntry.getKey()).setConfigContent(eachEntry.getValue());
            }
        }
        fileDownloader.setFileDownloadResource(new DownloadResource(createZipContentMap(), DOWNLOAD_FILE_NAME));
    }

    /**
     * Represents a downloadable Resource. If opened in the Application Window a
     * download via the browser is initiated. Usually a "save or open"-dialogue
     * shows up.
     * 
     * @author Markus von Rden <mvr@opennms.com>
     * 
     */
    private static class DownloadResource extends StreamResource {

        /**
         * 
         * @param zipContentMap
         *            key: Filename, value: File content
         * @param filename
         *            The filename for the downloadable zip file.
         */
        public DownloadResource(final Map<String, String> zipContentMap, final String filename) {
            super(new StreamSource() {
                @Override
                public InputStream getStream() {
                    return new ByteArrayInputStream(getZipByteArray(zipContentMap));
                }
            }, filename);
            // for "older" browsers to force a download,
            // otherwise it may not be downloaded
            setMIMEType("application/unknown");
        }

        /**
         * Set DownloadStream-Parameter "Content-Disposition" to atachment,
         * therefore the Stream is downloaded and is not parsed as for example
         * "normal" xml.
         */
        @Override
        public DownloadStream getStream() {
            DownloadStream ds = super.getStream();
            ds.setParameter("Content-Disposition", "attachment; filename=\"" + getFilename() + "\"");
            return ds;
        }

        /**
         * Creates a byte-Array which represents the content from the
         * zipContentMap in zipped form. The files are defined by the given Map.
         * The key of the map defines the name in the zip archive. The value of
         * the map defines file's content.
         * 
         * @param zipContentMap
         *            The map which contains the filenames and file contents for
         *            the zip archive to create.
         * @return a byte-Array which represents the zip file.
         */
        private static byte[] getZipByteArray(Map<String, String> zipContentMap) {
            try (
                    // create output streams ...
                    ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
                    ZipOutputStream out = new ZipOutputStream(arrayOutputStream)) {

                // Compress the files
                for (Entry<String, String> eachEntry : zipContentMap.entrySet()) {
                    out.putNextEntry(new ZipEntry(eachEntry.getKey()));
                    out.write(eachEntry.getValue().getBytes());
                    out.closeEntry();
                }
                out.close(); // Complete the ZIP file
                arrayOutputStream.close();
                return arrayOutputStream.toByteArray();
            } catch (IOException e) {
                UIHelper.showNotification("Download Error", e.getMessage(), Notification.Type.ERROR_MESSAGE);
                return new byte[0];
            }
        }
    }

    private static class TabContent extends HorizontalSplitPanel {

        /**
         * TextArea for the configuration content (e.g. the SNMP-Graph-Properties)
         */
        private final TextArea configTextArea = new TextArea();

        /**
         * Label for the description content (e.g. an explanation of the SNMP-Graph-Properties and what to do with that file).
         */
        private final Label descriptionLabel;

        private String configContent;

        private TabContent(OutputDataKey key) {
            configTextArea.setSizeFull();
            configTextArea.addStyleName("borderless");

            descriptionLabel = new Label(UIHelper.loadContentFromFile(getClass(), key.getDescriptionFilename()),
                    ContentMode.HTML);

            VerticalLayout leftLayout = new VerticalLayout(descriptionLabel);
            leftLayout.setMargin(true);

            addComponent(configTextArea);
            addComponent(leftLayout);

            setSizeFull();
            setLocked(false);
            setSplitPosition(75, Unit.PERCENTAGE);
            setCaption(key.getTitle());
        }

        /**
         * Sets the content of the {@linkplain #configTextArea}.
         * 
         * @param newConfigContent The new configuration content.
         */
        public void setConfigContent(String newConfigContent) {
            configContent = newConfigContent;
            if (newConfigContent.split("\n").length >= Config.CONFIG_SNIPPET_MAX_LINES) {
                configTextArea.setValue(
                        "The generated configuration snippet is too long to show here. Please download the files and edit/view with the editor of choice.");
            } else {
                configTextArea.setValue(newConfigContent);
            }
        }

        public String getConfigContent() {
            return configContent == null ? "" : configContent;
        }
    }
}