Tuesday, October 16, 2012

Java RMI

You may have noticed not much blogging since I returned from Philly.  That's because I have been grading papers.  Every spare moment is either my day job, or doing the drudge part of a job that I really enjoy: teaching.  (If only there was a way to get paid to do what I am really good at: legal and historical research.)

I have been learning more about Java RMI, but I am running into some obstacles, and I am hoping that some of my readers can help me figure these obstacles out.

I have managed to get a sample Java RMI application running, as long as I start the RMI server and client from the DOS shell with something like this for the server:

java -cp .;c:\tomcat5\webapps\rmi\compute.jar -Djava.rmi.server.codebase=file:/c:\tomcat5\webapps\rmi\compute.jar -Djava.security.policy="C:\\tomcat5\\webapps\rmi\server.policy" engine.ComputeEngine

and this for the client:

java -cp c:\tomcat5\webapps\rmi;c:\tomcat5\webapps\rmi\compute.jar 
-Djava.rmi.server.codebase=file:/c:\tomcat5\webapps\rmi\ 
-Djava.security.policy="c:\\tomcat5\\webapps\\rmi\\client\\client.policy" client.ComputePi localhost %1%

You will notice that I am storing many of the components in the Tomcat directory, but Java RMI does not actually require Tomcat.  (This is actually something of a virtue.)  I can make it work with Tomcat stopped.
  
However, if I try to get this running from MyEclipse, with all the magic incantations (environment variables for the -D fields, for example), I cannot get either the server or the client to work.  The error message for the server is:

ComputeEngine exception:
java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:1099 connect,resolve)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:374)
at java.security.AccessController.checkPermission(AccessController.java:546)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.SecurityManager.checkConnect(SecurityManager.java:1034)
at java.net.Socket.connect(Socket.java:524)
at java.net.Socket.connect(Socket.java:478)
at java.net.Socket.(Socket.java:375)
at java.net.Socket.(Socket.java:189)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:22)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:128)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:595)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:198)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:184)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:322)
at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
at engine.ComputeEngine.main(ComputeEngine.java:36)

This is apparently tied to the security policy settings.  My guess is that there is something rather magical about how MyEclipse is setting up the java.security.policy environment variable that explains the misbehavior: perhaps the use of backslashes in the DOS shell has to be done differently from MyEclipse.  I've tried a variety of different forms of this, without success.  It also looks like perhaps the security policy might require a URL, so I tried file:/// before the file name, without success.

Perhaps there is some way to force MyEclipse to show you what parameters it is passing to java when it executes?  

What is a bit annoying is that you can find vast numbers of questions on the Internet from developers running into exactly this same problem -- but real answers are surprisingly difficult to find.

No comments: