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