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