Удаленная коллекция RMI без сериализации объектов локали

Связано с: Передача удаленных параметров в RMI

Привет,

Я ищу решение следующей проблемы: у меня есть объекты локали (скажем, типа MyObject), которые удаленно представлены RemoteObject со ссылкой на эти объекты.

public class RemoteMyObject extends UnicastRemoteObject implements MyRemoteInterface {

  MyObject refToLocale;

  protected RemoteMyObject(MyObject locale) throws RemoteException {
    super();
    refToLocale = locale;
  }

  @Override // MyRemoteInterface
  public void doSomething() throws RemoteException {
    System.out.println("did it!");
  }

  public MyObject getLocale() {
    return refToLocale;
  }
}

Это работает, как и ожидалось. Я не хочу сериализовать MyObject, потому что в нем есть ссылки на другие несериализуемые классы, а файлы классов зашифрованы. Теперь у меня есть коллекции MyObject, и я хочу управлять ими удаленно. Поэтому я реализовал RemoteCollection.

public class MyRemoteCollection extends UnicastRemoteObject implements
RemoteCollection<MyRemoteInterface> {

  Collection<MyObject> localeCollection;

  public MyRemoteCollection(Collection<MyObject> locale) throws RemoteException {
    super();
    localeCollection = locale;
  }

  @Override
  public Collection<RemoteMyObject> getItems() throws RemoteException {
    ArrayList<RemoteMyObject> result = new ArrayList<RemoteMyObject>();
    for (MyObject locale : localeCollection) {
      result.add(new RemoteMyObject(locale));
    }
    return result;
  }

  @Override
  public void delete(MyRemoteInterface obj) {
    MyObject locale = ((RemoteMyObject)obj).getLocale();
    localeCollection.remove(locale);
  }

}

Теперь проблема в том, что клиент вызывает getItems() через RMI и получает коллекцию удаленных/прокси-объектов. Эти объекты можно использовать как обычно (я могу вызвать doSomething()), но как только я захочу удалить один из этих объектов, у меня возникнет проблема: delete()-метод ожидает объект, который он может привести к RemoteMyObject, чтобы получить ссылку на локаль, но доставленный аргумент - это просто заглушка, поэтому приведение не выполняется.

Поскольку объект изначально был создан на сервере, мой вопрос заключается в том, могу ли я вернуть объект локали или есть более элегантное решение проблемы?

Спасибо за чтение.

Для полноты интерфейсы и сервер и клиент:

public interface MyRemoteInterface extends Remote {

  void doSomething() throws RemoteException;

}

public interface RemoteCollection<REM> extends Remote {

  Collection< ? extends REM> getItems() throws RemoteException;

  void delete(REM obj) throws RemoteException;

}

public class MainServer {

  public static void main(String[] args) {
    try {
      Registry registry = java.rmi.registry.LocateRegistry.createRegistry(1099);
      Collection<MyObject> coll = new ArrayList<>();
      coll.add(new MyObject());
      coll.add(new MyObject());
      coll.add(new MyObject());
      MyRemoteCollection remCol = new MyRemoteCollection(coll);
      registry.rebind("mylist", remCol);

    } catch (RemoteException e) {
      e.printStackTrace();
    }
  }

}

public class MainClient {

  public static void main(String[] args) {
    try {
      Registry registry = LocateRegistry.getRegistry("localhost", 1099);
      RemoteCollection<MyRemoteInterface> remCol = (RemoteCollection<MyRemoteInterface>)registry.lookup("mylist");
      for (MyRemoteInterface item : remCol.getItems()) {
        item.doSomething();
        remCol.delete(item);
      }
    } catch (RemoteException | NotBoundException  e) {
      e.printStackTrace();
    }
  }
}

person Joachim    schedule 09.12.2014    source источник


Ответы (2)


Идея RMI состоит в том, чтобы определить параметры удаленного метода и возвращаемые значения как удаленный интерфейс, а не удаленный объект.

Таким образом, приведение в методе delete() должно быть MyRemoteInterface, а не RemoteMyObject.

Так же:

public Collection<RemoteMyObject> getItems() throws RemoteException {

Измените эту подпись на:

public Collection<MyRemoteInterface> getItems() throws RemoteException {
person user207421    schedule 09.12.2014
comment
Спасибо за ответ, к сожалению, это не решило проблему. На самом деле я могу привести аргумент к MyRemoteInterface, но тогда я не могу получить доступ к MyObject, который хочу удалить из коллекции на сервере. RemoteCollectionInterface определяет сигнатуру метода как ограниченный тип подстановочного знака < ? extends MyRemoteInterface> getItems(), поэтому эта часть работает хорошо, и я могу использовать этот метод. - person Joachim; 10.12.2014
comment
Вам нужна карта, чтобы вы могли перейти от заглушек, которые вы получите в качестве параметров, к фактическим экспортированным объектам, которым они принадлежат. - person user207421; 11.12.2014
comment
Спасибо, это то, что я наконец сделал. - person Joachim; 21.12.2014

Как сказал @EJP в комментариях, вам нужна карта для сопоставления заглушек с реальными/локальными объектами. Я добавил новый интерфейс

interface IdentifieableRemoteObject {

  ObjID getObjectID();

}

Затем я создал карту из ObjID в конкретный экземпляр реализующего класса.

class RemoteObjectCache {

  private static WeakHashMap<ObjID, WeakReference<IdentifieableRemoteObject>> cache = new WeakHashMap<>;

  public static void register(IdentiefieableRemoteObject iro) {
    cache.put(iro.getID(), iro);
  }

  public IdentifieableRemoteObject lookUp(ObjID id) {
    chache.get(id);
  }

}

Я использую WeakHashMap со слабыми ссылками, поэтому (распределенный) процесс сборки мусора удалит неиспользуемые удаленные объекты, даже если они есть на карте. Мои удаленные объекты регистрируются, вызывая RemoteObjectCache.register(this) в своем конструкторе.

person Joachim    schedule 21.12.2014