I'm trying to do something that is quite impossible with Java, but maybe there's a solution.
The code below tries to pass a transactional object via RMI
public class FileRepositoryImpl extends UnicastRemoteObject
implements FileRepository {
@Override
public byte[] get(String appId, String filePath) throws RemoteException, NotBoundException {
Registry registry = LocateRegistry.getRegistry();
XodusRepository repository = (XodusRepository) registry.lookup(XodusRepository.class.getName());
final byte[][] bytes = {null};
repository.transact(appId, true, new Command<byte[]>() {
@Override public byte[] execute(jetbrains.exodus.entitystore.StoreTransaction txn) {
Entity entity = txn.findWithBlob(Constants.ENTITYSTORE_FILE, filePath).getLast();
if (entity != null) {
InputStream blobStream = entity.getBlob(filePath);
bytes[0] = Try.of(() -> ByteStreams.toByteArray(blobStream)).getOrNull();
}
return bytes[0];
}
});
return bytes[0];
}
}
However this code throws:
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: com.mycompany.backend.repository.FileRepositoryImpl$1 (no security manager: RMI class loader disabled)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:391)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
at java.rmi/sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:283)
at java.rmi/sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:260)
at java.rmi/sun.rmi.server.UnicastRef.invoke(UnicastRef.java:161)
at java.rmi/java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:209)
at java.rmi/java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:161)
at com.sun.proxy.$Proxy57.transact(Unknown Source)
at com.mycompany.backend.repository.FileRepositoryImpl.get(FileRepositoryImpl.java:48)
at com.mycompany.backend.hosting.MyCompanyFileRepresentation.write(MyCompanyFileRepresentation.java:91)
On the other side, the other Java process it have:
@Override public <T> T transact(String appId, boolean isReadOnly, Command<T> command)
throws NotBoundException, RemoteException {
AtomicReference<T> result = null;
manager.transactPersistentEntityStore(xodusRoot, appId, isReadOnly, txn -> {
result.set(command.execute(txn));
});
return Try.of(() -> result.get()).getOrNull();
}
Is there a way to use transactional objects over RMI?
ClassNotFoundException
for theFileRepositoryImpl$1
class. We had similar symptoms when the rmiregistry could not access our business classes. We had to make our classes visible to the rmiregistry.exe using the "code base" property (don't recall the details right now). – AdditamentSystem.setProperty("java.rmi.server.codebase", codebaseUrl)
in a very early stage of initialization, with a URL where the rmiregistry.exe could find the relevant class definitions. As a special hack, we integrated an HTTP server into our app serving class files based ongetResourceAsStream()
, so the class version seen by rmiregistry was always up to date. As a security measure, we published only a limited list of classes this way. – Additamentbytes
is on the client side and also being updated on the server thus, how can the "server-side" RMI even assign value to that variable from the other end of the spectrum? Can RMI access objects across difference processes? – Lacerate