org.sensorhub.ui.AdminUI.java Source code

Java tutorial

Introduction

Here is the source code for org.sensorhub.ui.AdminUI.java

Source

/***************************** BEGIN LICENSE BLOCK ***************************
    
The contents of this file are subject to the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file, You can obtain one
at http://mozilla.org/MPL/2.0/.
    
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the License.
     
Copyright (C) 2012-2015 Sensia Software LLC. All Rights Reserved.
     
******************************* END LICENSE BLOCK ***************************/

package org.sensorhub.ui;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import org.sensorhub.api.comm.CommConfig;
import org.sensorhub.api.common.SensorHubException;
import org.sensorhub.api.module.IModule;
import org.sensorhub.api.module.ModuleConfig;
import org.sensorhub.api.persistence.StorageConfig;
import org.sensorhub.api.processing.ProcessConfig;
import org.sensorhub.api.sensor.SensorConfig;
import org.sensorhub.api.service.ClientConfig;
import org.sensorhub.api.service.ServiceConfig;
import org.sensorhub.impl.SensorHub;
import org.sensorhub.impl.module.ModuleRegistry;
import org.sensorhub.impl.persistence.StreamStorageConfig;
import org.sensorhub.impl.service.HttpServer;
import org.sensorhub.impl.service.HttpServerConfig;
import org.sensorhub.ui.ModuleTypeSelectionPopup.ModuleTypeSelectionCallback;
import org.sensorhub.ui.api.IModuleConfigForm;
import org.sensorhub.ui.api.IModuleAdminPanel;
import org.sensorhub.ui.api.UIConstants;
import org.sensorhub.ui.data.MyBeanItem;
import org.sensorhub.ui.data.MyBeanItemContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vaadin.annotations.Theme;
import com.vaadin.data.Item;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.data.util.converter.ConverterFactory;
import com.vaadin.data.util.converter.DefaultConverterFactory;
import com.vaadin.data.util.converter.StringToIntegerConverter;
import com.vaadin.event.Action;
import com.vaadin.event.Action.Handler;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.event.ItemClickEvent.ItemClickListener;
import com.vaadin.server.ClassResource;
import com.vaadin.server.Resource;
import com.vaadin.server.ThemeResource;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinSession;
import com.vaadin.ui.Accordion;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.Image;
import com.vaadin.ui.Label;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.TabSheet.Tab;
import com.vaadin.ui.Table;
import com.vaadin.ui.Table.CellStyleGenerator;
import com.vaadin.ui.Table.ColumnHeaderMode;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window.CloseEvent;
import com.vaadin.ui.Window.CloseListener;

//@Theme("reindeer")
//@Theme("runo")
//@Theme("valo")
@Theme("sensorhub")
public class AdminUI extends com.vaadin.ui.UI {
    private static final long serialVersionUID = 4069325051233125115L;

    private static final Action ADD_MODULE_ACTION = new Action("Add Module",
            new ThemeResource("icons/module_add.png"));
    private static final Action REMOVE_MODULE_ACTION = new Action("Remove Module",
            new ThemeResource("icons/module_delete.png"));
    private static final Action ENABLE_MODULE_ACTION = new Action("Enable", new ThemeResource("icons/enable.png"));
    private static final Action DISABLE_MODULE_ACTION = new Action("Disable",
            new ThemeResource("icons/disable.gif"));
    private static final Resource LOGO_ICON = new ClassResource("/sensorhub_logo_128.png");
    private static final Resource ACC_TAB_ICON = new ThemeResource("icons/enable.png");
    private static final String STYLE_LOGO = "logo";

    protected static final Logger log = LoggerFactory.getLogger(AdminUI.class);
    private static AdminUI singleton;

    VerticalLayout configArea;
    AdminUIConfig uiConfig;

    protected Map<Class<?>, MyBeanItemContainer<ModuleConfig>> moduleConfigLists = new HashMap<Class<?>, MyBeanItemContainer<ModuleConfig>>();
    protected Map<String, Class<? extends IModuleAdminPanel<?>>> customPanels = new HashMap<String, Class<? extends IModuleAdminPanel<?>>>();
    protected Map<String, Class<? extends IModuleConfigForm>> customForms = new HashMap<String, Class<? extends IModuleConfigForm>>();

    public static AdminUI getInstance() {
        return singleton;
    }

