/**
* Copyright (c) 2010-2016 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.binding.homematic.internal.communicator.server;
import java.io.EOFException;
import java.io.IOException;
import java.net.Socket;
import java.util.Map;
import org.openhab.binding.homematic.internal.binrpc.BinRpcResponse;
import org.openhab.binding.homematic.internal.communicator.HomematicCallbackReceiver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Reads a BIN-RPC message from the socket and handles the method call.
*
* @author Gerhard Riegler
* @since 1.5.0
*/
public class BinRpcCallbackHandler implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(BinRpcCallbackHandler.class);
private final static boolean TRACE_ENABLED = logger.isTraceEnabled();
private static final byte BIN_EMPTY_STRING[] = { 'B', 'i', 'n', 1, 0, 0, 0, 8, 0, 0, 0, 3, 0, 0, 0, 0 };
private static final byte BIN_EMPTY_ARRAY[] = { 'B', 'i', 'n', 1, 0, 0, 0, 8, 0, 0, 1, 0, 0, 0, 0, 0 };
private static final byte BIN_EMPTY_EVENT_LIST[] = { 'B', 'i', 'n', 1, 0, 0, 0, 21, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,
3, 0, 0, 0, 5, 'e', 'v', 'e', 'n', 't' };
private static final byte BIN_LIST_METHODS_RESPONSE[] = { 'B', 'i', 'n', 1, 0, 0, 0, 45, 0, 0, 1, 0, 0, 0, 0, 2, 0,
0, 0, 3, 0, 0, 0, 16, 's', 'y', 's', 't', 'e', 'm', '.', 'm', 'u', 'l', 't', 'i', 'c', 'a', 'l', 'l', 0, 0,
0, 3, 0, 0, 0, 5, 'e', 'v', 'e', 'n', 't' };
private Socket socket;
private HomematicCallbackReceiver callbackReceiver;
public BinRpcCallbackHandler(Socket socket, HomematicCallbackReceiver callbackReceiver) {
this.socket = socket;
this.callbackReceiver = callbackReceiver;
}
/**
* Reads the event from the Homematic server and handles the method call.
*/
@Override
public void run() {
try {
BinRpcResponse response = new BinRpcResponse(socket.getInputStream(), true);
if (TRACE_ENABLED) {
logger.trace("Event BinRpcResponse: {}", response.toString());
}
byte[] returnValue = handleMethodCall(response.getMethodName(), response.getResponseData());
if (returnValue != null) {
socket.getOutputStream().write(returnValue);
}
} catch (EOFException eof) {
// ignore
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
try {
socket.close();
} catch (IOException ex) {
// ignore
}
}
}
/**
* Returns a valid result of the method called by the Homematic server.
*/
private byte[] handleMethodCall(String methodName, Object[] responseData) throws Exception {
if ("event".equals(methodName)) {
handleEvent(responseData);
return BIN_EMPTY_STRING;
} else if ("listDevices".equals(methodName) || "deleteDevices".equals(methodName)
|| "updateDevice".equals(methodName)) {
return BIN_EMPTY_ARRAY;
} else if ("newDevices".equals(methodName)) {
callbackReceiver.newDevices(null, null);
return BIN_EMPTY_ARRAY;
} else if ("system.listMethods".equals(methodName)) {
return BIN_LIST_METHODS_RESPONSE;
} else if ("system.multicall".equals(methodName)) {
for (Object o : (Object[]) responseData[0]) {
Map<?, ?> call = (Map<?, ?>) o;
String method = call.get("methodName").toString();
Object[] data = (Object[]) call.get("params");
handleMethodCall(method, data);
}
return BIN_EMPTY_EVENT_LIST;
} else {
logger.warn("Unknown method called by Homematic server: " + methodName);
return BIN_EMPTY_EVENT_LIST;
}
}
/**
* Populates the extracted event to the callbackReceiver.
*/
private void handleEvent(Object[] parms) {
String interfaceId = parms[0].toString();
String address = parms[1].toString();
String attribute = parms[2].toString();
Object value = parms[3];
callbackReceiver.event(interfaceId, address, attribute, value);
}
}