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