Salut, j'ai une application RMI et maintenant j'essaie d'invoquer certaines méthodes sur le serveur depuis mon client. J'ai le code suivant:
public static void main(final String[] args) {
try {
//Setting the security manager
System.setSecurityManager(new RMISecurityManager());
IndicatorsService server = (IndicatorsService) Naming
.lookup("rmi://localhost/" + IndicatorsService.SERVICE_NAME);
DataProvider provider = new OHLCProvider(server);
server.registerOHLCProvider(provider);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
le serveur est correctement chargé, mais lorsque j'essaie d'appeler server.registerOHLCProvider(provider);
j'obtiens ces erreurs:
Java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
Java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
Java.lang.ClassNotFoundException: sk.xorty.client.providers.OHLCProvider (no security manager: RMI class loader disabled)
at Sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.Java:336)
at Sun.rmi.transport.Transport$1.run(Transport.Java:159)
at Java.security.AccessController.doPrivileged(Native Method)
at Sun.rmi.transport.Transport.serviceCall(Transport.Java:155)
at Sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.Java:535)
at Sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.Java:790)
at Sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.Java:649)
at Java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.Java:886)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:908)
at Java.lang.Thread.run(Thread.Java:662)
at Sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.Java:255)
at Sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.Java:233)
at Sun.rmi.server.UnicastRef.invoke(UnicastRef.Java:142)
at sk.fri.statistics.service.impl.IndicatorsServiceImpl_Stub.registerOHLCProvider(Unknown Source)
at sk.fri.statistics.service.Client.main(Client.Java:61)
Caused by: Java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
Java.lang.ClassNotFoundException: sk.xorty.client.providers.OHLCProvider (no security manager: RMI class loader disabled)
at Sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.Java:296)
at Sun.rmi.transport.Transport$1.run(Transport.Java:159)
at Java.security.AccessController.doPrivileged(Native Method)
at Sun.rmi.transport.Transport.serviceCall(Transport.Java:155)
at Sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.Java:535)
at Sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.Java:790)
at Sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.Java:649)
at Java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.Java:886)
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:908)
at Java.lang.Thread.run(Thread.Java:662)
Caused by: Java.lang.ClassNotFoundException: sk.xorty.client.providers.OHLCProvider (no security manager: RMI class loader disabled)
at Sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.Java:375)
at Sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.Java:165)
at Java.rmi.server.RMIClassLoader$2.loadClass(RMIClassLoader.Java:620)
at Java.rmi.server.RMIClassLoader.loadClass(RMIClassLoader.Java:247)
at Sun.rmi.server.MarshalInputStream.resolveClass(MarshalInputStream.Java:197)
at Java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.Java:1574)
at Java.io.ObjectInputStream.readClassDesc(ObjectInputStream.Java:1495)
at Java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.Java:1731)
at Java.io.ObjectInputStream.readObject0(ObjectInputStream.Java:1328)
at Java.io.ObjectInputStream.readObject(ObjectInputStream.Java:350)
at Sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.Java:306)
at Sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.Java:290)
... 9 more
J'ai ajouté mon fichier de stratégie en tant qu'argument VM, voici à quoi il ressemble:
grant {
permission Java.security.AllPermission;
}
Il continue de dire quelque chose sur le chargement de classe désactivé, donc je suppose que le problème est quelque part là-bas ... Merci!
Le chargement de classe à distance peut être délicat.
Le message d'origine ne contient aucune information sur la base de code. Il se peut que la configuration de sécurité du client soit correcte, mais il n'a pas accès au code distant. Les classes sont chargées directement à partir de la "base de code" par le client. Ils ne sont pas présentés au client par le service via la connexion RMI. Le service fait simplement référence à une source externe pour les classes.
Le serveur doit spécifier la propriété système Java.rmi.server.codebase
. La valeur doit être une URL accessible au client à partir de laquelle les classes nécessaires peuvent être chargées. S'il s'agit d'un file:
URL, le système de fichiers doit être accessible au client.
Et l'inverse: si le serveur doit pouvoir charger des classes à partir du client (comme ici), le client doit définir la propriété de base de code sur une URL accessible au serveur.
Chaque fois que vous appelez une méthode sur un proxy dynamique RMI, le MarshalInputStream
(qui étend ObjectInputStream
pour remplacer resolveClass
et resolveProxyClass
) délègue à LoaderHandler
pour rechercher à 3 endroits le ClassLoader
à utiliser:
latestUserDefinedLoader()
: il parcourt la pile, recherchant la première méthode sur la pile qui ne fait pas partie de JRE).contextClassLoader
de l'appelantJava.rmi.server.useCodebaseOnly=false
, Alors le ClassLoader de base de code utilise des URL dans la télécommande Java.rmi.server.codebase
. Notez que la valeur par défaut de useCodebaseOnly a changé dans JDK 7u21 afin que la base de code distante ne soit plus utilisée à moins que vous ne la changiez !Java.rmi.server.codebase
.Il y a donc plusieurs raisons possibles pour lesquelles vous obtiendrez un ClassNotFoundException
lors de l'appel d'une méthode distante:
-Djava.rmi.server.useCodebaseOnly=true
Pour qu'il corresponde au comportement précédent ou définissez -Djava.rmi.server.codebase
Sur une liste d'URL séparées par des espaces sur les deux les côtés locaux et éloignés. Et assurez-vous que l'ordinateur peut accéder à ces URL.Thread.setContextClassLoader(ClassLoader)
pour que RMI utilise ce ClassLoader. (C'était mon problème: j'avais un SwingWorker
qui se trouvait être planifié sur un thread de travail qui a été créé avant que le contextClassLoader ne soit défini sur EventDispatchThread). Par exemple, A et C appartiennent à votre ClassLoader personnalisé mais B appartient au ClassLoader parent, puis lorsque vous appelez a.getB (). GetC (), l'appel getB () utilise le chargeur de classe personnalisé, mais l'appel getC () échouera à trouver C dans le dernierUserDefinedClassLoader et devra se replier sur le contextClassLoader.Tout cela est un récit édifiant sur la mauvaise conception d'API d'ObjectInputStream. ObjectInputStream aurait dû vous obliger à passer un paramètre ClassLoader, et non pas à en trouver un au hasard à l'aide de latestUserDefinedLoader, contextClassLoader et codebase.
Vous avez besoin du gestionnaire de sécurité côté serveur, pas seulement côté client.
Sans cela, le moteur RMI du serveur refuse de charger des classes à partir du client, car il ne peut garantir que celles-ci ne feront rien de mal sur le serveur.
Avez-vous besoin du chargement de classe RMI? Le serveur ne peut-il pas déjà avoir les classes que le client essaie d'envoyer?