001package jmri.jmrix.openlcb; 002 003import java.util.*; 004 005import javax.annotation.Nonnull; 006import jmri.BooleanPropertyDescriptor; 007import jmri.JmriException; 008import jmri.NamedBean; 009import jmri.NamedBeanPropertyDescriptor; 010import jmri.Turnout; 011import jmri.jmrix.can.CanSystemConnectionMemo; 012import jmri.managers.AbstractTurnoutManager; 013 014/** 015 * OpenLCB implementation of a TurnoutManager. 016 * <p> 017 * Turnouts must be manually created. 018 * 019 * @author Bob Jacobsen Copyright (C) 2008, 2010 020 * @since 2.3.1 021 */ 022public class OlcbTurnoutManager extends AbstractTurnoutManager { 023 024 public OlcbTurnoutManager(CanSystemConnectionMemo memo) { 025 super(memo); 026 } 027 028 // Whether we accumulate partially loaded turnouts in pendingTurnouts. 029 private boolean isLoading = false; 030 // Turnouts that are being loaded from XML. 031 private final ArrayList<OlcbTurnout> pendingTurnouts = new ArrayList<>(); 032 033 /** 034 * {@inheritDoc} 035 */ 036 @Override 037 @Nonnull 038 public CanSystemConnectionMemo getMemo() { 039 return (CanSystemConnectionMemo) memo; 040 } 041 042 @Override 043 @Nonnull 044 public List<NamedBeanPropertyDescriptor<?>> getKnownBeanProperties() { 045 List<NamedBeanPropertyDescriptor<?>> l = new ArrayList<>(); 046 l.add(new BooleanPropertyDescriptor(OlcbUtils.PROPERTY_IS_AUTHORITATIVE, OlcbTurnout 047 .DEFAULT_IS_AUTHORITATIVE) { 048 @Override 049 public String getColumnHeaderText() { 050 return Bundle.getMessage("OlcbStateAuthHeader"); 051 } 052 053 @Override 054 public boolean isEditable(NamedBean bean) { 055 return OlcbUtils.isOlcbBean(bean); 056 } 057 }); 058 l.add(new BooleanPropertyDescriptor(OlcbUtils.PROPERTY_LISTEN, OlcbTurnout 059 .DEFAULT_LISTEN) { 060 @Override 061 public String getColumnHeaderText() { 062 return Bundle.getMessage("OlcbStateListenHeader"); 063 } 064 065 @Override 066 public boolean isEditable(NamedBean bean) { 067 return OlcbUtils.isOlcbBean(bean); 068 } 069 }); 070 return l; 071 } 072 073 /** 074 * Internal method to invoke the factory, after all the logic for returning 075 * an existing method has been invoked. 076 * 077 * @return never null 078 * {@inheritDoc} 079 */ 080 @Nonnull 081 @Override 082 protected Turnout createNewTurnout(@Nonnull String systemName, String userName) throws IllegalArgumentException { 083 String addr = systemName.substring(getSystemPrefix().length() + 1); 084 OlcbTurnout t = new OlcbTurnout(getSystemPrefix(), addr, (CanSystemConnectionMemo) memo); 085 t.setUserName(userName); 086 synchronized (pendingTurnouts) { 087 if (isLoading) { 088 pendingTurnouts.add(t); 089 } else { 090 t.finishLoad(); 091 } 092 } 093 return t; 094 } 095 096 /** 097 * This function is invoked before an XML load is started. We defer initialization of the 098 * newly created turnouts until finishLoad because the feedback type might be changing as we 099 * are parsing the XML. 100 */ 101 public void startLoad() { 102 synchronized (pendingTurnouts) { 103 isLoading = true; 104 } 105 } 106 107 /** 108 * This function is invoked after the XML load is complete and all turnouts are instantiated 109 * and their feedback type is read in. We use this hook to finalize the construction of the 110 * OpenLCB objects whose instantiation was deferred until the feedback type was known. 111 */ 112 public void finishLoad() { 113 synchronized (pendingTurnouts) { 114 pendingTurnouts.forEach(OlcbTurnout::finishLoad); 115 pendingTurnouts.clear(); 116 isLoading = false; 117 } 118 } 119 120 @Override 121 public boolean allowMultipleAdditions(@Nonnull String systemName) { 122 return false; 123 } 124 125 @Override 126 public String createSystemName(@Nonnull String curAddress, @Nonnull String prefix) throws JmriException { 127 // don't check for integer; should check for validity here 128 String tmpPrefix = prefix + typeLetter(); 129 String tmpSName = tmpPrefix + curAddress; 130 try { 131 OlcbAddress.validateSystemNameFormat(tmpSName,Locale.getDefault(),tmpPrefix, (CanSystemConnectionMemo) memo); 132 } catch (jmri.NamedBean.BadSystemNameException e) { 133 throw new JmriException(e.getMessage()); 134 } 135 return prefix + typeLetter() + curAddress; 136 } 137 138 @Override 139 @javax.annotation.Nonnull 140 @javax.annotation.CheckReturnValue 141 public String getNextValidSystemName(@Nonnull NamedBean currentBean) throws JmriException { 142 throw new jmri.JmriException("getNextValidSystemName should not have been called"); 143 } 144 145 /** 146 * Validates to OpenLCB 2 part address format. 147 * {@inheritDoc} 148 */ 149 @Override 150 @Nonnull 151 public String validateSystemNameFormat(@Nonnull String name, @Nonnull java.util.Locale locale) 152 throws jmri.NamedBean.BadSystemNameException { 153 return OlcbAddress.validateSystemNameFormat2Part(super.validateSystemNameFormat( 154 name,locale),locale,getSystemNamePrefix(), (CanSystemConnectionMemo) memo); 155 } 156 157 /** 158 * {@inheritDoc} 159 */ 160 @Override 161 public String getEntryToolTip() { 162 return Bundle.getMessage("AddTurnoutEntryToolTip"); 163 } 164 165}