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.DefaultDigitalBooleanActionManager; 012import jmri.jmrit.logixng.implementation.DefaultMaleDigitalBooleanActionSocket; 013import jmri.managers.configurexml.AbstractNamedBeanManagerConfigXML; 014import jmri.util.ThreadingUtil; 015 016import org.jdom2.Element; 017 018/** 019 * Provides the functionality for configuring ActionManagers 020 * 021 * @author Dave Duchamp Copyright (c) 2007 022 * @author Daniel Bergqvist Copyright (c) 2018 023 */ 024public class DefaultDigitalBooleanActionManagerXml extends AbstractManagerXml { 025 026 private final Map<String, Class<?>> xmlClasses = new HashMap<>(); 027 028 public DefaultDigitalBooleanActionManagerXml() { 029 } 030 031 /** 032 * Default implementation for storing the contents of a DigitalBooleanActionManager 033 * 034 * @param o Object to store, of type DigitalBooleanActionManager 035 * @return Element containing the complete info 036 */ 037 @Override 038 public Element store(Object o) { 039 Element actions = new Element("LogixNGDigitalBooleanActions"); 040 setStoreElementClass(actions); 041 DigitalBooleanActionManager tm = (DigitalBooleanActionManager) o; 042 if (tm != null) { 043 if (tm.getNamedBeanSet().isEmpty()) return null; 044 for (MaleDigitalBooleanActionSocket action : tm.getNamedBeanSet()) { 045 log.debug("action system name is {}", action.getSystemName()); // NOI18N 046 try { 047 List<Element> elements = new ArrayList<>(); 048 // The male socket may be embedded in other male sockets 049 MaleDigitalBooleanActionSocket a = action; 050 elements.add(storeMaleSocket(a)); 051 while (!(a instanceof DefaultMaleDigitalBooleanActionSocket)) { 052 a = (MaleDigitalBooleanActionSocket) 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 actions.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 (actions); 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 actions The top-level element being created 075 */ 076 public void setStoreElementClass(Element actions) { 077 actions.setAttribute("class", this.getClass().getName()); // NOI18N 078 } 079 080 /** 081 * Create a DigitalBooleanActionManager object of the correct class, then register 082 * and fill it. 083 * 084 * @param sharedAction Shared top level Element to unpack. 085 * @param perNodeAction Per-node top level Element to unpack. 086 * @return true if successful 087 */ 088 @Override 089 public boolean load(Element sharedAction, Element perNodeAction) { 090 // create the master object 091 replaceActionManager(); 092 // load individual sharedAction 093 loadActions(sharedAction); 094 return true; 095 } 096 097 /** 098 * Utility method to load the individual DigitalBooleanActionBean objects. If 099 * there's no additional info needed for a specific action type, invoke 100 * this with the parent of the set of DigitalBooleanActionBean elements. 101 * 102 * @param actions Element containing the DigitalBooleanActionBean elements to load. 103 */ 104 public void loadActions(Element actions) { 105 106 List<Element> actionList = actions.getChildren(); // NOI18N 107 log.debug("Found {} actions", actionList.size()); // NOI18N 108 109 for (int i = 0; i < actionList.size(); i++) { 110 111 String className = actionList.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(DigitalBooleanActionManager.class).getLastRegisteredMaleSocket(); 139 o.load(actionList.get(i), null); 140 141 // Load male socket data if a new bean has been registered 142 MaleSocket newLastItem = InstanceManager.getDefault(DigitalBooleanActionManager.class).getLastRegisteredMaleSocket(); 143 if (newLastItem != oldLastItem) loadMaleSocket(actionList.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 DigitalBooleanActionManager, if there is one, with one newly 157 * created during a load operation. This is skipped if they are of the same 158 * absolute type. 159 */ 160 protected void replaceActionManager() { 161 if (InstanceManager.getDefault(jmri.jmrit.logixng.DigitalBooleanActionManager.class).getClass().getName() 162 .equals(DefaultDigitalBooleanActionManager.class.getName())) { 163 return; 164 } 165 // if old manager exists, remove it from configuration process 166 if (InstanceManager.getNullableDefault(jmri.jmrit.logixng.DigitalBooleanActionManager.class) != null) { 167 ConfigureManager cmOD = InstanceManager.getNullableDefault(jmri.ConfigureManager.class); 168 if (cmOD != null) { 169 cmOD.deregister(InstanceManager.getDefault(jmri.jmrit.logixng.DigitalBooleanActionManager.class)); 170 } 171 172 } 173 174 ThreadingUtil.runOnGUI(() -> { 175 // register new one with InstanceManager 176 DefaultDigitalBooleanActionManager pManager = DefaultDigitalBooleanActionManager.instance(); 177 InstanceManager.store(pManager, DigitalBooleanActionManager.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_DIGITAL_BOOLEAN_ACTIONS); 182 } 183 }); 184 } 185 186 @Override 187 public int loadOrder() { 188 return InstanceManager.getDefault(jmri.jmrit.logixng.DigitalBooleanActionManager.class).getXMLOrder(); 189 } 190 191 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultDigitalBooleanActionManagerXml.class); 192}