001package jmri.managers.configurexml; 002 003import java.util.List; 004import java.util.SortedSet; 005 006import jmri.ConfigureManager; 007import jmri.InstanceManager; 008import jmri.Manager; 009import jmri.SignalHead; 010import jmri.SignalHeadManager; 011import jmri.configurexml.ConfigXmlManager; 012import jmri.jmrix.internal.InternalSystemConnectionMemo; 013import jmri.managers.AbstractSignalHeadManager; 014import org.jdom2.Element; 015import org.slf4j.Logger; 016import org.slf4j.LoggerFactory; 017 018/** 019 * Provides the abstract base and store functionality for configuring 020 * SignalHeadManagers, working with AbstractSignalHeadManagers. 021 * <p> 022 * Typically, a subclass will just implement the load(Element turnouts) class, 023 * relying on implementation here to load the individual turnouts. Note that 024 * these are stored explicitly, so the resolution mechanism doesn't need to see 025 * *Xml classes for each specific SignalHead or AbstractSignalHead subclass at 026 * store time. 027 * <p> 028 * Based on {@link AbstractTurnoutManagerConfigXML} 029 * 030 * @author Bob Jacobsen Copyright: Copyright (c) 2003, 2008 031 */ 032public class AbstractSignalHeadManagerXml extends AbstractNamedBeanManagerConfigXML { 033 034 public AbstractSignalHeadManagerXml() { 035 } 036 037 /** 038 * Default implementation for storing the contents of a SignalHeadManager. 039 * <p> 040 * Unlike most other managers, the individual SignalHead objects are stored 041 * separately via the configuration system so they can have separate type 042 * information. 043 * 044 * @param o Object to store, of type SignalHeadManager 045 * @return Element containing the complete info 046 */ 047 @Override 048 public Element store(Object o) { 049 Element signalheads = new Element("signalheads"); 050 setStoreElementClass(signalheads); 051 SignalHeadManager shm = (SignalHeadManager) o; 052 if (shm != null) { 053 SortedSet<SignalHead> shList = shm.getNamedBeanSet(); 054 // don't return an element if there are no signalheads to include 055 if (shList.isEmpty()) { 056 return null; 057 } 058 for (SignalHead sh : shList) { 059 // store the signalheads 060 String shName = sh.getSystemName(); 061 log.debug("system name is {}", shName); 062 Element e = ConfigXmlManager.elementFromObject(sh); 063 if (e != null) { 064 signalheads.addContent(e); 065 } 066 } 067 } 068 return signalheads; 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 turnouts The top-level element being created 077 */ 078 public void setStoreElementClass(Element turnouts) { 079 turnouts.setAttribute("class", this.getClass().getName()); 080 } 081 082 /** 083 * Create a SignalHeadManager object of the correct class, then register and 084 * fill it. 085 * 086 * @param shared Shared top level Element to unpack. 087 * @param perNode Per-node top level Element to unpack. 088 * @return true if successful 089 */ 090 @Override 091 public boolean load(Element shared, Element perNode) { 092 // create the master object 093 replaceSignalHeadManager(); 094 095 // load individual turnouts 096 loadSignalHeads(shared, perNode); 097 return true; 098 } 099 100 /** 101 * Utility method to load the individual SignalHead objects. If there's no 102 * additional info needed for a specific signal head type, invoke this with 103 * the parent of the set of SignalHead elements. 104 * 105 * @param shared Element containing the SignalHead elements to load. 106 * @param perNode Element containing any per-node information associated 107 * with the shared Element. 108 */ 109 public void loadSignalHeads(Element shared, Element perNode) { 110 InstanceManager.getDefault(SignalHeadManager.class); 111 List<Element> headClassList = shared.getChildren(); 112 log.debug("Found {} signal heads", headClassList.size()); 113 // load the contents 114 boolean result = loadInAdapter(headClassList, null); 115 if (!result) { 116 log.warn("error loading signalheads"); 117 } 118 } 119 120 /** 121 * Replace the current signal head manager, if there is one, with one newly 122 * created during a load operation. This is skipped if they are of the same 123 * absolute type. 124 */ 125 protected void replaceSignalHeadManager() { 126 if (InstanceManager.getDefault(SignalHeadManager.class).getClass().getName() 127 .equals(AbstractSignalHeadManager.class.getName())) { 128 return; 129 } 130 // if old manager exists, remove it from configuration process 131 InstanceManager.getOptionalDefault(SignalHeadManager.class).ifPresent((shm) -> { 132 InstanceManager.getDefault(ConfigureManager.class).deregister(shm); 133 }); 134 135 // register new one with InstanceManager 136 AbstractSignalHeadManager pManager = new AbstractSignalHeadManager(InstanceManager.getDefault(InternalSystemConnectionMemo.class)); 137 InstanceManager.setDefault(SignalHeadManager.class, pManager); 138 // register new one for configuration 139 InstanceManager.getOptionalDefault(ConfigureManager.class).ifPresent((cm) -> { 140 cm.registerConfig(pManager, Manager.SIGNALHEADS); 141 }); 142 } 143 144 @Override 145 public int loadOrder() { 146 return InstanceManager.getDefault(SignalHeadManager.class).getXMLOrder(); 147 } 148 149 private final static Logger log = LoggerFactory.getLogger(AbstractSignalHeadManagerXml.class); 150 151}