title: Spring - Passing Listener via RMI
body: <h2>Basis</h2>
  
  <p>I have several projects, which implement a caching service - each its own, and each one is almost the same as the others. I have coompressed and shortened the existing cacheservices into a single project containing two different cache services - one for basic objects, and one for complex objects (which extends the basic service). I have created 2 projects - one to deploy as a .war-file and the API-project for this.</p>
  
  <p>The entire application runs on a JBoss AS 7.1 "Thunder" with the latest JDK 7.</p>
  
  <h2>Problem</h2>
  
  <p>One class in particular requires to be notified whenever an old cache entry is deleted. For this, I implemented a notification procedure using CleanupListeners.</p>
  
  <p><em>CleanupListener.java</em></p>
  
  <pre><code>public interface CleanupListener extends Remote {
  
      public abstract boolean supports(Class&lt;?&gt; clazz) throws RemoteException;
  
      public abstract void notify(Object removedObject) throws RemoteException;
  
  }
  </code></pre>
  
  <p><em>necessary implementations in the cache service</em></p>
  
  <pre><code>public void registerCleanupListener(CleanupListener listener) {
      listeners.add(listener);
  }
  
  private void fireCleanupEvent(Object removedObject) {
      for (CleanupListener cleanupListener : listeners) {
          try {
              if (cleanupListener.supports(removedObject.getClass())) {
                  cleanupListener.notify(removedObject);
              }
          } catch (RemoteException re) {
              LOGGER.error("Remote Listener not available", re);
          }
      }
  }
  </code></pre>
  
  <p>The listeners are managed via a <code>private final HashSet&lt;CleanupListener&gt;</code><br>
  The project which needs to be notified uses this implementation of the interface:</p>
  
  <pre><code>@Component
  public class CleanupEventListener extends UnicastRemoteObject implements CleanupListener {
  
      protected CleanupEventListener() throws RemoteException {
          super();
      }
  
      @Resource
      private ClassRequiresNotification notifyMe;
  
      public boolean supports(Class&lt;?&gt; clazz) {
          return SupportedObject.class.isAssignableFrom(clazz);
      }
  
      public void notify(Object removedObject) {
          notifyMe.someMethod((SupportedObject) removedObject);
      }
  }
  </code></pre>
  
  <p>and a registration bean:</p>
  
  <pre><code>@Component
  public class CleanupEventListenerRegistrator {
  
      @Resource
      private CleanupEventListener cleanupEventListener;
  
      @Resource
      private BasicCacheService cacheService;
  
      @PostConstruct
      public void init() {
          cacheService.registerCleanupListener(cleanupEventListener);
      }
  }
  </code></pre>
  
  <p>The remote services are exported via SpringBean:</p>
  
  <pre><code>@Bean
  public RmiServiceExporter basicCacheServiceExporter(BasicCacheService basicCacheService) {
      RmiServiceExporter cacheService = new RmiServiceExporter();
      cacheService.setService(basicCacheService);
      cacheService.setServiceName(BASIC_CACHE_SERVICE_NAME);
      cacheService.setServiceInterface(some.package.BasicCacheService.class);
      return cacheService;
  }
  </code></pre>
  
  <p>and registered via XML-Config:</p>
  
  <pre><code>&lt;bean id="basicCacheService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"&gt;
      &lt;property name="lookupStubOnStartup" value="false"/&gt;
      &lt;property name="serviceUrl" value="basicCacheService" /&gt;
      &lt;property name="serviceInterface" value="some.package.BasicCacheService" /&gt;
      &lt;property name="refreshStubOnConnectFailure" value="true"/&gt;
  &lt;/bean&gt;
  </code></pre>
  
  <h2>Exception</h2>
  
  <p>So, whenever I try to call the expected methods, I get one of two Exceptions:</p>
  
  <p>Either I get a <code>NoSuchObjectException</code> (rare) or, much more common a <code>ClassNotFoundException</code> wrapped in an <code>UnmarshalException</code></p>
  
  <h2>What I did</h2>
  
  <p>I already consulted the JavaDocs, googled massively and have sifted through several questions here, however to no avail. I found a bit of info that the standard property <code>rmi.codebase</code> is set to <code>true</code>, and this might require some rewriting of code, however we are already using RMI at another place in the projects, and it does work fine there. Adding a SecurityManager breaks the rest of our Application (due to external prerequisites) and calls the <code>NoSuchObjectException</code>.
  Answers within StackOverflow so far have yielded "this is a problem with the codebase", "you need to install a securityManager", "the classes have to have the same name and be in the same package" and of course "it's the codebase". I am mentioning this one twice, since it does appear quite often yet not a single mention as to how to deal with a codebase problem accompanies it.</p>
  
  <h2>Additional Info</h2>
  
  <p>I am not sure if this is important, but here's some more info:
  The cacheservice-project is configured in java code, the projects which use the service are configured in XML.<br>
  The Listener-Interface is not exported vie Annotations or XML-Beans, since several Posts (including at least one here) hinted that this will export the class, but keep listening only on server-side, which is not what I want.<br>
  I have also tried to make the <code>CleanupListener</code>an abstract class, which in itselt extends <code>UnicastRemoteObject</code> but that did not work out either - in fact, it was worse than what I have now.<br>
  I am writing and testing the application in eclipse.<br>
  Assembling and publishing to server is done by gradle in the command line.</p>
  
  <h2>Question</h2>
  
  <p>Does anyone know what the problem here is, and how to actually solve it? It is getting quite aggravating when everything I do is either running into an exception or is "yeah that's a codebase error", since both do not help at all.</p>
  
  <p>Any help would be appreciated.</p>