/*
* Copyright 2000-2016 Vaadin Ltd.
*
* 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 com.vaadin.server;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.vaadin.shared.communication.ServerRpc;
/**
* Server side RPC manager that handles RPC calls coming from the client.
*
* Each {@link RpcTarget} (typically a {@link ClientConnector}) should have its
* own instance of {@link ServerRpcManager} if it wants to receive RPC calls
* from the client.
*
* @since 7.0
*/
public class ServerRpcManager<T extends ServerRpc> implements Serializable {
private final T implementation;
private final Class<T> rpcInterface;
/**
* Wrapper exception for exceptions which occur during invocation of an RPC
* call
*
* @author Vaadin Ltd
* @since 7.0
*
*/
public static class RpcInvocationException extends Exception {
public RpcInvocationException() {
super();
}
public RpcInvocationException(String message, Throwable cause) {
super(message, cause);
}
public RpcInvocationException(String message) {
super(message);
}
public RpcInvocationException(Throwable cause) {
super(cause);
}
}
private static final Map<Class<?>, Class<?>> boxedTypes = new HashMap<>();
static {
try {
Class<?>[] boxClasses = new Class<?>[] { Boolean.class, Byte.class,
Short.class, Character.class, Integer.class, Long.class,
Float.class, Double.class };
for (Class<?> boxClass : boxClasses) {
Field typeField = boxClass.getField("TYPE");
Class<?> primitiveType = (Class<?>) typeField.get(boxClass);
boxedTypes.put(primitiveType, boxClass);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Create a RPC manager for an RPC target.
*
* @param implementation
* RPC interface implementation for the target
* @param rpcInterface
* RPC interface type
*/
public ServerRpcManager(T implementation, Class<T> rpcInterface) {
this.implementation = implementation;
this.rpcInterface = rpcInterface;
}
/**
* Invoke a method in a server side RPC target class. This method is to be
* used by the RPC framework and unit testing tools only.
*
* @param target
* non-null target of the RPC call
* @param invocation
* method invocation to perform
* @throws RpcInvocationException
*/
public static void applyInvocation(ClientConnector target,
ServerRpcMethodInvocation invocation)
throws RpcInvocationException {
ServerRpcManager<?> manager = target
.getRpcManager(invocation.getInterfaceName());
if (manager != null) {
manager.applyInvocation(invocation);
} else {
getLogger().log(Level.WARNING,
"RPC call received for RpcTarget {0} ({1}) but the target has not registered any RPC interfaces",
new Object[] { target.getClass().getName(),
invocation.getConnectorId() });
}
}
/**
* Returns the RPC interface implementation for the RPC target.
*
* @return RPC interface implementation
*/
protected T getImplementation() {
return implementation;
}
/**
* Returns the RPC interface type managed by this RPC manager instance.
*
* @return RPC interface type
*/
public Class<T> getRpcInterface() {
return rpcInterface;
}
/**
* Invoke a method in a server side RPC target class. This method is to be
* used by the RPC framework and unit testing tools only.
*
* @param invocation
* method invocation to perform
*/
public void applyInvocation(ServerRpcMethodInvocation invocation)
throws RpcInvocationException {
Method method = invocation.getMethod();
Object[] arguments = invocation.getParameters();
try {
method.invoke(implementation, arguments);
} catch (Exception e) {
throw new RpcInvocationException(
"Unable to invoke method " + invocation.getMethodName()
+ " in " + invocation.getInterfaceName(),
e);
}
}
private static Logger getLogger() {
return Logger.getLogger(ServerRpcManager.class.getName());
}
/**
* Returns an RPC proxy for a given client to server RPC interface for the
* given component or extension.
*
* @param connector
* the connector for which to the RPC proxy
* @param rpcInterface
* the RPC interface type
*
* @return a server RPC handler which can be used to invoke RPC methods
* @since 8.0
*/
public static <T extends ServerRpc> T getRpcProxy(ClientConnector connector,
final Class<T> rpcInterface) {
@SuppressWarnings("unchecked")
ServerRpcManager<T> rpcManager = (ServerRpcManager<T>) connector
.getRpcManager(rpcInterface.getName());
if (rpcManager == null) {
return null;
}
return rpcManager.getImplementation();
}
}