/*
* (C) Copyright 2013 Kurento (http://kurento.org/)
*
* 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.kurento.jsonrpc.internal;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.kurento.jsonrpc.DefaultJsonRpcHandler;
import org.kurento.jsonrpc.JsonRpcException;
import org.kurento.jsonrpc.JsonRpcHandler;
import org.kurento.jsonrpc.Session;
import org.kurento.jsonrpc.internal.client.TransactionImpl;
import org.kurento.jsonrpc.internal.client.TransactionImpl.ResponseSender;
import org.kurento.jsonrpc.message.MessageUtils;
import org.kurento.jsonrpc.message.Request;
import org.kurento.jsonrpc.message.Response;
import org.kurento.jsonrpc.message.ResponseError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonElement;
public class JsonRpcHandlerManager {
private static final Logger log = LoggerFactory.getLogger(JsonRpcHandlerManager.class);
private JsonRpcHandler<?> handler;
public JsonRpcHandlerManager(JsonRpcHandler<?> handler) {
this.handler = handler;
}
public JsonRpcHandlerManager() {
}
/**
* Sets the handler. This method will also set the handlerClass, based on the {@link #getClass()}
* method from the handler passed as parameter
*
* @param handler
*/
public void setJsonRpcHandler(JsonRpcHandler<?> handler) {
this.handler = handler;
}
public void afterConnectionClosed(Session session, String reason) {
if (handler != null) {
try {
handler.afterConnectionClosed(session, reason);
} catch (Exception e) {
try {
handler.handleUncaughtException(session, e);
} catch (Exception e2) {
log.error("Exception while executing handleUncaughtException", e2);
}
}
}
}
public void afterConnectionEstablished(Session session) {
try {
if (handler != null) {
handler.afterConnectionEstablished(session);
}
} catch (Exception e) {
try {
handler.handleUncaughtException(session, e);
} catch (Exception e2) {
log.error("Exception while executing handleUncaughtException", e2);
}
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public void handleRequest(Session session, Request<JsonElement> request, ResponseSender rs) {
try {
if (handler == null) {
log.warn("JsonRpcClient has received a request from server but"
+ " there is no JsonRpcHandler configured to manage this" + " request");
return;
}
Class<?> paramsType = getParamsType(handler.getHandlerType());
Request<?> nonGenRequest;
try {
nonGenRequest = MessageUtils.convertRequest(request, paramsType);
} catch (ClassCastException e) {
String message = "The handler " + handler.getClass()
+ " is trying to process the request. But request params '" + request.getParams()
+ "' cannot be converted to " + paramsType.getCanonicalName()
+ ". The type to convert params is specified in the"
+ " handler as the supertype generic parameter";
// TODO Maybe use the pattern handleUncaughtException
log.error(message, e);
if (request.getId() != null) {
rs.sendResponse(new Response<>(null, new ResponseError(0, message)));
}
return;
}
JsonRpcHandler nonGenHandler = handler;
TransactionImpl tx = new TransactionImpl(session, request, rs);
nonGenHandler.handleRequest(tx, nonGenRequest);
if (!tx.isAsync() && request.getId() != null) {
log.debug("Request {} is processed asynchronously", request);
boolean notResponded = tx.setRespondedIfNot();
if (notResponded) {
// Empty response
rs.sendResponse(new Response<>(request.getId(), ""));
}
}
} catch (Exception e) {
// TODO Maybe use the pattern handleUncaughtException
log.error("Exception while processing request {}", request, e);
ResponseError error = ResponseError.newFromException(e);
try {
rs.sendResponse(new Response<>(request.getId(), error));
} catch (IOException e1) {
log.error("Exception sending error to client", e1);
}
}
}
// TODO Improve this way to obtain the generic parameters in class
// hierarchies
public static Class<?> getParamsType(Class<?> handlerClass) {
Type[] genericInterfaces = handlerClass.getGenericInterfaces();
for (Type type : genericInterfaces) {
if (type instanceof ParameterizedType) {
ParameterizedType parameterized = (ParameterizedType) type;
if (parameterized.getRawType() == JsonRpcHandler.class) {
return (Class<?>) parameterized.getActualTypeArguments()[0];
}
}
}
Type genericSuperclass = handlerClass.getGenericSuperclass();
if (genericSuperclass != null) {
if (genericSuperclass instanceof Class) {
return getParamsType((Class<?>) genericSuperclass);
}
ParameterizedType paramClass = (ParameterizedType) genericSuperclass;
if (paramClass.getRawType() == DefaultJsonRpcHandler.class) {
return (Class<?>) paramClass.getActualTypeArguments()[0];
}
return getParamsType((Class<?>) paramClass.getRawType());
}
throw new JsonRpcException("Unable to obtain the type paramter of JsonRpcHandler");
}
public void handleTransportError(Session session, Throwable exception) {
if (handler != null) {
try {
handler.handleTransportError(session, exception);
} catch (Exception e) {
try {
handler.handleUncaughtException(session, e);
} catch (Exception e2) {
log.error("Exception while executing handleUncaughtException", e2);
}
}
}
}
public JsonRpcHandler<?> getHandler() {
return handler;
}
}