RMI Remote Collection без сериализиране на локални обекти

Свързано с: Предаване на отдалечени параметри в 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