001package jmri.managers.configurexml;
002
003import java.util.List;
004import java.util.SortedSet;
005import jmri.InstanceManager;
006import jmri.Memory;
007import jmri.MemoryManager;
008import jmri.configurexml.JmriConfigureXmlException;
009import jmri.jmrit.roster.RosterEntry;
010import org.jdom2.Element;
011import org.slf4j.Logger;
012import org.slf4j.LoggerFactory;
013
014/**
015 * Provides the abstract base and store functionality for configuring
016 * MemoryManagers, working with AbstractMemoryManagers.
017 * <p>
018 * Also serves as base class for {@link jmri.configurexml.BlockManagerXml} persistence.
019 * <p>
020 * Typically, a subclass will just implement the load(Element memories) class,
021 * relying on implementation here to load the individual Memory objects. Note
022 * that these are stored explicitly, so the resolution mechanism doesn't need to
023 * see *Xml classes for each specific Memory or AbstractMemory subclass at store
024 * time.
025 *
026 * @author Bob Jacobsen Copyright: Copyright (c) 2002, 2008
027 */
028public abstract class AbstractMemoryManagerConfigXML extends AbstractNamedBeanManagerConfigXML {
029
030    public AbstractMemoryManagerConfigXML() {
031    }
032
033    /**
034     * Default implementation for storing the contents of a MemoryManager.
035     *
036     * @param o Object to store, of type MemoryManager
037     * @return Element containing the complete info
038     */
039    @Override
040    public Element store(Object o) {
041        Element memories = new Element("memories");
042        setStoreElementClass(memories);
043        MemoryManager mm = (MemoryManager) o;
044        if (mm != null) {
045            SortedSet<Memory> memList = mm.getNamedBeanSet();
046            // don't return an element if there are no memories to include
047            if (memList.isEmpty()) {
048                return null;
049            }
050            // store the memories
051            for (Memory m : memList) {
052                String mName = m.getSystemName();
053                log.debug("system name is {}", mName);
054
055                Element elem = new Element("memory");
056                elem.addContent(new Element("systemName").addContent(mName));
057
058                // store common part
059                storeCommon(m, elem);
060
061                // store value if non-null; null values omitted
062                Object obj = m.getValue();
063                if (obj != null) {
064                    if (obj instanceof RosterEntry) {
065                        String valueClass = obj.getClass().getName();
066                        String value = ((RosterEntry) obj).getId();
067                        elem.setAttribute("value", value);
068                        elem.setAttribute("valueClass", valueClass);
069                    } else {
070                        String value = obj.toString();
071                        elem.setAttribute("value", value);
072                    }
073                }
074
075                log.debug("store Memory {}", mName);
076                memories.addContent(elem);
077            }
078        }
079        return memories;
080    }
081
082    /**
083     * Subclass provides implementation to create the correct top element,
084     * including the type information. Default implementation is to use the
085     * local class here.
086     *
087     * @param memories The top-level element being created
088     */
089    abstract public void setStoreElementClass(Element memories);
090
091    /**
092     * Create a MemoryManager object of the correct class, then register and
093     * fill it.
094     *
095     * @param sharedMemories  Shared top level Element to unpack.
096     * @param perNodeMemories Per-node top level Element to unpack.
097     * @return true if successful
098     * @throws jmri.configurexml.JmriConfigureXmlException if error during load.
099     */
100    @Override
101    abstract public boolean load(Element sharedMemories, Element perNodeMemories) throws JmriConfigureXmlException;
102
103    /**
104     * Utility method to load the individual Memory objects. If there's no
105     * additional info needed for a specific Memory type, invoke this with the
106     * parent of the set of Memory elements.
107     *
108     * @param memories Element containing the Memory elements to load.
109     */
110    public void loadMemories(Element memories) {
111        List<Element> memoryList = memories.getChildren("memory");
112        log.debug("Found {} Memory objects", memoryList.size());
113        MemoryManager mm = InstanceManager.memoryManagerInstance();
114
115        for (Element el : memoryList) {
116            String sysName = getSystemName(el);
117            if (sysName == null) {
118                log.warn("unexpected null in systemName {}", (el));
119                break;
120            }
121
122            String userName = getUserName(el);
123
124            checkNameNormalization(sysName, userName, mm);
125
126            log.debug("create Memory: ({})({})", sysName, (userName == null ? "<null>" : userName));
127            Memory m = mm.newMemory(sysName, userName);
128            if (el.getAttribute("value") != null) {
129                loadValue(el, m);
130            }
131            // load common parts
132            loadCommon(m, el);
133        }
134    }
135
136    @Override
137    public int loadOrder() {
138        return InstanceManager.memoryManagerInstance().getXMLOrder();
139    }
140
141    private void loadValue(Element memory, Memory m) {
142        String value = memory.getAttribute("value").getValue();
143        if (memory.getAttribute("valueClass") != null) {
144            String adapter = memory.getAttribute("valueClass").getValue();
145            if (adapter.equals("jmri.jmrit.roster.RosterEntry")) {
146                RosterEntry re = jmri.jmrit.roster.Roster.getDefault().getEntryForId(value);
147                m.setValue(re);
148                return;
149            }
150        }
151        m.setValue(value);
152    }
153
154    private final static Logger log = LoggerFactory.getLogger(AbstractMemoryManagerConfigXML.class);
155
156}