|
I'm not sure we can do this at the moment; Sun's RMI implementation
checks that each method exhibited by a Remote object has a "throws RemoteException" on it. I don't think we can declare a "throws" clause on a Scala method, and therefore we can't define a trait in Scala that can be exported and called remotely. That a trait can include code and method bodies would at first seem to be something of a benefit, as it provides an easy way to create a "smart proxy", in RMI-speak. In any case, the workaround is likely to be declaring the remote interface in Java, then having a Scala object extend that interface. RJ G:\Workspaces\Soletta\SPipe>scala -classpath bin com.soletta.spipe.Submit52 Exception in thread "main" java.lang.ExceptionInInitializerError at com.soletta.spipe.Submit52.main(Submit52.scala) Caused by: java.rmi.server.ExportException: remote object implements illegal rem ote interface; nested exception is: java.lang.IllegalArgumentException: illegal remote method encountered: p ublic abstract java.lang.String com.soletta.spipe.DMSubmit.submit(java.lang.Stri ng,java.lang.String,java.lang.String,byte[]) at sun.rmi.server.UnicastServerRef.exportObject(Unknown Source) at java.rmi.server.UnicastRemoteObject.exportObject(Unknown Source) at java.rmi.server.UnicastRemoteObject.exportObject(Unknown Source) at java.rmi.server.UnicastRemoteObject.<init>(Unknown Source) at com.soletta.spipe.Submit52$.<init>(Submit52.scala:5) at com.soletta.spipe.Submit52$.<clinit>(Submit52.scala) ... 1 more Caused by: java.lang.IllegalArgumentException: illegal remote method encountered : public abstract java.lang.String com.soletta.spipe.DMSubmit.submit(java.lang.S tring,java.lang.String,java.lang.String,byte[]) at sun.rmi.server.Util.checkMethod(Unknown Source) at sun.rmi.server.Util.getRemoteInterfaces(Unknown Source) at sun.rmi.server.Util.getRemoteInterfaces(Unknown Source) at sun.rmi.server.Util.createProxy(Unknown Source) ... 7 more package com.soletta.spipe; trait DMSubmit extends java.rmi.Remote { def submit(name: String, subject: String, docType: String, content: Array[byte]): String; def quit: unit; def getReport: String; def getSubmissions: int; } package com.soletta.spipe; import java.rmi.server.{UnicastRemoteObject,RemoteServer} object Submit52 extends UnicastRemoteObject(10100) with DMSubmit { val quitFlag = new Object var submissions = 0 def quit: unit = quitFlag synchronized { quitFlag.notify() } def getReport = "A-OK" def getSubmissions = submissions def submit(name: String, subject: String, docType: String, content: Array[byte]) = { val id = RemoteServer.getClientHost() Console.println("Received submit from " + id) id } def main(args: Array[String]): unit = { quitFlag synchronized { wait() wait(1000) } Console.println("Submit52 exit") } } |
|
I got to thinking about it, and figured that the way to implement this
would be to create a "remote" trait; about five minutes later I found "scala.remote", which does precisely what we want. For the record, here's how you create a remote trait: [remote] trait DMSubmit extends java.rmi.Remote { def submit(name: String, subject: String, docType: String, content: Array[byte]): String; def quit: unit; def getReport: String; def getSubmissions: int; } Nsc's JVM generator will automatically attach the "throws RemoteException" to each method in the interface, allowing it to pass the JVM's method checks during remote object exporting. Does it make sense to create a "throws" attribute that can generalize this a bit? [throws(IOException)] def readFile(fn: String): unit = { ... } Which brings me to another question...what's the best way in Scala to refer to a Class object? In Java I can refer to Remote.class, but in my Scala code I've been doing a Class.forName instead. Is there a better way? RJ |
|
Hi Ross:
Your questions are right up to the point. > Does it make sense to create a "throws" attribute that can generalize > this a bit? > > [throws(IOException)] def readFile(fn: String): unit = { ... } > > Absolutely. We are about to add this. > Which brings me to another question...what's the best way in Scala to > refer to a Class object? In Java I can refer to Remote.class, but in my > Scala code I've been doing a Class.forName instead. Is there a better > way? > We just added a better way of doing this: You now can write classOf[Remote] `classOf' is a new magic method in Predef. The Scala compiler will translate applications of classOf to class literals. On a jvm 1.5 target (enabled by scalac -target jvm-1.5) this will translate to a special byte code. On all other platforms this will translate to a cached call to Class.forName (i.e. the call will be performed only the first time you execute the instruction). Using these class literals, we could re-write the support for polymorphic arrays so that the problems with using mutliple classloaders that have been mentioned on the list should go away. All of this is in the nightly build, and will be in the next minor release. Cheers -- Martin |
|
In reply to this post by Judson, Ross
Judson, Ross wrote:
> I got to thinking about it, and figured that the way to implement this > would be to create a "remote" trait; about five minutes later I found > "scala.remote", which does precisely what we want. That's right. You can even attach it to specific methods (as it is done with method '$tag' in ScalaObject). Note that this attribute us interpreted only by the backend, so the type checker will not see that a remote class implements the marker interface java.rmi.Remote. > Does it make sense to create a "throws" attribute that can generalize > this a bit? > > [throws(IOException)] def readFile(fn: String): unit = { ... } This sounds like a good idea, especially in the context of pluggable types.. a custom type checker could even make use of them to enforce Java-semantics, if desired. The only downside I see is that this might not be portable to .NET (which can safely ignore them). It could also solve another problem reported by Sean some time ago: checked exception thrown from Scala code cannot be cought by Java code (the compiler will complain that the exception is never thrown in the body of try-catch). > Which brings me to another question...what's the best way in Scala to > refer to a Class object? In Java I can refer to Remote.class, but in my > Scala code I've been doing a Class.forName instead. Is there a better > way? Not with the current release, but the CVS version has a new way: 'classOf[T]'. You can us it like this: classOf[Array[Int]] to obtain the class of a given type. It will make it into the new release. Iulian |
|
In reply to this post by Judson, Ross
Hi Ross,
Yes it can be written entirely in Scala 2 :-) I've added a RMI client and slightly modified your code (cf. http://lamp.epfl.ch/~michelou/scala/submit52.tar.gz) to run your example; here is my shell session: lamp:~/submit52> make lamp:~/submit52> make runNS Name server was started on localhost lamp:~/submit52> make runServer lamp:~/submit52> make runClient com.soletta.spipe.Submit52Client$: A-OK lamp:~/submit52> make runClient com.soletta.spipe.Submit52Client$: A-OK lamp:~/submit52> make runClient ARGS=-quit lamp:~/submit52> Submit52 exit lamp:~/submit52> Regards --S. Micheloud Judson, Ross wrote: > I'm not sure we can do this at the moment; Sun's RMI implementation > checks that each method exhibited by a Remote object has a "throws > RemoteException" on it. I don't think we can declare a "throws" clause > on a Scala method, and therefore we can't define a trait in Scala that > can be exported and called remotely. That a trait can include code and > method bodies would at first seem to be something of a benefit, as it > provides an easy way to create a "smart proxy", in RMI-speak. > > In any case, the workaround is likely to be declaring the remote > interface in Java, then having a Scala object extend that interface. > > RJ > > > G:\Workspaces\Soletta\SPipe>scala -classpath bin > com.soletta.spipe.Submit52 > Exception in thread "main" java.lang.ExceptionInInitializerError > at com.soletta.spipe.Submit52.main(Submit52.scala) > Caused by: java.rmi.server.ExportException: remote object implements > illegal rem > ote interface; nested exception is: > java.lang.IllegalArgumentException: illegal remote method > encountered: p > ublic abstract java.lang.String > com.soletta.spipe.DMSubmit.submit(java.lang.Stri > ng,java.lang.String,java.lang.String,byte[]) > at sun.rmi.server.UnicastServerRef.exportObject(Unknown Source) > at java.rmi.server.UnicastRemoteObject.exportObject(Unknown > Source) > at java.rmi.server.UnicastRemoteObject.exportObject(Unknown > Source) > at java.rmi.server.UnicastRemoteObject.<init>(Unknown Source) > at com.soletta.spipe.Submit52$.<init>(Submit52.scala:5) > at com.soletta.spipe.Submit52$.<clinit>(Submit52.scala) > ... 1 more > Caused by: java.lang.IllegalArgumentException: illegal remote method > encountered > : public abstract java.lang.String > com.soletta.spipe.DMSubmit.submit(java.lang.S > tring,java.lang.String,java.lang.String,byte[]) > at sun.rmi.server.Util.checkMethod(Unknown Source) > at sun.rmi.server.Util.getRemoteInterfaces(Unknown Source) > at sun.rmi.server.Util.getRemoteInterfaces(Unknown Source) > at sun.rmi.server.Util.createProxy(Unknown Source) > ... 7 more > > [..] |
|
In reply to this post by Judson, Ross
Yes it can! Thanks for help. I now have a little RMI-based pair of Scala programs that will be performing transfers of documents from one Documentum system to another (of a previous version); the Scala code is interacting very nicely with the Documentum Java libraries. It does raise an interesting case; it would be nice to be able to adapt the dbc libraries to move away from ResultSet/java.sql and be a little more general. Documentum has "dql", which is quite a bit like sql but doesn't participate in Java's standard ResultSet etc.
Incidentally, another major way of doing remote calls on Java is to use the JMX protocols; Scala and JMX work just fine together already. There's no "throws RemoteException" with JMX remoting. I've got several Scala programs exhibiting mbeans, and they work very nicely. The only slightly ugly thing is that $tag method, which introspects as an operation under JMX (but can be filtered out). I have a short JMX wrapper that provides case classes for JMX introspection and makes it easy to pattern match against them. Once it's in a decent form I'll put it up on sbaz. RJ [inline] -----Original Message----- From: Stéphane Micheloud [mailto:[hidden email]] Sent: Wednesday, May 10, 2006 7:26 AM To: [hidden email] Subject: Re: Creating RMI traits Hi Ross, Yes it can be written entirely in Scala 2 :-) I've added a RMI client and slightly modified your code (cf. http://lamp.epfl.ch/~michelou/scala/submit52.tar.gz) to run your example; here is my shell session: lamp:~/submit52> make lamp:~/submit52> make runNS Name server was started on localhost lamp:~/submit52> make runServer lamp:~/submit52> make runClient com.soletta.spipe.Submit52Client$: A-OK lamp:~/submit52> make runClient com.soletta.spipe.Submit52Client$: A-OK lamp:~/submit52> make runClient ARGS=-quit lamp:~/submit52> Submit52 exit lamp:~/submit52> Regards --S. Micheloud Judson, Ross wrote: > I'm not sure we can do this at the moment; Sun's RMI implementation > checks that each method exhibited by a Remote object has a "throws > RemoteException" on it. I don't think we can declare a "throws" > clause on a Scala method, and therefore we can't define a trait in > Scala that can be exported and called remotely. That a trait can > include code and method bodies would at first seem to be something of > a benefit, as it provides an easy way to create a "smart proxy", in RMI-speak. > > In any case, the workaround is likely to be declaring the remote > interface in Java, then having a Scala object extend that interface. > > RJ > > > G:\Workspaces\Soletta\SPipe>scala -classpath bin > com.soletta.spipe.Submit52 > Exception in thread "main" java.lang.ExceptionInInitializerError > at com.soletta.spipe.Submit52.main(Submit52.scala) > Caused by: java.rmi.server.ExportException: remote object implements > illegal rem ote interface; nested exception is: > java.lang.IllegalArgumentException: illegal remote method > encountered: p > ublic abstract java.lang.String > com.soletta.spipe.DMSubmit.submit(java.lang.Stri > ng,java.lang.String,java.lang.String,byte[]) > at sun.rmi.server.UnicastServerRef.exportObject(Unknown Source) > at java.rmi.server.UnicastRemoteObject.exportObject(Unknown > Source) > at java.rmi.server.UnicastRemoteObject.exportObject(Unknown > Source) > at java.rmi.server.UnicastRemoteObject.<init>(Unknown Source) > at com.soletta.spipe.Submit52$.<init>(Submit52.scala:5) > at com.soletta.spipe.Submit52$.<clinit>(Submit52.scala) > ... 1 more > Caused by: java.lang.IllegalArgumentException: illegal remote method > encountered > : public abstract java.lang.String > com.soletta.spipe.DMSubmit.submit(java.lang.S > tring,java.lang.String,java.lang.String,byte[]) > at sun.rmi.server.Util.checkMethod(Unknown Source) > at sun.rmi.server.Util.getRemoteInterfaces(Unknown Source) > at sun.rmi.server.Util.getRemoteInterfaces(Unknown Source) > at sun.rmi.server.Util.createProxy(Unknown Source) > ... 7 more > > [..] |
|
In reply to this post by Judson, Ross
Great! classOf[T] will clean up the Class.forname calls. I'll update
my Scala source and clean up my JMX code. Some random thoughts: - The latest scalac.bat works under cmd.exe but doesn't work under 4nt (which I have trouble living without). I'll see if I can figure out the simplest patch to have it work under both. - Perhaps sbaz should adapt some of the Webstart element definitions to create a "run" script automatically, if desired. As sbaz gets bigger, placing all the JARs on the classpath is going to become progressively less practical and will need to be replaced with a different mechanism. - A small set of standard attribute classes that can be used to characterize methods might be useful for organization of Scala code. -----Original Message----- From: martin odersky [mailto:[hidden email]] Sent: Wednesday, May 10, 2006 3:46 AM To: Judson, Ross Cc: [hidden email] Subject: Re: Creating RMI traits Hi Ross: Your questions are right up to the point. > Does it make sense to create a "throws" attribute that can generalize > this a bit? > > [throws(IOException)] def readFile(fn: String): unit = { ... } > > Absolutely. We are about to add this. > Which brings me to another question...what's the best way in Scala to > refer to a Class object? In Java I can refer to Remote.class, but in > my Scala code I've been doing a Class.forName instead. Is there a > better way? > We just added a better way of doing this: You now can write classOf[Remote] `classOf' is a new magic method in Predef. The Scala compiler will translate applications of classOf to class literals. On a jvm 1.5 target (enabled by scalac -target jvm-1.5) this will translate to a special byte code. On all other platforms this will translate to a cached call to Class.forName (i.e. the call will be performed only the first time you execute the instruction). Using these class literals, we could re-write the support for polymorphic arrays so that the problems with using mutliple classloaders that have been mentioned on the list should go away. All of this is in the nightly build, and will be in the next minor release. Cheers -- Martin |
|
"Judson, Ross" <[hidden email]> writes:
> - Perhaps sbaz should adapt some of the Webstart element definitions to > create a "run" script automatically, if desired. As sbaz gets bigger, > placing all the JARs on the classpath is going to become progressively > less practical and will need to be replaced with a different mechanism. Automatic definition makes sense if your infrastructure has the information already. However, this is such a small problem that surely it is not by itself reason to add new infrastructure? If you have a performance problem from all the jars, it seems better to arrange to list the jars explicitly. Previous versions of the ant task allowed this, the current version does not, and it could come back again if there is a demand.... -Lex |
|
In reply to this post by Judson, Ross
Judson, Ross wrote: > Great! classOf[T] will clean up the Class.forname calls. I'll update > my Scala source and clean up my JMX code. > > Some random thoughts: > > - The latest scalac.bat works under cmd.exe but doesn't work under 4nt > (which I have trouble living without). I'll see if I can figure out the > simplest patch to have it work under both. Can you be more precise about your problem using the tool 4nt (http://www.jpsoft.com/) ? I works fine for me (cf. attached screen dump) ! > > [..] > Regards --S. Micheloud |
| Powered by Nabble | Edit this page |
