001package jmri.jmrit.logixng.implementation; 002 003import java.util.ArrayList; 004import java.util.List; 005import java.util.Map; 006import java.util.HashMap; 007import java.util.ServiceLoader; 008 009import javax.annotation.Nonnull; 010 011import jmri.InstanceManager; 012import jmri.InvokeOnGuiThread; 013import jmri.jmrit.logixng.*; 014import jmri.util.LoggingUtil; 015import jmri.util.ThreadingUtil; 016 017/** 018 * Class providing the basic logic of the DigitalActionManager interface. 019 * 020 * @author Dave Duchamp Copyright (C) 2007 021 * @author Daniel Bergqvist Copyright (C) 2018 022 */ 023public class DefaultDigitalActionManager extends AbstractBaseManager<MaleDigitalActionSocket> 024 implements DigitalActionManager { 025 026 private final Map<Category, List<Class<? extends Base>>> actionClassList = new HashMap<>(); 027 private MaleSocket _lastRegisteredBean; 028 029 030 public DefaultDigitalActionManager() { 031 InstanceManager.getDefault(LogixNG_Manager.class).registerManager(this); 032 033 for (DigitalActionFactory actionFactory : ServiceLoader.load(DigitalActionFactory.class)) { 034 actionFactory.init(); 035 } 036 037 for (Category category : Category.values()) { 038 actionClassList.put(category, new ArrayList<>()); 039 } 040 041 for (DigitalActionFactory actionFactory : ServiceLoader.load(DigitalActionFactory.class)) { 042 actionFactory.getActionClasses().forEach((entry) -> { 043// System.out.format("Add action: %s, %s%n", entry.getKey().name(), entry.getValue().getName()); 044 actionClassList.get(entry.getKey()).add(entry.getValue()); 045 }); 046 } 047 048 for (MaleDigitalActionSocketFactory maleSocketFactory : ServiceLoader.load(MaleDigitalActionSocketFactory.class)) { 049 _maleSocketFactories.add(maleSocketFactory); 050 } 051 } 052 053 /** {@inheritDoc} */ 054 @Override 055 public Class<? extends MaleSocket> getMaleSocketClass() { 056 return DefaultMaleDigitalActionSocket.class; 057 } 058 059 protected MaleDigitalActionSocket createMaleActionSocket(DigitalActionBean action) { 060 MaleDigitalActionSocket socket = new DefaultMaleDigitalActionSocket(this, action); 061 action.setParent(socket); 062 return socket; 063 } 064 065 /** {@inheritDoc} */ 066 @Override 067 public MaleSocket getLastRegisteredMaleSocket() { 068 return _lastRegisteredBean; 069 } 070 071 /** {@inheritDoc} */ 072 @Override 073 public MaleDigitalActionSocket registerBean(MaleDigitalActionSocket maleSocket) { 074 MaleDigitalActionSocket bean = super.registerBean(maleSocket); 075 _lastRegisteredBean = maleSocket; 076 return bean; 077 } 078 079 /** 080 * Remember a NamedBean Object created outside the manager. 081 * This method creates a MaleDigitalActionSocket for the action. 082 * 083 * @param action the bean 084 */ 085 @Override 086 public MaleDigitalActionSocket registerAction(@Nonnull DigitalActionBean action) 087 throws IllegalArgumentException { 088 089 if (action instanceof MaleDigitalActionSocket) { 090 throw new IllegalArgumentException("registerAction() cannot register a MaleDigitalActionSocket. Use the method register() instead."); 091 } 092 093 // Check if system name is valid 094 if (this.validSystemNameFormat(action.getSystemName()) != NameValidity.VALID) { 095 log.warn("SystemName {} is not in the correct format", action.getSystemName() ); 096 throw new IllegalArgumentException(String.format("System name is invalid: %s", action.getSystemName())); 097 } 098 099 // Keep track of the last created auto system name 100 updateAutoNumber(action.getSystemName()); 101 102 // save in the maps 103 MaleDigitalActionSocket maleSocket = createMaleActionSocket(action); 104 return registerBean(maleSocket); 105 } 106 107 @Override 108 public int getXMLOrder() { 109 return LOGIXNG_DIGITAL_ACTIONS; 110 } 111 112 @Override 113 public char typeLetter() { 114 return 'Q'; 115 } 116 117 @Override 118 public FemaleDigitalActionSocket createFemaleSocket( 119 Base parent, FemaleSocketListener listener, String socketName) { 120 return new DefaultFemaleDigitalActionSocket(parent, listener, socketName); 121 } 122 123 @Override 124 public Map<Category, List<Class<? extends Base>>> getActionClasses() { 125 return actionClassList; 126 } 127 128 /** {@inheritDoc} */ 129 @Override 130 public String getBeanTypeHandled(boolean plural) { 131 return Bundle.getMessage(plural ? "BeanNameDigitalActions" : "BeanNameDigitalAction"); 132 } 133 134 /** {@inheritDoc} */ 135 @Override 136 public void deleteDigitalAction(MaleDigitalActionSocket x) { 137 // delete the MaleDigitalActionSocket 138 deregister(x); 139 x.dispose(); 140 } 141 142 static volatile DefaultDigitalActionManager _instance = null; 143 144 @InvokeOnGuiThread // this method is not thread safe 145 static public DefaultDigitalActionManager instance() { 146 if (!ThreadingUtil.isGUIThread()) { 147 LoggingUtil.warnOnce(log, "instance() called on wrong thread"); 148 } 149 150 if (_instance == null) { 151 _instance = new DefaultDigitalActionManager(); 152 } 153 return (_instance); 154 } 155 156 @Override 157 public Class<MaleDigitalActionSocket> getNamedBeanClass() { 158 return MaleDigitalActionSocket.class; 159 } 160 161 @Override 162 protected MaleDigitalActionSocket castBean(MaleSocket maleSocket) { 163 return (MaleDigitalActionSocket)maleSocket; 164 } 165 166 167 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultDigitalActionManager.class); 168 169}