001package jmri.managers; 002 003import javax.annotation.Nonnull; 004 005import jmri.*; 006 007/** 008 * Implementation of a Manager that can serves as a proxy for multiple 009 * system-specific implementations. 010 * <p> 011 * Automatically includes an Internal system, which need not be separately added 012 * any more. 013 * <p> 014 * Encapsulates access to the "Primary" manager, used by default, which is the 015 * first one provided. 016 * <p> 017 * Internally, this is done by using an ordered list of all non-Internal 018 * managers, plus a separate reference to the internal manager and default 019 * manager. 020 * 021 * @param <E> the supported type of NamedBean 022 * @author Bob Jacobsen Copyright (C) 2003, 2010, 2018 023 * @author Daniel Bergqvist Copyright (C) 2020 024 */ 025abstract public class AbstractProvidingProxyManager<E extends NamedBean> extends AbstractProxyManager<E> implements ProvidingManager<E> { 026 027 /** 028 * Locate via user name, then system name if needed. If that fails, create a 029 * new NamedBean: If the name is a valid system name, it will be used for 030 * the new NamedBean. Otherwise, the makeSystemName method will attempt to 031 * turn it into a valid system name. Subclasses use this to create provider methods such as 032 * getSensor or getTurnout via casts. 033 * 034 * @param name the user name or system name of the bean 035 * @return an existing or new NamedBean 036 * @throws IllegalArgumentException if name is not usable in a bean 037 */ 038 @Nonnull 039 protected E provideNamedBean(String name) throws IllegalArgumentException { 040 // make sure internal present 041 initInternal(); 042 043 E t = getNamedBean(name); 044 if (t != null) { 045 return t; 046 } 047 // Doesn't exist. If the systemName was specified, find that system 048 Manager<E> manager = getManager(name); 049 if (manager != null) { 050 return makeBean(manager, name, null); 051 } 052 log.debug("provideNamedBean did not find manager for name {}, defer to default", name); // NOI18N 053 return makeBean(getDefaultManager(), getDefaultManager().makeSystemName(name), null); 054 } 055 056 /** 057 * Return an instance with the specified user or system name. 058 * <p> 059 * Lookup by UserName, then provide by System Name. 060 * <p> 061 * Note that 062 * two calls with the same arguments will get the same instance; there is 063 * i.e. only one Sensor object representing a given physical sensor and 064 * therefore only one with a specific system or user name. 065 * <p> 066 * This will always return a valid object reference for a valid request; a 067 * new object will be created if necessary. In that case: 068 * <ul> 069 * <li>If a null reference is given for user name, no user name will be 070 * associated with the NamedBean object created; a valid system name must be 071 * provided 072 * <li>If both names are provided, the system name defines the hardware 073 * access of the desired turnout, and the user address is associated with 074 * it. 075 * <li>If a matching UserName is located, that will be returned. 076 * <li>Else If a matching SystemName is located, that will be returned. 077 * <li>Else A New Bean will be created with the given System Name. 078 * The UserName will be added to the New Bean if no existing. 079 * </ul> 080 * Note that it is possible to make an inconsistent request if both 081 * addresses are provided, but the given values are associated with 082 * different objects. This is a problem, and we don't have a good solution 083 * except to issue warnings. This will mostly happen if you're creating 084 * NamedBean when you should be looking them up. 085 * <p> 086 * If the System Name contains the start of a specified Manager, that will be used, 087 * else the default manager will be used. 088 * @see #getManager(java.lang.String) 089 * 090 * @param systemName the system name 091 * @param userName the user name 092 * @return requested NamedBean object (never null) 093 */ 094 @Nonnull 095 public E newNamedBean(@Nonnull String systemName, String userName) throws IllegalArgumentException { 096 // make sure internal present 097 initInternal(); 098 099 // if the systemName is specified, find that system 100 Manager<E> m = getManager(systemName); 101 if (m != null) { 102 return makeBean(m, systemName, userName); 103 } 104 105 // did not find a manager, allow it to default to the primary 106 log.debug("Did not find manager for system name {}, delegate to primary", systemName); // NOI18N 107 return makeBean(getDefaultManager(), systemName, userName); 108 } 109 110 /** 111 * Defer creation of the proper type to the subclass. 112 * 113 * @param manager the manager to invoke 114 * @param systemName the system name 115 * @param userName the user name 116 * @throws IllegalArgumentException if unable to make. 117 * @return a bean 118 */ 119 @Nonnull 120 abstract protected E makeBean(Manager<E> manager,@Nonnull String systemName, String userName) throws IllegalArgumentException; 121 122 // initialize logging 123 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractProvidingProxyManager.class); 124 125}