2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.jeelink.internal.connection;
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;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
28 * Reads lines from TCP port and propagates them to registered InputListeners.
30 * @author Volker Bier - Initial contribution
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]+)");
35 private final Logger logger = LoggerFactory.getLogger(JeeLinkTcpConnection.class);
37 private ScheduledExecutorService scheduler;
38 private Reader reader;
39 private Socket socket;
41 public JeeLinkTcpConnection(String port, ScheduledExecutorService scheduler, ConnectionListener l) {
43 this.scheduler = scheduler;
47 public synchronized void closeConnection() {
49 logger.debug("Closing TCP connection to port {}...", port);
52 closeSocketSilently();
59 public synchronized void openConnection() {
61 logger.debug("TCP connection to port {} is already open!", port);
65 Matcher ipm = IP_PORT_PATTERN.matcher(port);
67 notifyAbort("Invalid TCP port specification: " + port);
70 String hostName = ipm.group(1);
71 int portNumber = Integer.parseInt(ipm.group(2));
73 logger.debug("Opening TCP connection to host {} port {}...", hostName, portNumber);
75 logger.debug("Creating TCP socket to {}...", port);
76 socket = new Socket(hostName, portNumber);
77 socket.setKeepAlive(true);
78 logger.debug("TCP socket created.");
80 reader = new Reader(socket);
81 scheduler.execute(reader);
84 } catch (IOException ex) {
86 closeSocketSilently();
89 notifyAbort(ex.getMessage());
93 private void closeSocketSilently() {
96 } catch (IOException e) {
97 logger.debug("Failed to close socket.", e);
102 public OutputStream getInitStream() throws IOException {
103 return socket == null ? null : socket.getOutputStream();
106 private class Reader implements Runnable {
107 private Socket socket;
108 private BufferedReader inputReader;
109 private volatile boolean isRunning = true;
111 private Reader(Socket socket) throws IOException {
112 this.socket = socket;
113 inputReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
119 logger.debug("Reader for TCP port {} starting...", port);
122 line = inputReader.readLine();
125 throw new IOException("Got EOF on port " + port);
130 } catch (IOException ex) {
133 notifyAbort(ex.getMessage());
136 logger.debug("Reader for TCP port {} finished...", port);
140 public void close() {
141 logger.debug("Shutting down reader for TCP port {}...", port);
146 } catch (IOException ex) {
147 logger.debug("Failed to close TCP port {}!", port, ex);