001package jmri.jmrix.can.cbus.swing.modules; 002 003import java.util.*; 004 005import javax.annotation.Nonnull; 006 007import jmri.jmrix.can.cbus.node.CbusNode; 008import jmri.jmrix.can.cbus.node.CbusNodeNVTableDataModel; 009import jmri.spi.JmriServiceProviderInterface; 010 011import org.slf4j.Logger; 012import org.slf4j.LoggerFactory; 013 014 015/** 016 * Pane for configuring events in a CBUS module 017 * 018 * Definition of objects to handle configuring a CBUS module. 019 * 020 * Implementing classes <em>must</em> be registered as service providers of this 021 * type to be recognized and usable. 022 * <p> 023 * General design documentation is available on the 024 * <a href="http://jmri.org/help/en/html/doc/Technical/SystemStructure.shtml">Structure of External System Connections page</a>. 025 * 026 * @author Andrew Crosland Copyright (C) 2021 027 * @see java.util.ServiceLoader 028 */ 029public abstract class CbusConfigPaneProvider extends jmri.jmrix.can.swing.CanPanel implements JmriServiceProviderInterface { 030 031 protected CbusConfigPaneProvider() { 032 super(); 033 } 034 035 /** 036 * Get the manufacturer name for the class 037 * 038 * @return the manufacturer 039 */ 040 @Nonnull 041 abstract public String getModuleType(); 042 043 /** 044 * Get descriptive name of NV 045 * 046 * @param index of the NV 047 * @return the name as String. May be empty string if NV description is unknown 048 * or null if index is out of range 049 */ 050 abstract public String getNVNameByIndex(int index); 051 052 protected AbstractEditNVPane _nVarEditFrame = null; 053 054 /** 055 * Get the edit frame instance 056 * @return the edit frame 057 */ 058 abstract public AbstractEditNVPane getEditNVFrameInstance(); 059 060 /** 061 * Create a new edit frame 062 * 063 * @param editFrame the containing frame 064 * @param node the node to be edited 065 * @return the edit frame 066 */ 067 abstract public AbstractEditNVPane getEditNVFrame(CbusNodeNVTableDataModel editFrame, CbusNode node); 068 069 /** 070 * Return string representation of the node 071 * 072 * @return name of object 073 */ 074 @Override 075 final public String toString() { 076 return getModuleType(); 077 } 078 079 /** 080 * Get a module provider from a module name 081 * 082 * @param name of the module 083 * @return the module provider, null if not known 084 */ 085 final static public CbusConfigPaneProvider getProviderByName(String name) { 086 loadInstances(); 087 CbusConfigPaneProvider p = instanceMap.get(name); 088 return p; 089 } 090 091 /** 092 * Get a module provider from a CBUS node 093 * 094 * @param node the node instance 095 * @return the module provider 096 */ 097 final static public CbusConfigPaneProvider getProviderByNode(CbusNode node) { 098 loadInstances(); 099 CbusConfigPaneProvider p = instanceMap.get(node.getName()); 100 if (p != null) { 101 return p; 102 } else if (node.getResyncName() != null) { 103 // Get the saved name during a resync 104 p = instanceMap.get(node.getResyncName()); 105 if (p != null) { 106 return p; 107 } 108 } 109 log.info("node gets unknown provider: {}", node); 110 return new UnknownPaneProvider(); 111 } 112 113 /** 114 * Get all available instances as an {@link Collections#unmodifiableMap} 115 * between the (localized) name and the pane. Note that this is a SortedMap in 116 * name order. 117 * 118 * @return all instance map sorted in name order. 119 */ 120 final static public Map<String, CbusConfigPaneProvider> getInstancesMap() { 121 loadInstances(); 122 return Collections.unmodifiableMap(instanceMap); 123 } 124 125 /** 126 * Get all available instances as an {@link Collections#unmodifiableCollection} 127 * between the (localized) name and the pane. 128 * 129 * @return unmodifiable collection. 130 */ 131 final static public Collection<CbusConfigPaneProvider> getInstancesCollection() { 132 loadInstances(); 133 return Collections.unmodifiableCollection(instanceMap.values()); 134 } 135 136 /** 137 * Load all the available instances. Note this only runs 138 * once; there's no reloading once the program is running. 139 */ 140 final static public void loadInstances() { 141 if (instanceMap != null) return; 142 143 instanceMap = new TreeMap<>(); // sorted map, in string order on key 144 145 java.util.ServiceLoader.load(CbusConfigPaneProvider.class).forEach((pane) -> { 146 if (!instanceMap.containsKey(pane.getModuleType())) { 147 instanceMap.put(pane.getModuleType(), pane); 148 } 149 }); 150 151 } 152 153 static volatile Map<String, CbusConfigPaneProvider> instanceMap = null; 154 155 private final static Logger log = LoggerFactory.getLogger(CbusConfigPaneProvider.class); 156}