views:

25

answers:

2

I have an application which exposes a service via Spring's RMI proxy mechanism. There is a problem whereby sometimes a "blip" on the file-server it has its JARs stored on causes an invocation to propagate a NoClassDefFoundError back to the caller.

So far, so fair enough. The thing is, I would like my app to just crash if this happens - i.e. if an Error is going to be propagated back out to the caller.

Note that I already have an UncaughtExceptionHandler in the app and this is not being invoked (because the exception is not really uncaught)

+1  A: 

If you are exposing the RMI service via RmiServiceExporter (or any other subclass of RemoteExporter), then you can inject arbitrary interceptors into the call stack, which will be invoked whenever the RMI service is invoked.

These interceptors could trap any thrown NoClassDefFoundError, and call System.exit().

For example:

public class ExitInterceptor implements MethodInterceptor {

 @Override
 public Object invoke(MethodInvocation methodInvocation) throws Throwable {
  try {
   return methodInvocation.proceed();
  } catch (NoClassDefFoundError noClassDefFoundError) {
   noClassDefFoundError.printStackTrace();
   System.exit(1);
   return null;
  }
 }

}

and

<bean id="exporter" class="org.springframework.remoting.rmi.RmiServiceExporter">
   <!-- existing properties -->
   <property name="interceptors">
      <bean class="com.x.ExitInterceptor"/>
   <property>
</bean>
skaffman
+1  A: 

What you can do is to extend [RmiServiceExporter][1] and handle the exception in the invoke method. This can be done as so

public class AutoFailRmiServiceExporter extends RmiProxyFactoryBean implements ApplicationContextAware {

    private ApplicationContext ac;
    @override
    public Object invoke(RemoteInvocation invocation,
                    Object targetObject)
             throws NoSuchMethodException,
                    IllegalAccessException,
                    InvocationTargetException {
        try {
          super.invoke(methodInvocation, target);
        } catch (NoClassDefFoundError e) {
          if {ac instanceof ConfigurableApplicationContext) {
            (ConfigurableApplicationContext)ac).close();
          else {
            //log error
          }
        }
    }
    //application context setter

}

You would then use your AutoFail version of the RmiServiceExporterwhen defining your rmi service in your spring context.

EDIT: The original answer showed a way of killing the client when the exception is thrown. This is done by subclassing RmiProxyFactorty and overriding doInvoke instead of RmiServiceExporter.

mR_fr0g
`RmiProxyFactoryBean` is used on the client, not the server.
skaffman
My answer assumes that you wanted to kill the client. From a second reading it appears that you want to kill the service app. The same principle still applies. Instead of extending RmiProxyFactory you would extend RmiServiceExporter
mR_fr0g
I want to kill the server: the point being is that my client will then failover to a secondary server instance
oxbow_lakes