]> git.basschouten.com Git - openhab-addons.git/blob
7fe8d95611b281945eb37463dba806742386cae9
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.jeelink.internal.connection;
14
15 import java.io.BufferedReader;
16 import java.io.IOException;
17 import java.io.InputStreamReader;
18 import java.io.OutputStream;
19 import java.net.Socket;
20 import java.util.concurrent.ScheduledExecutorService;
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * Reads lines from TCP port and propagates them to registered InputListeners.
29  *
30  * @author Volker Bier - Initial contribution
31  */
32 public class JeeLinkTcpConnection extends AbstractJeeLinkConnection {
33     private static final Pattern IP_PORT_PATTERN = Pattern.compile("([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+):([0-9]+)");
34
35     private final Logger logger = LoggerFactory.getLogger(JeeLinkTcpConnection.class);
36
37     private ScheduledExecutorService scheduler;
38     private Reader reader;
39     private Socket socket;
40
41     public JeeLinkTcpConnection(String port, ScheduledExecutorService scheduler, ConnectionListener l) {
42         super(port, l);
43         this.scheduler = scheduler;
44     }
45
46     @Override
47     public synchronized void closeConnection() {
48         if (reader != null) {
49             logger.debug("Closing TCP connection to port {}...", port);
50             reader.close();
51             reader = null;
52             closeSocketSilently();
53             socket = null;
54             notifyClosed();
55         }
56     }
57
58     @Override
59     public synchronized void openConnection() {
60         if (reader != null) {
61             logger.debug("TCP connection to port {} is already open!", port);
62             return;
63         }
64
65         Matcher ipm = IP_PORT_PATTERN.matcher(port);
66         if (!ipm.matches()) {
67             notifyAbort("Invalid TCP port specification: " + port);
68         }
69
70         String hostName = ipm.group(1);
71         int portNumber = Integer.parseInt(ipm.group(2));
72
73         logger.debug("Opening TCP connection to host {} port {}...", hostName, portNumber);
74         try {
75             logger.debug("Creating TCP socket to {}...", port);
76             socket = new Socket(hostName, portNumber);
77             socket.setKeepAlive(true);
78             logger.debug("TCP socket created.");
79
80             reader = new Reader(socket);
81             scheduler.execute(reader);
82
83             notifyOpen();
84         } catch (IOException ex) {
85             if (socket != null) {
86                 closeSocketSilently();
87             }
88
89             notifyAbort(ex.getMessage());
90         }
91     }
92
93     private void closeSocketSilently() {
94         try {
95             socket.close();
96         } catch (IOException e) {
97             logger.debug("Failed to close socket.", e);
98         }
99     }
100
101     @Override
102     public OutputStream getInitStream() throws IOException {
103         return socket == null ? null : socket.getOutputStream();
104     }
105
106     private class Reader implements Runnable {
107         private Socket socket;
108         private BufferedReader inputReader;
109         private volatile boolean isRunning = true;
110
111         private Reader(Socket socket) throws IOException {
112             this.socket = socket;
113             inputReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
114         }
115
116         @Override
117         public void run() {
118             String line;
119             logger.debug("Reader for TCP port {} starting...", port);
120             try {
121                 while (isRunning) {
122                     line = inputReader.readLine();
123
124                     if (line == null) {
125                         throw new IOException("Got EOF on port " + port);
126                     }
127
128                     propagateLine(line);
129                 }
130             } catch (IOException ex) {
131                 if (isRunning) {
132                     closeConnection();
133                     notifyAbort(ex.getMessage());
134                 }
135             } finally {
136                 logger.debug("Reader for TCP port {} finished...", port);
137             }
138         }
139
140         public void close() {
141             logger.debug("Shutting down reader for TCP port {}...", port);
142             try {
143                 isRunning = false;
144                 socket.close();
145                 inputReader.close();
146             } catch (IOException ex) {
147                 logger.debug("Failed to close TCP port {}!", port, ex);
148             }
149         }
150     }
151 }