Related To: Passing remote parameters in RMI
Hello,
I look for a solution for the following problem: I have locale Objects (lets say of type MyObject) that are represented remotely by RemoteObject with a Reference to these Objects.
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;
}
}
That works as expected. I do not want to serialize MyObject
, because it has references to other unseriliazable classes and the class-files are enyrypted. Now I have Collections of MyObject
and I want to manipulate them remotely. So I implemented a 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);
}
}
The problem is now, that the client calls getItems()
via RMI and recieves a Collection of Remote/Proxy-Objects. These objects can be used as normal (I can call doSomething()
) but as soon as I want one of these objects deleted I have a problem: The delete()
-Method expects an Object that it can cast to RemoteMyObject
to get the locale reference, but the delivered argument is just a stub and so the cast fails.
Since the Object was originally created on the server, my question is now if I can get the locale object back or if there is a more elegant solution to solve the Problem?
Thank you for reading.
For completeness the interfaces and the server and client:
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();
}
}
}
As @EJP said in the comments, you need a map for mapping the stubs to the real/local objects. I added a new Interface
interface IdentifieableRemoteObject {
ObjID getObjectID();
}
Then I created a Map from ObjID
to the concrete instance of the implementing class.
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);
}
}
I use a WeakHashMap
with weak references, so the (distributed) garbage collection process will remove unused remote objects even if they are in the map. My remote objects register themselves by calling RemoteObjectCache.register(this)
in theire constructor.