001package jmri.jmrit.logixng.implementation.configurexml; 002 003import java.lang.reflect.Constructor; 004import java.lang.reflect.InvocationTargetException; 005import java.util.HashMap; 006import java.util.List; 007import java.util.Map; 008 009import jmri.ConfigureManager; 010import jmri.InstanceManager; 011import jmri.configurexml.JmriConfigureXmlException; 012import jmri.jmrit.logixng.*; 013import jmri.jmrit.logixng.Module; 014import jmri.jmrit.logixng.implementation.DefaultModuleManager; 015import jmri.managers.configurexml.AbstractNamedBeanManagerConfigXML; 016import jmri.util.ThreadingUtil; 017 018import org.jdom2.Element; 019 020/** 021 * Provides the functionality for configuring DefaultModuleManager 022 * 023 * @author Dave Duchamp Copyright (c) 2007 024 * @author Daniel Bergqvist Copyright (c) 2018 025 */ 026public class DefaultModuleManagerXml extends AbstractManagerXml { 027 028 private final Map<String, Class<?>> xmlClasses = new HashMap<>(); 029 030 public DefaultModuleManagerXml() { 031 } 032 033 /** 034 * Default implementation for storing the contents of a ModuleManager 035 * 036 * @param o Object to store, of type LogixManager 037 * @return Element containing the complete info 038 */ 039 @Override 040 public Element store(Object o) { 041 Element expressions = new Element("LogixNGModules"); 042 setStoreElementClass(expressions); 043 DefaultModuleManager tm = (DefaultModuleManager) o; 044 if (tm != null) { 045 if (tm.getNamedBeanSet().isEmpty()) return null; 046 for (Module module : tm.getNamedBeanSet()) { 047 try { 048 Element e = jmri.configurexml.ConfigXmlManager.elementFromObject(module); 049 if (e != null) { 050 expressions.addContent(e); 051 } 052 } catch (RuntimeException e) { 053 log.error("Error storing action: {}", e, e); 054 } 055 } 056 } 057 return expressions; 058 } 059 060 /** 061 * Subclass provides implementation to create the correct top element, 062 * including the type information. Default implementation is to use the 063 * local class here. 064 * 065 * @param expressions The top-level element being created 066 */ 067 public void setStoreElementClass(Element expressions) { 068 expressions.setAttribute("class", this.getClass().getName()); // NOI18N 069 } 070 071 /** 072 * Create a ModuleManager object of the correct class, then 073 * register and fill it. 074 * 075 * @param sharedExpression Shared top level Element to unpack. 076 * @param perNodeExpression Per-node top level Element to unpack. 077 * @return true if successful 078 */ 079 @Override 080 public boolean load(Element sharedExpression, Element perNodeExpression) { 081 // create the master object 082 replaceExpressionManager(); 083 // load individual sharedLogix 084 loadTables(sharedExpression); 085 return true; 086 } 087 088 /** 089 * Utility method to load the individual Logix objects. If there's no 090 * additional info needed for a specific logix type, invoke this with the 091 * parent of the set of Logix elements. 092 * 093 * @param expressions Element containing the Logix elements to load. 094 */ 095 public void loadTables(Element expressions) { 096 097 List<Element> expressionList = expressions.getChildren(); // NOI18N 098 log.debug("Found {} tables", expressionList.size() ); // NOI18N 099 100 for (int i = 0; i < expressionList.size(); i++) { 101 102 String className = expressionList.get(i).getAttribute("class").getValue(); 103// log.error("className: " + className); 104 105 Class<?> clazz = xmlClasses.get(className); 106 107 if (clazz == null) { 108 try { 109 clazz = Class.forName(className); 110 xmlClasses.put(className, clazz); 111 } catch (ClassNotFoundException ex) { 112 log.error("cannot load class {}", className, ex); 113 } 114 } 115 116 if (clazz != null) { 117 Constructor<?> c = null; 118 try { 119 c = clazz.getConstructor(); 120 } catch (NoSuchMethodException | SecurityException ex) { 121 log.error("cannot create constructor", ex); 122 } 123 124 if (c != null) { 125 try { 126 AbstractNamedBeanManagerConfigXML o = (AbstractNamedBeanManagerConfigXML)c.newInstance(); 127 o.load(expressionList.get(i), null); 128 } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { 129 log.error("cannot create object", ex); 130 } catch (JmriConfigureXmlException ex) { 131 log.error("cannot load action", ex); 132 } 133 } 134 } 135 } 136 } 137 138 /** 139 * Replace the current ModuleManager, if there is one, with one newly created 140 * during a load operation. This is skipped if they are of the same absolute 141 * type. 142 */ 143 protected void replaceExpressionManager() { 144 if (InstanceManager.getDefault(ModuleManager.class).getClass().getName() 145 .equals(DefaultModuleManager.class.getName())) { 146 return; 147 } 148 // if old manager exists, remove it from configuration process 149 if (InstanceManager.getNullableDefault(ModuleManager.class) != null) { 150 ConfigureManager cmOD = InstanceManager.getNullableDefault(jmri.ConfigureManager.class); 151 if (cmOD != null) { 152 cmOD.deregister(InstanceManager.getDefault(ModuleManager.class)); 153 } 154 155 } 156 157 ThreadingUtil.runOnGUI(() -> { 158 // register new one with InstanceManager 159 DefaultModuleManager pManager = DefaultModuleManager.instance(); 160 InstanceManager.store(pManager, ModuleManager.class); 161 // register new one for configuration 162 ConfigureManager cmOD = InstanceManager.getNullableDefault(jmri.ConfigureManager.class); 163 if (cmOD != null) { 164 cmOD.registerConfig(pManager, jmri.Manager.LOGIXNG_MODULES); 165 } 166 }); 167 } 168 169 @Override 170 public int loadOrder() { 171 return InstanceManager.getDefault(ModuleManager.class).getXMLOrder(); 172 } 173 174 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultModuleManagerXml.class); 175}