tags:

views:

370

answers:

2

I'm currently using a Spring RmiProxyFactoryBean to access remote services. Since requirements have changed, I need to specify at runtime a different host - there can be many of them - , but the remoteServiceInterface and the non-host components of the remoteServiceUrl remain the same.

Conceptually speaking, I'd see a bean definition similar to:

<bean class="org.springframework.remoting.rmi.RmiProxyFactoryBeanFactory">
     <property name="serviceInterface" value="xxx"/>
     <property name="serviceUrl" value="rmi://#{HOST}:1099/ServiceUrl"/>
</bean>

which exposes a

Object getServiceFor(String hostName);

Is there such a service available with Spring? Alternatively, do you see another way of doing this?


Please note that the host list will not be known at compile or startup time, so I can't generate it in the xml file.

+1  A: 

If you look at the source for RmiProxyFactoryBean, you can see that it's a very thin subclass of RmiClientInterceptor, which is just a standard AOP MethodInterceptor. This suggests to me that you could write a custom class which implements your desired getServiceFor(hostname) method, and this method could use a Spring ProxyFactory in a similar way to RmiProxyFactoryBean, to generate a run-time proxy for your specific host.

For example:

public Object getProxyFor(String hostName) {
 RmiClientInterceptor rmiClientInterceptor = new RmiClientInterceptor();
 rmiClientInterceptor.setServiceUrl(String.format("rmi://%s:1099/ServiceUrl", hostName));
 rmiClientInterceptor.setServiceInterface(rmiServiceInterface);
 rmiClientInterceptor.afterPropertiesSet();

 return new ProxyFactory(proxyInterface, rmiClientInterceptor).getProxy();
}

Where rmiServiceInterface and proxyInterface are types defined by you.

skaffman
A: 

I ended up implemeting something similar to:

public class RmiServiceFactory implements BeanClassLoaderAware {
  public Service getServiceForHost(String hostName) {
    factory = new RmiProxyFactoryBean();
    factory.setLookupStubOnStartup(false);
    factory.setRefreshStubOnConnectFailure(true);
    factory.setServiceInterface(Service.class);
    factory.setServiceUrl(String.format(_serviceUrlFormat, hostName));
    if (_classLoader != null)
        factory.setBeanClassLoader(_classLoader);

    factory.afterPropertiesSet();
  }
}

Of course, there is some sanity checking and caching involved, but I've ommited them.

Robert Munteanu