    public AdminUI() {
        singleton = this;
    }

    @Override
    protected void init(VaadinRequest request) {
        String configClass = null;
        moduleConfigLists.clear();

        // retrieve module config
        try {
            Properties initParams = request.getService().getDeploymentConfiguration().getInitParameters();
            String moduleID = initParams.getProperty(AdminUIModule.SERVLET_PARAM_MODULE_ID);
            uiConfig = (AdminUIConfig) SensorHub.getInstance().getModuleRegistry().getModuleById(moduleID)
                    .getConfiguration();
        } catch (Exception e) {
            throw new RuntimeException("Cannot get UI module configuration", e);
        }

        try {
            // load default form builders
            customForms.put(HttpServerConfig.class.getCanonicalName(), HttpServerConfigForm.class);
            customForms.put(StreamStorageConfig.class.getCanonicalName(), GenericStorageConfigForm.class);
            customForms.put(CommConfig.class.getCanonicalName(), CommConfigForm.class);
            customForms.put(SOSConfigForm.SOS_PACKAGE + "SOSServiceConfig", SOSConfigForm.class);
            customForms.put(SOSConfigForm.SOS_PACKAGE + "SOSProviderConfig", SOSConfigForm.class);

            // load custom form builders defined in config
            for (CustomUIConfig customForm : uiConfig.customForms) {
                configClass = customForm.configClass;
                Class<?> clazz = Class.forName(customForm.uiClass);
                customForms.put(configClass, (Class<IModuleConfigForm>) clazz);
                log.debug("Loaded custom form for " + configClass);
            }
        } catch (Exception e) {
            log.error("Error while instantiating form builder for config class " + configClass, e);
        }

        try {
            // load default panel builders
            customPanels.put(SensorConfig.class.getCanonicalName(), SensorAdminPanel.class);
            customPanels.put(StorageConfig.class.getCanonicalName(), StorageAdminPanel.class);

            // load custom panel builders defined in config
            for (CustomUIConfig customPanel : uiConfig.customPanels) {
                configClass = customPanel.configClass;
                Class<?> clazz = Class.forName(customPanel.uiClass);
                customPanels.put(configClass, (Class<IModuleAdminPanel<?>>) clazz);
                log.debug("Loaded custom panel for " + configClass);
            }
        } catch (Exception e) {
            log.error("Error while instantiating panel builder for config class " + configClass, e);
        }

        // register new field converter for interger numbers
        @SuppressWarnings("serial")
        ConverterFactory converterFactory = new DefaultConverterFactory() {
            @Override
            protected <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> findConverter(
                    Class<PRESENTATION> presentationType, Class<MODEL> modelType) {
                // Handle String <-> Integer/Short/Long
                if (presentationType == String.class
                        && (modelType == Long.class || modelType == Integer.class || modelType == Short.class)) {
                    return (Converter<PRESENTATION, MODEL>) new StringToIntegerConverter() {
                        @Override
                        protected NumberFormat getFormat(Locale locale) {
                            NumberFormat format = super.getFormat(Locale.US);
                            format.setGroupingUsed(false);
                            return format;
                        }
                    };
                }
                // Let default factory handle the rest
                return super.findConverter(presentationType, modelType);
            }
        };
        VaadinSession.getCurrent().setConverterFactory(converterFactory);

        // init main panels
        HorizontalSplitPanel splitPanel = new HorizontalSplitPanel();
        splitPanel.setMinSplitPosition(300.0f, Unit.PIXELS);
        splitPanel.setMaxSplitPosition(30.0f, Unit.PERCENTAGE);
        splitPanel.setSplitPosition(350.0f, Unit.PIXELS);
        setContent(splitPanel);

        // build left pane
        VerticalLayout leftPane = new VerticalLayout();
        leftPane.setSizeFull();

        // header image and title
        Component header = buildHeader();
        leftPane.addComponent(header);
        leftPane.setExpandRatio(header, 0);

        // toolbar
        Component toolbar = buildToolbar();
        leftPane.addComponent(toolbar);
        leftPane.setExpandRatio(toolbar, 0);

        // accordion with several sections
        Accordion stack = new Accordion();
        stack.setSizeFull();
        VerticalLayout layout;
        Tab tab;

        layout = new VerticalLayout();
        tab = stack.addTab(layout, "Sensors");
        tab.setIcon(ACC_TAB_ICON);
        buildModuleList(layout, SensorConfig.class);

        layout = new VerticalLayout();
        tab = stack.addTab(layout, "Storage");
        tab.setIcon(ACC_TAB_ICON);
        buildModuleList(layout, StorageConfig.class);

        layout = new VerticalLayout();
        tab = stack.addTab(layout, "Processing");
        tab.setIcon(ACC_TAB_ICON);
        buildModuleList(layout, ProcessConfig.class);

        layout = new VerticalLayout();
        tab = stack.addTab(layout, "Services");
        tab.setIcon(ACC_TAB_ICON);
        buildModuleList(layout, ServiceConfig.class);

        layout = new VerticalLayout();
        tab = stack.addTab(layout, "Clients");
        tab.setIcon(ACC_TAB_ICON);
        buildModuleList(layout, ClientConfig.class);

        layout = new VerticalLayout();
        tab = stack.addTab(layout, "Network");
        tab.setIcon(ACC_TAB_ICON);
        buildNetworkConfig(layout);

        leftPane.addComponent(stack);
        leftPane.setExpandRatio(stack, 1);
        splitPanel.addComponent(leftPane);

        // init config area
        configArea = new VerticalLayout();
        configArea.setMargin(true);
        splitPanel.addComponent(configArea);
    }

