gt:             while (uiClass == null && clazz != null)
context: /***************************** 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;
  