001package jmri.jmrix.roco.z21;
002
003import java.net.DatagramSocket;
004import java.util.ResourceBundle;
005import jmri.jmrix.ConnectionStatus;
006import org.slf4j.Logger;
007import org.slf4j.LoggerFactory;
008
009/**
010 * Adapter representing a Z21 communication port.
011 * <p>
012 * Note: This connection uses UDP for communication.
013 *
014 * @author Bob Jacobsen Copyright (C) 2001, 2008
015 * @author Paul Bender Copyright (C) 2004,2010,2011,2014
016 */
017public class Z21Adapter extends jmri.jmrix.AbstractNetworkPortController {
018
019    protected static ResourceBundle rb =  ResourceBundle.getBundle("jmri.jmrix.roco.z21.z21AdapterConfigurationBundle");
020    protected static int COMMUNICATION_UDP_PORT = java.lang.Integer.parseInt(rb.getString("z21UDPPort1"));
021    protected static String DEFAULT_IP_ADDRESS = rb.getString("defaultZ21IPAddress");
022
023    private DatagramSocket socket = null;
024
025    public Z21Adapter() {
026        super(new Z21SystemConnectionMemo());
027        setHostName(DEFAULT_IP_ADDRESS);
028        setPort(COMMUNICATION_UDP_PORT);
029        allowConnectionRecovery = true; // all classes derived from this class
030        // can recover from a connection failure
031
032    }
033
034    /**
035     * Configure all of the other jmrix widgets needed to work with this adapter
036     */
037    @Override
038    public void configure() {
039        if (log.isDebugEnabled()) {
040            log.debug("configure called");
041        }
042        // connect to a packetizing traffic controller
043        Z21TrafficController packets = new Z21TrafficController();
044        packets.connectPort(this);
045
046        // start operation
047        this.getSystemConnectionMemo().setTrafficController(packets);
048        this.getSystemConnectionMemo().configureManagers();
049    }
050
051    @Override
052    public void connect() throws java.io.IOException {
053        opened = false;
054        if (getHostAddress() == null || m_port == 0) {
055            log.error("No host name or port set : {}:{}", m_HostName, m_port);
056            return;
057        }
058        try {
059            socket = new DatagramSocket();
060            opened = true;
061        } catch (java.net.SocketException se) {
062            log.error("Socket Exception creating connection.");
063            if (m_port != 0) {
064                ConnectionStatus.instance().setConnectionState(
065                        this.getSystemConnectionMemo().getUserName(),
066                        m_HostName + ":" + m_port, ConnectionStatus.CONNECTION_DOWN);
067            } else {
068                ConnectionStatus.instance().setConnectionState(
069                        this.getSystemConnectionMemo().getUserName(),
070                        m_HostName, ConnectionStatus.CONNECTION_DOWN);
071            }
072            throw (se);
073        }
074        if (opened && m_port != 0) {
075            ConnectionStatus.instance().setConnectionState(
076                    this.getSystemConnectionMemo().getUserName(),
077                    m_HostName + ":" + m_port, ConnectionStatus.CONNECTION_UP);
078        } else if (opened) {
079            ConnectionStatus.instance().setConnectionState(
080                    this.getSystemConnectionMemo().getUserName(),
081                    m_HostName, ConnectionStatus.CONNECTION_UP);
082        }
083
084    }
085
086    /**
087     * @return the DatagramSocket of this connection.  Returns null
088     *         if not connected.
089     */
090    public DatagramSocket getSocket() {
091        return socket;
092    }
093
094    /**
095     * Check that this object is ready to operate. This is a question of
096     * configuration, not transient hardware status.
097     */
098    @Override
099    public boolean status() {
100        return opened;
101    }
102
103    @Override
104    public Z21SystemConnectionMemo getSystemConnectionMemo() {
105        return (Z21SystemConnectionMemo) super.getSystemConnectionMemo();
106    }
107
108    /**
109     * Customizable method to deal with resetting a system connection after a
110     * successful recovery of a connection.
111     */
112    @Override
113    protected void resetupConnection() {
114        // UDP connection is re-established for each message.
115    }
116
117    @Override
118    public void dispose(){
119       super.dispose();
120       if (opened) {
121          socket.close();
122       }
123       opened = false;
124       allowConnectionRecovery = false; // disposing of the object should 
125                                        // result in not allowing reconnection.
126    }
127
128    private static final Logger log = LoggerFactory.getLogger(Z21Adapter.class);
129
130}