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.GlobalVariable;
014import jmri.jmrit.logixng.implementation.DefaultGlobalVariableManager;
015import jmri.managers.configurexml.AbstractNamedBeanManagerConfigXML;
016import jmri.util.ThreadingUtil;
017
018import org.jdom2.Element;
019
020/**
021 * Provides the functionality for configuring DefaultGlobalVariableManager
022 *
023 * @author Dave Duchamp Copyright (c) 2007
024 * @author Daniel Bergqvist Copyright (c) 2018
025 */
026public class DefaultGlobalVariableManagerXml extends AbstractManagerXml {
027
028    private final Map<String, Class<?>> xmlClasses = new HashMap<>();
029
030    public DefaultGlobalVariableManagerXml() {
031    }
032
033    /**
034     * Default implementation for storing the contents of a GlobalVariableManager
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("LogixNGGlobalVariables");
042        setStoreElementClass(expressions);
043        DefaultGlobalVariableManager tm = (DefaultGlobalVariableManager) o;
044        if (tm != null) {
045            if (tm.getNamedBeanSet().isEmpty()) return null;
046            for (GlobalVariable 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 GlobalVariableManager 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 GlobalVariableManager, 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(GlobalVariableManager.class).getClass().getName()
145                .equals(DefaultGlobalVariableManager.class.getName())) {
146            return;
147        }
148        // if old manager exists, remove it from configuration process
149        if (InstanceManager.getNullableDefault(GlobalVariableManager.class) != null) {
150            ConfigureManager cmOD = InstanceManager.getNullableDefault(jmri.ConfigureManager.class);
151            if (cmOD != null) {
152                cmOD.deregister(InstanceManager.getDefault(GlobalVariableManager.class));
153            }
154
155        }
156
157        ThreadingUtil.runOnGUI(() -> {
158            // register new one with InstanceManager
159            DefaultGlobalVariableManager pManager = DefaultGlobalVariableManager.instance();
160            InstanceManager.store(pManager, GlobalVariableManager.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_GLOBAL_VARIABLES);
165            }
166        });
167    }
168
169    @Override
170    public int loadOrder() {
171        return InstanceManager.getDefault(GlobalVariableManager.class).getXMLOrder();
172    }
173
174    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultGlobalVariableManagerXml.class);
175}