    protected Component buildHeader() {
        HorizontalLayout header = new HorizontalLayout();
        header.setMargin(false);
        header.setHeight(100.0f, Unit.PIXELS);
        header.setWidth(100.0f, Unit.PERCENTAGE);
        Image img = new Image(null, LOGO_ICON);
        img.setHeight(90, Unit.PIXELS);
        img.setStyleName(STYLE_LOGO);
        header.addComponent(img);
        Label title = new Label("SensorHub");
        title.addStyleName(UIConstants.STYLE_H1);
        title.addStyleName(STYLE_LOGO);
        title.setWidth(null);
        header.addComponent(title);
        header.setExpandRatio(img, 0);
        header.setExpandRatio(title, 1);
        header.setComponentAlignment(img, Alignment.MIDDLE_LEFT);
        header.setComponentAlignment(title, Alignment.MIDDLE_RIGHT);
        return header;
    }

    protected Component buildToolbar() {
        HorizontalLayout toolbar = new HorizontalLayout();
        toolbar.setWidth(100.0f, Unit.PERCENTAGE);

        // apply changes button
        Button saveButton = new Button("Save Config");
        saveButton.setDescription("Save Config");
        saveButton.setIcon(UIConstants.APPLY_ICON);
        saveButton.addStyleName(UIConstants.STYLE_SMALL);
        saveButton.setWidth(100.0f, Unit.PERCENTAGE);

        // apply button action
        saveButton.addClickListener(new Button.ClickListener() {
            private static final long serialVersionUID = 1L;

            public void buttonClick(ClickEvent event) {
                try {
                    SensorHub.getInstance().getModuleRegistry().saveModulesConfiguration();
                } catch (Exception e) {
                    AdminUI.log.error("Error while saving SensorHub configuration", e);
                    Notification.show("Error", e.getMessage(), Notification.Type.ERROR_MESSAGE);
                }
            }
        });

        toolbar.addComponent(saveButton);
        return toolbar;
    }

    protected void buildNetworkConfig(VerticalLayout layout) {
        // add config objects to container
        MyBeanItemContainer<ModuleConfig> container = new MyBeanItemContainer<ModuleConfig>(ModuleConfig.class);
        container.addBean(HttpServer.getInstance().getConfiguration());
        //container.addBean(uiConfig); 
        displayModuleList(layout, container, null);
    }

    protected void buildModuleList(VerticalLayout layout, final Class<?> configType) {
        ModuleRegistry reg = SensorHub.getInstance().getModuleRegistry();

        // build bean items and add them to container
        MyBeanItemContainer<ModuleConfig> container = new MyBeanItemContainer<ModuleConfig>(ModuleConfig.class);
        for (IModule<?> module : reg.getLoadedModules()) {
            ModuleConfig config = module.getConfiguration().clone();
            if (configType.isAssignableFrom(config.getClass()))
                container.addBean(config);
        }

        moduleConfigLists.put(configType, container);
        displayModuleList(layout, container, configType);
    }

