/*
* Copyright 2002-2016 the original author or authors.
*
* 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.springframework.remoting.rmi;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.SocketException;
import java.rmi.ConnectException;
import java.rmi.ConnectIOException;
import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.rmi.StubNotFoundException;
import java.rmi.UnknownHostException;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.remoting.RemoteConnectFailureException;
import org.springframework.remoting.RemoteProxyFailureException;
import org.springframework.util.ReflectionUtils;
Factored-out methods for performing invocations within an RMI client.
Can handle both RMI and non-RMI service interfaces working on an RMI stub.
Note: This is an SPI class, not intended to be used by applications.
Author: Juergen Hoeller Since: 1.1
/**
* Factored-out methods for performing invocations within an RMI client.
* Can handle both RMI and non-RMI service interfaces working on an RMI stub.
*
* <p>Note: This is an SPI class, not intended to be used by applications.
*
* @author Juergen Hoeller
* @since 1.1
*/
public abstract class RmiClientInterceptorUtils {
private static final Log logger = LogFactory.getLog(RmiClientInterceptorUtils.class);
Perform a raw method invocation on the given RMI stub,
letting reflection exceptions through as-is.
Params: - invocation – the AOP MethodInvocation
- stub – the RMI stub
Throws: - InvocationTargetException – if thrown by reflection
Returns: the invocation result, if any
/**
* Perform a raw method invocation on the given RMI stub,
* letting reflection exceptions through as-is.
* @param invocation the AOP MethodInvocation
* @param stub the RMI stub
* @return the invocation result, if any
* @throws InvocationTargetException if thrown by reflection
*/
@Nullable
public static Object invokeRemoteMethod(MethodInvocation invocation, Object stub)
throws InvocationTargetException {
Method method = invocation.getMethod();
try {
if (method.getDeclaringClass().isInstance(stub)) {
// directly implemented
return method.invoke(stub, invocation.getArguments());
}
else {
// not directly implemented
Method stubMethod = stub.getClass().getMethod(method.getName(), method.getParameterTypes());
return stubMethod.invoke(stub, invocation.getArguments());
}
}
catch (InvocationTargetException ex) {
throw ex;
}
catch (NoSuchMethodException ex) {
throw new RemoteProxyFailureException("No matching RMI stub method found for: " + method, ex);
}
catch (Throwable ex) {
throw new RemoteProxyFailureException("Invocation of RMI stub method failed: " + method, ex);
}
}
Wrap the given arbitrary exception that happened during remote access
in either a RemoteException or a Spring RemoteAccessException (if the
method signature does not support RemoteException).
Only call this for remote access exceptions, not for exceptions
thrown by the target service itself!
Params: - method – the invoked method
- ex – the exception that happened, to be used as cause for the
RemoteAccessException or RemoteException
- message – the message for the RemoteAccessException respectively
RemoteException
Returns: the exception to be thrown to the caller
/**
* Wrap the given arbitrary exception that happened during remote access
* in either a RemoteException or a Spring RemoteAccessException (if the
* method signature does not support RemoteException).
* <p>Only call this for remote access exceptions, not for exceptions
* thrown by the target service itself!
* @param method the invoked method
* @param ex the exception that happened, to be used as cause for the
* RemoteAccessException or RemoteException
* @param message the message for the RemoteAccessException respectively
* RemoteException
* @return the exception to be thrown to the caller
*/
public static Exception convertRmiAccessException(Method method, Throwable ex, String message) {
if (logger.isDebugEnabled()) {
logger.debug(message, ex);
}
if (ReflectionUtils.declaresException(method, RemoteException.class)) {
return new RemoteException(message, ex);
}
else {
return new RemoteAccessException(message, ex);
}
}
Convert the given RemoteException that happened during remote access
to Spring's RemoteAccessException if the method signature does not
support RemoteException. Else, return the original RemoteException.
Params: - method – the invoked method
- ex – the RemoteException that happened
- serviceName – the name of the service (for debugging purposes)
Returns: the exception to be thrown to the caller
/**
* Convert the given RemoteException that happened during remote access
* to Spring's RemoteAccessException if the method signature does not
* support RemoteException. Else, return the original RemoteException.
* @param method the invoked method
* @param ex the RemoteException that happened
* @param serviceName the name of the service (for debugging purposes)
* @return the exception to be thrown to the caller
*/
public static Exception convertRmiAccessException(Method method, RemoteException ex, String serviceName) {
return convertRmiAccessException(method, ex, isConnectFailure(ex), serviceName);
}
Convert the given RemoteException that happened during remote access
to Spring's RemoteAccessException if the method signature does not
support RemoteException. Else, return the original RemoteException.
Params: - method – the invoked method
- ex – the RemoteException that happened
- isConnectFailure – whether the given exception should be considered
a connect failure
- serviceName – the name of the service (for debugging purposes)
Returns: the exception to be thrown to the caller
/**
* Convert the given RemoteException that happened during remote access
* to Spring's RemoteAccessException if the method signature does not
* support RemoteException. Else, return the original RemoteException.
* @param method the invoked method
* @param ex the RemoteException that happened
* @param isConnectFailure whether the given exception should be considered
* a connect failure
* @param serviceName the name of the service (for debugging purposes)
* @return the exception to be thrown to the caller
*/
public static Exception convertRmiAccessException(
Method method, RemoteException ex, boolean isConnectFailure, String serviceName) {
if (logger.isDebugEnabled()) {
logger.debug("Remote service [" + serviceName + "] threw exception", ex);
}
if (ReflectionUtils.declaresException(method, ex.getClass())) {
return ex;
}
else {
if (isConnectFailure) {
return new RemoteConnectFailureException("Could not connect to remote service [" + serviceName + "]", ex);
}
else {
return new RemoteAccessException("Could not access remote service [" + serviceName + "]", ex);
}
}
}
Determine whether the given RMI exception indicates a connect failure.
Treats RMI's ConnectException, ConnectIOException, UnknownHostException,
NoSuchObjectException and StubNotFoundException as connect failure.
Params: - ex – the RMI exception to check
See Also: Returns: whether the exception should be treated as connect failure
/**
* Determine whether the given RMI exception indicates a connect failure.
* <p>Treats RMI's ConnectException, ConnectIOException, UnknownHostException,
* NoSuchObjectException and StubNotFoundException as connect failure.
* @param ex the RMI exception to check
* @return whether the exception should be treated as connect failure
* @see java.rmi.ConnectException
* @see java.rmi.ConnectIOException
* @see java.rmi.UnknownHostException
* @see java.rmi.NoSuchObjectException
* @see java.rmi.StubNotFoundException
*/
public static boolean isConnectFailure(RemoteException ex) {
return (ex instanceof ConnectException || ex instanceof ConnectIOException ||
ex instanceof UnknownHostException || ex instanceof NoSuchObjectException ||
ex instanceof StubNotFoundException || ex.getCause() instanceof SocketException);
}
}