180 lines
6.2 KiB
Java
180 lines
6.2 KiB
Java
/*
|
|
* Copyright 2016 Martijn Brekhof. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package org.xbmc.kore.testutils.tcpserver.handlers;
|
|
|
|
import com.fasterxml.jackson.core.JsonParser;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
|
|
import org.xbmc.kore.testutils.tcpserver.MockTcpServer;
|
|
import org.xbmc.kore.testutils.tcpserver.handlers.jsonrpc.JsonResponse;
|
|
import org.xbmc.kore.utils.LogUtils;
|
|
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.concurrent.TimeoutException;
|
|
|
|
import static org.xbmc.kore.jsonrpc.ApiMethod.ID_NODE;
|
|
import static org.xbmc.kore.jsonrpc.ApiMethod.METHOD_NODE;
|
|
|
|
public class JSONConnectionHandlerManager implements MockTcpServer.TcpServerConnectionHandler {
|
|
public static final String TAG = LogUtils.makeLogTag(JSONConnectionHandlerManager.class);
|
|
|
|
private HashMap<String, ConnectionHandler> handlersByType = new HashMap<>();
|
|
private HashSet<ConnectionHandler> handlers = new HashSet<>();
|
|
private StringBuffer buffer = new StringBuffer();
|
|
private int amountOfOpenBrackets = 0;
|
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
|
|
|
private int responseCount;
|
|
|
|
private HashMap<String, ArrayList<JsonResponse>> clientResponses = new HashMap<>();
|
|
|
|
public interface ConnectionHandler {
|
|
/**
|
|
* Used to determine which methods the handler implements
|
|
* @return list of JSON method names
|
|
*/
|
|
String[] getType();
|
|
|
|
/**
|
|
* Used to get the response from a handler implementing the requested
|
|
* method.
|
|
* @param method requested method
|
|
* @param jsonRequest json node containing the original request
|
|
* @return {@link JsonResponse} that should be sent to the client
|
|
*/
|
|
ArrayList<JsonResponse> getResponse(String method, ObjectNode jsonRequest);
|
|
|
|
/**
|
|
* Used to get any notifications from the handler.
|
|
* @return {@link JsonResponse} that should be sent to the client or null if there are no notifications
|
|
*/
|
|
ArrayList<JsonResponse> getNotifications();
|
|
|
|
/**
|
|
* Should set the state of the handler to its initial state
|
|
*/
|
|
void reset();
|
|
}
|
|
|
|
public void addHandler(ConnectionHandler handler) throws Exception {
|
|
for(String type : handler.getType()) {
|
|
handlersByType.put(type, handler);
|
|
}
|
|
handlers.add(handler);
|
|
}
|
|
|
|
@Override
|
|
public void processInput(char c) {
|
|
buffer.append(c);
|
|
if ( c == '{' ) {
|
|
amountOfOpenBrackets++;
|
|
} else if ( c == '}' ) {
|
|
amountOfOpenBrackets--;
|
|
}
|
|
|
|
if ( amountOfOpenBrackets == 0 ) {
|
|
String input = buffer.toString();
|
|
buffer = new StringBuffer();
|
|
processJSONInput(input);
|
|
}
|
|
}
|
|
|
|
private void processJSONInput(String input) {
|
|
try {
|
|
JsonParser parser = objectMapper.getFactory().createParser(input);
|
|
ObjectNode jsonRequest = objectMapper.readTree(parser);
|
|
|
|
int methodId = jsonRequest.get(ID_NODE).asInt();
|
|
String method = jsonRequest.get(METHOD_NODE).asText();
|
|
ConnectionHandler connectionHandler = handlersByType.get(method);
|
|
if ( connectionHandler != null ) {
|
|
ArrayList<JsonResponse> responses = connectionHandler.getResponse(method, jsonRequest);
|
|
if (responses != null) {
|
|
addResponse(methodId, responses);
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
LogUtils.LOGE(getClass().getSimpleName(), e.getMessage());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String getResponse() {
|
|
StringBuffer stringBuffer = new StringBuffer();
|
|
|
|
synchronized (clientResponses) {
|
|
//Handle responses
|
|
Collection<ArrayList<JsonResponse>> jsonResponses = clientResponses.values();
|
|
for (ArrayList<JsonResponse> arrayList : jsonResponses) {
|
|
for (JsonResponse response : arrayList) {
|
|
stringBuffer.append(response.toJsonString() + "\n");
|
|
}
|
|
}
|
|
clientResponses.clear();
|
|
}
|
|
|
|
//Handle notifications
|
|
for(ConnectionHandler handler : handlers) {
|
|
ArrayList<JsonResponse> jsonNotifications = handler.getNotifications();
|
|
if (jsonNotifications != null) {
|
|
for (JsonResponse jsonResponse : jsonNotifications) {
|
|
stringBuffer.append(jsonResponse.toJsonString() +"\n");
|
|
}
|
|
}
|
|
}
|
|
responseCount++;
|
|
if (stringBuffer.length() > 0) {
|
|
return stringBuffer.toString();
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Waits until at least one response has been processed before returning
|
|
*/
|
|
public void waitForNextResponse(long timeOutMillis) throws TimeoutException {
|
|
responseCount = 0;
|
|
while ((responseCount < 2) && (timeOutMillis > 0)) {
|
|
try {
|
|
Thread.sleep(500);
|
|
timeOutMillis -= 500;
|
|
} catch (InterruptedException e) {
|
|
|
|
}
|
|
}
|
|
if (timeOutMillis < 0)
|
|
throw new TimeoutException();
|
|
}
|
|
|
|
private void addResponse(int id, ArrayList<JsonResponse> jsonResponses) {
|
|
ArrayList<JsonResponse> responses = clientResponses.get(String.valueOf(id));
|
|
if (responses == null) {
|
|
responses = new ArrayList<>();
|
|
synchronized (clientResponses) {
|
|
clientResponses.put(String.valueOf(id), responses);
|
|
}
|
|
}
|
|
responses.addAll(jsonResponses);
|
|
}
|
|
}
|