    @SuppressWarnings("serial")
    protected void displayModuleList(VerticalLayout layout, final MyBeanItemContainer<ModuleConfig> container,
            final Class<?> configType) {
        // create table to display module list
        final Table table = new Table();
        table.setSizeFull();
        table.setSelectable(true);
        table.setImmediate(true);
        table.setColumnReorderingAllowed(false);
        table.setContainerDataSource(container);
        table.setVisibleColumns(new Object[] { UIConstants.PROP_NAME, UIConstants.PROP_ENABLED });
        table.setColumnWidth(UIConstants.PROP_ENABLED, 100);
        table.setColumnHeaderMode(ColumnHeaderMode.HIDDEN);

        // value converter for enabled field
        table.setConverter(UIConstants.PROP_ENABLED, new Converter<String, Boolean>() {
            @Override
            public Boolean convertToModel(String value, Class<? extends Boolean> targetType, Locale locale)
                    throws com.vaadin.data.util.converter.Converter.ConversionException {
                return (value != null && value.equals("enabled"));
            }

            @Override
            public String convertToPresentation(Boolean value, Class<? extends String> targetType, Locale locale)
                    throws com.vaadin.data.util.converter.Converter.ConversionException {
                return value ? "enabled" : "disabled";
            }

            @Override
            public Class<Boolean> getModelType() {
                return boolean.class;
            }

            @Override
            public Class<String> getPresentationType() {
                return String.class;
            }
        });

        table.setCellStyleGenerator(new CellStyleGenerator() {
            @Override
            public String getStyle(Table source, Object itemId, Object propertyId) {
                if (propertyId != null && propertyId.equals(UIConstants.PROP_ENABLED)) {
                    boolean val = (boolean) table.getItem(itemId).getItemProperty(propertyId).getValue();
                    if (val == true)
                        return "green";
                    else
                        return "red";
                }

                return null;
            }
        });

        // item click listener to display selected module settings
        table.addItemClickListener(new ItemClickListener() {
            @Override
            public void itemClick(ItemClickEvent event) {
                openModuleInfo((MyBeanItem<ModuleConfig>) event.getItem());
            }
        });
        layout.addComponent(table);

        // context menu
        table.addActionHandler(new Handler() {
            @Override
            public Action[] getActions(Object target, Object sender) {
                List<Action> actions = new ArrayList<Action>(10);

                if (target != null) {
                    boolean enabled = ((MyBeanItem<ModuleConfig>) table.getItem(target)).getBean().enabled;
                    if (enabled)
                        actions.add(DISABLE_MODULE_ACTION);
                    else
                        actions.add(ENABLE_MODULE_ACTION);
                    actions.add(REMOVE_MODULE_ACTION);
                } else {
                    if (configType != null)
                        actions.add(ADD_MODULE_ACTION);
                }

                return actions.toArray(new Action[0]);
            }

            @Override
            public void handleAction(Action action, Object sender, Object target) {
                final Object selectedId = table.getValue();

                if (action == ADD_MODULE_ACTION) {
                    // show popup to select among available module types
                    ModuleTypeSelectionPopup popup = new ModuleTypeSelectionPopup(configType,
                            new ModuleTypeSelectionCallback() {
                                public void configSelected(Class<?> moduleType, ModuleConfig config) {
                                    try {
                                        // add to main config
                                        ModuleRegistry reg = SensorHub.getInstance().getModuleRegistry();
                                        reg.loadModule(config);
                                    } catch (Exception e) {
                                        String msg = "The module could not be initialized";
                                        Notification.show("Error", msg + '\n' + e.getMessage(),
                                                Notification.Type.ERROR_MESSAGE);
                                    }

                                    MyBeanItem<ModuleConfig> newBeanItem = container.addBean(config);
                                    openModuleInfo(newBeanItem);
                                }
                            });
                    popup.setModal(true);
                    addWindow(popup);
                }

                else if (selectedId != null) {
                    // possible actions when a module is selected
                    final Item item = table.getItem(selectedId);
                    final String moduleId = (String) item.getItemProperty(UIConstants.PROP_ID).getValue();
                    final String moduleName = (String) item.getItemProperty(UIConstants.PROP_NAME).getValue();

                    if (action == REMOVE_MODULE_ACTION) {
                        final ConfirmDialog popup = new ConfirmDialog("Are you sure you want to remove module "
                                + moduleName + "?</br>All settings will be lost.");
                        popup.addCloseListener(new CloseListener() {
                            @Override
                            public void windowClose(CloseEvent e) {
                                if (popup.isConfirmed()) {
                                    try {
                                        SensorHub.getInstance().getModuleRegistry().destroyModule(moduleId);
                                        container.removeItem(selectedId);
                                    } catch (SensorHubException ex) {
                                        String msg = "The module could not be removed";
                                        Notification.show("Error", msg + '\n' + ex.getMessage(),
                                                Notification.Type.ERROR_MESSAGE);
                                        AdminUI.log.debug(msg, e);
                                    }
                                }
                            }
                        });

                        addWindow(popup);

                    } else if (action == ENABLE_MODULE_ACTION) {
                        final ConfirmDialog popup = new ConfirmDialog(
                                "Are you sure you want to enable module " + moduleName + "?");
                        popup.addCloseListener(new CloseListener() {
                            @Override
                            public void windowClose(CloseEvent e) {
                                if (popup.isConfirmed()) {
                                    try {
                                        SensorHub.getInstance().getModuleRegistry().enableModule(moduleId);
                                        item.getItemProperty(UIConstants.PROP_ENABLED).setValue(true);
                                        openModuleInfo((MyBeanItem<ModuleConfig>) item);
                                    } catch (SensorHubException ex) {
                                        String msg = "The module could not be enabled";
                                        Notification.show("Error", msg + '\n' + ex.getMessage(),
                                                Notification.Type.ERROR_MESSAGE);
                                    }
                                }
                            }
                        });

                        addWindow(popup);
                    } else if (action == DISABLE_MODULE_ACTION) {
                        final ConfirmDialog popup = new ConfirmDialog(
                                "Are you sure you want to disable module " + moduleName + "?");
                        popup.addCloseListener(new CloseListener() {
                            @Override
                            public void windowClose(CloseEvent e) {
                                if (popup.isConfirmed()) {
                                    try {
                                        SensorHub.getInstance().getModuleRegistry().disableModule(moduleId);
                                        item.getItemProperty(UIConstants.PROP_ENABLED).setValue(false);
                                    } catch (SensorHubException ex) {
                                        String msg = "The module could not be disabled";
                                        Notification.show("Error", msg + '\n' + ex.getMessage(),
                                                Notification.Type.ERROR_MESSAGE);
                                    }
                                }
                            }
                        });

                        addWindow(popup);
                    }
                }
            }
        });

        layout.setSizeFull();
    }

