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 log.trace("{} doesn't exist, make with {}", name, manager); 050 if (manager != null) { 051 return makeBean(manager, name, null); 052 } 053 log.debug("provideNamedBean did not find manager for name {}, defer to default", name); // NOI18N 054 return makeBean(getDefaultManager(), getDefaultManager().makeSystemName(name), null); 055 } 056 057 /** 058 * Return an instance with the specified user or system name. 059 * <p> 060 * Lookup by UserName, then provide by System Name. 061 * <p> 062 * Note that 063 * two calls with the same arguments will get the same instance; there is 064 * i.e. only one Sensor object representing a given physical sensor and 065 * therefore only one with a specific system or user name. 066 * <p> 067 * This will always return a valid object reference for a valid request; a 068 * new object will be created if necessary. In that case: 069 * <ul> 070 * <li>If a null reference is given for user name, no user name will be 071 * associated with the NamedBean object created; a valid system name must be 072 * provided 073 * <li>If both names are provided, the system name defines the hardware 074 * access of the desired turnout, and the user address is associated with 075 * it. 076 * <li>If a matching UserName is located, that will be returned. 077 * <li>Else If a matching SystemName is located, that will be returned. 078 * <li>Else A New Bean will be created with the given System Name. 079 * The UserName will be added to the New Bean if no existing. 080 * </ul> 081 * Note that it is possible to make an inconsistent request if both 082 * addresses are provided, but the given values are associated with 083 * different objects. This is a problem, and we don't have a good solution 084 * except to issue warnings. This will mostly happen if you're creating 085 * NamedBean when you should be looking them up. 086 * <p> 087 * If the System Name contains the start of a specified Manager, that will be used, 088 * else the default manager will be used. 089 * @see #getManager(java.lang.String) 090 * 091 * @param systemName the system name 092 * @param userName the user name 093 * @return requested NamedBean object (never null) 094 */ 095 @Nonnull 096 public E newNamedBean(@Nonnull String systemName, String userName) throws IllegalArgumentException { 097 // make sure internal present 098 initInternal(); 099 100 // if the systemName is specified, find that system 101 Manager<E> m = getManager(systemName); 102 if (m != null) { 103 return makeBean(m, systemName, userName); 104 } 105 106 // did not find a manager, allow it to default to the primary 107 log.debug("Did not find manager for system name {}, delegate to primary", systemName); // NOI18N 108 return makeBean(getDefaultManager(), systemName, userName); 109 } 110 111 /** 112 * Defer creation of the proper type to the subclass. 113 * 114 * @param manager the manager to invoke 115 * @param systemName the system name 116 * @param userName the user name 117 * @throws IllegalArgumentException if unable to make. 118 * @return a bean 119 */ 120 @Nonnull 121 abstract protected E makeBean(Manager<E> manager,@Nonnull String systemName, String userName) throws IllegalArgumentException; 122 123 // initialize logging 124 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractProvidingProxyManager.class); 125 126}