]> git.basschouten.com Git - openhab-addons.git/blob
4877d9f63e942158a1f470b5983d5b5bd2beea06
[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.homematic.internal.communicator.server;
14
15 import java.io.IOException;
16 import java.io.PrintWriter;
17 import java.net.InetSocketAddress;
18
19 import javax.servlet.ServletException;
20 import javax.servlet.http.HttpServletRequest;
21 import javax.servlet.http.HttpServletResponse;
22 import javax.xml.parsers.ParserConfigurationException;
23
24 import org.eclipse.jetty.server.Request;
25 import org.eclipse.jetty.server.Server;
26 import org.eclipse.jetty.server.handler.AbstractHandler;
27 import org.openhab.binding.homematic.internal.common.HomematicConfig;
28 import org.openhab.binding.homematic.internal.communicator.message.RpcRequest;
29 import org.openhab.binding.homematic.internal.communicator.message.XmlRpcRequest;
30 import org.openhab.binding.homematic.internal.communicator.message.XmlRpcResponse;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import org.xml.sax.SAXException;
34
35 /**
36  * Reads a XML-RPC message and handles the method call.
37  *
38  * @author Gerhard Riegler - Initial contribution
39  */
40 public class XmlRpcServer implements RpcServer {
41     private final Logger logger = LoggerFactory.getLogger(XmlRpcServer.class);
42
43     private static final String XML_EMPTY_STRING = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<methodResponse><params><param><value></value></param></params></methodResponse>";
44     private static final String XML_EMPTY_ARRAY = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<methodResponse><params><param><value><array><data></data></array></value></param></params></methodResponse>";
45     private static final String XML_EMPTY_EVENT_LIST = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<methodResponse><params><param><value><array><data><value>event</value></data></array></value></param></params></methodResponse>";
46
47     private Server xmlRpcHTTPD;
48     private HomematicConfig config;
49     private RpcResponseHandler<String> rpcResponseHander;
50     private final ResponseHandler jettyResponseHandler = new ResponseHandler();
51
52     public XmlRpcServer(RpcEventListener listener, HomematicConfig config) {
53         this.config = config;
54         this.rpcResponseHander = new RpcResponseHandler<String>(listener) {
55
56             @Override
57             protected String getEmptyStringResult() {
58                 return XML_EMPTY_STRING;
59             }
60
61             @Override
62             protected String getEmptyEventListResult() {
63                 return XML_EMPTY_EVENT_LIST;
64             }
65
66             @Override
67             protected String getEmptyArrayResult() {
68                 return XML_EMPTY_ARRAY;
69             }
70
71             @Override
72             protected RpcRequest<String> createRpcRequest() {
73                 return new XmlRpcRequest(null, XmlRpcRequest.TYPE.RESPONSE);
74             }
75         };
76     }
77
78     @Override
79     public void start() throws IOException {
80         logger.debug("Initializing XML-RPC server at port {}", config.getXmlCallbackPort());
81
82         InetSocketAddress callbackAddress = new InetSocketAddress(config.getXmlCallbackPort());
83         xmlRpcHTTPD = new Server(callbackAddress);
84         xmlRpcHTTPD.setHandler(jettyResponseHandler);
85
86         try {
87             xmlRpcHTTPD.start();
88             if (logger.isTraceEnabled()) {
89                 xmlRpcHTTPD.dumpStdErr();
90             }
91         } catch (Exception e) {
92             throw new IOException("Jetty start failed", e);
93         }
94     }
95
96     @Override
97     public void shutdown() {
98         if (xmlRpcHTTPD != null) {
99             logger.debug("Stopping XML-RPC server");
100             try {
101                 xmlRpcHTTPD.stop();
102             } catch (Exception ex) {
103                 logger.error("{}", ex.getMessage(), ex);
104             }
105         }
106     }
107
108     /**
109      * Response handler for Jetty implementing a XML-RPC server
110      *
111      * @author Martin Herbst
112      */
113     private class ResponseHandler extends AbstractHandler {
114         @Override
115         public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
116                 throws IOException, ServletException {
117             response.setContentType("text/xml;charset=ISO-8859-1");
118             response.setStatus(HttpServletResponse.SC_OK);
119             final PrintWriter respWriter = response.getWriter();
120             try {
121                 XmlRpcResponse xmlResponse = new XmlRpcResponse(request.getInputStream(), config.getEncoding());
122                 if (logger.isTraceEnabled()) {
123                     logger.trace("Server parsed XmlRpcMessage:\n{}", xmlResponse);
124                 }
125                 final String returnValue = rpcResponseHander.handleMethodCall(xmlResponse.getMethodName(),
126                         xmlResponse.getResponseData());
127                 if (logger.isTraceEnabled()) {
128                     logger.trace("Server XmlRpcResponse:\n{}", returnValue);
129                 }
130                 respWriter.println(returnValue);
131             } catch (SAXException | ParserConfigurationException ex) {
132                 logger.error("{}", ex.getMessage(), ex);
133                 respWriter.println(XML_EMPTY_STRING);
134             }
135             baseRequest.setHandled(true);
136         }
137     }
138 }