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