    protected void openModuleInfo(MyBeanItem<ModuleConfig> beanItem) {
        configArea.removeAllComponents();

        // this will load the module (i.e. call init) if not already loaded
        IModule<?> module = null;
        try {
            module = SensorHub.getInstance().getModuleRegistry().getModuleById(beanItem.getBean().id);
        } catch (Exception e) {
        }

        // get panel for this config object        
        Class<?> configClass = beanItem.getBean().getClass();
        IModuleAdminPanel<IModule<?>> panel = generatePanel(configClass);
        panel.build(beanItem, module);

        // generate module admin panel        
        configArea.addComponent(panel);
    }

    protected IModuleAdminPanel<IModule<?>> generatePanel(Class<?> clazz) {
        try {
            // check if there is a custom panel registered, if not use default
            Class<IModuleAdminPanel<IModule<?>>> uiClass = null;
            while (uiClass == null && clazz != null) {
                uiClass = (Class<IModuleAdminPanel<IModule<?>>>) customPanels.get(clazz.getCanonicalName());
                clazz = clazz.getSuperclass();
            }

            if (uiClass == null)
                return new DefaultModulePanel<IModule<?>>();

            return uiClass.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("Cannot instantiate UI class", e);
        }
    }

    protected IModuleConfigForm generateForm(Class<?> clazz) {
        try {
            // check if there is a custom form registered, if not use default        
            Class<IModuleConfigForm> uiClass = null;
            while (uiClass == null && clazz != null) {
                uiClass = (Class<IModuleConfigForm>) customForms.get(clazz.getCanonicalName());
                clazz = clazz.getSuperclass();
            }

            if (uiClass == null)
                return new GenericConfigForm();

            return uiClass.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("Cannot instantiate UI class", e);
        }
    }

}