Quantcast

Creating RMI traits

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Creating RMI traits

Judson, Ross
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")
  }
}
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

RE: Creating RMI traits

Judson, Ross
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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Creating RMI traits

Martin Odersky
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

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Creating RMI traits

Iulian Dragos-2
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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Creating RMI traits

Stéphane Micheloud
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
>
> [..]
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

RE: Creating RMI traits

Judson, Ross
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
>
> [..]
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

RE: Creating RMI traits

Judson, Ross
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

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Creating RMI traits

Lex Spoon
"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

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Creating RMI traits

Stéphane Micheloud
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

scala4nt.jpg (61K) Download Attachment
Loading...