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.implementation.DefaultNamedTableManager;
014import jmri.managers.configurexml.AbstractNamedBeanManagerConfigXML;
015import jmri.util.ThreadingUtil;
016
017import org.jdom2.Element;
018
019/**
020 * Provides the functionality for configuring DefaultNamedTableManager
021 *
022 * @author Dave Duchamp Copyright (c) 2007
023 * @author Daniel Bergqvist Copyright (c) 2018
024 */
025public class DefaultNamedTableManagerXml extends AbstractManagerXml {
026
027    private final Map<String, Class<?>> xmlClasses = new HashMap<>();
028    
029    public DefaultNamedTableManagerXml() {
030    }
031
032    /**
033     * Default implementation for storing the contents of a NamedTableManager
034     *
035     * @param o Object to store, of type LogixManager
036     * @return Element containing the complete info
037     */
038    @Override
039    public Element store(Object o) {
040        Element tables = new Element("LogixNGTables");
041        setStoreElementClass(tables);
042        DefaultNamedTableManager tm = (DefaultNamedTableManager) o;
043        if (tm != null) {
044            if (tm.getNamedBeanSet().isEmpty()) return null;
045            for (NamedTable table : tm.getNamedBeanSet()) {
046                log.debug("table system name is {}", table.getSystemName());  // NOI18N
047                try {
048                    Element e = jmri.configurexml.ConfigXmlManager.elementFromObject(table);
049                    if (e != null) {
050                        tables.addContent(e);
051                    }
052                } catch (RuntimeException e) {
053                    log.error("Error storing table: {}", e, e);
054                }
055            }
056        }
057        return (tables);
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 NamedTableManager 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 NamedTableManager, 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(NamedTableManager.class).getClass().getName()
145                .equals(DefaultNamedTableManager.class.getName())) {
146            return;
147        }
148        // if old manager exists, remove it from configuration process
149        if (InstanceManager.getNullableDefault(NamedTableManager.class) != null) {
150            ConfigureManager cmOD = InstanceManager.getNullableDefault(jmri.ConfigureManager.class);
151            if (cmOD != null) {
152                cmOD.deregister(InstanceManager.getDefault(NamedTableManager.class));
153            }
154
155        }
156
157        ThreadingUtil.runOnGUI(() -> {
158            // register new one with InstanceManager
159            DefaultNamedTableManager pManager = DefaultNamedTableManager.instance();
160            InstanceManager.store(pManager, NamedTableManager.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_TABLES);
165            }
166        });
167    }
168
169    @Override
170    public int loadOrder() {
171        return InstanceManager.getDefault(NamedTableManager.class).getXMLOrder();
172    }
173
174    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultNamedTableManagerXml.class);
175}