• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

RMI from start to finish

 
High Plains Drifter
Posts: 7289
Netbeans IDE VI Editor
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
As luck would have it, I am teaching a Jini course for Sun this week, in Columbia, Maryland. I'm far from home, there's no baseball, and despite all the babes I could easily score in Georgetown, I've opted to stay in my hotel, practice my tai chi (since I suck at it), and write an RMI tutorial.
I'm going to write code pieces and advisory comments as I go; feel free to throw in comments, except "it's cool that you are doing this!" You'll break my concentration.
Given the interactive nature of this experiment (i.e., total lack of a plan), I will not edit posts except for broken code and lousy narratives. I'll put rewrites in a new post so we can all watch the evolution. Please feel free to post alternative post if you feel like jumping in, making sure to give me full credit if your stuff is better than mine.
I should have the first post up around 4 pm JavaRanch time. Topic: overview of the whole thing.
 
Ranch Hand
Posts: 65
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hi Micheal,
do add somehing that usually people dont cover..like client authorisation/authentication...activation...and if you could explain RMI with the help of a basic decompiled stub then that would be great....
regards
-Mandan
 
Michael Ernest
High Plains Drifter
Posts: 7289
Netbeans IDE VI Editor
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok! Only two (three?) days late on my deadline. Sorry 'bout that. But here goes.
I'm going to encourage you all to follow along if you like, and to that end, I want to start with file system layout. We're going to be writing an RMI server that accepts a java.lang.Runnable implementation from its client. The client is going to choose one of several Runnable things at runtime, and ask the server to process it. That is, at compile-time, the only thing Client and Server will have agreed to is that the server will accept a Runnable from the client, and return the Runnable after it has been processed.
The concept we're exploring here is the notion of mobile code, sometimes called agents. From the point of view of the client and server programs, the code that will be executed is arbitrarily chosen; all they know is that the code itself is Runnable.
It's going to be and that's an order! But to get to , we need to lay out files to clarify two things: 1) CLASSPATH and 2) true "remote" behavior. Also, I'm working on a Solaris box and darn proud of it, so your sort will have to transliterate to your environments as necessary.
Directory layout. I'm building from a structure like this:
/$HOME/mfe ------- package names will start with mfe; my compiled classes will go here
/$HOME/src ------- source code repository
/$HOME/sdocroot -- server's HTTP document root
/$HOME/cdocroot -- client's HTTP document root
/$HOME/tmp ------- 'well-known' point to start rmiregistry
One reason I separate source and classes is to make our command-line invocation simpler, e.g.:

The packages I'll want to import (other than JDK stuff) will have a common top-level directory in the $HOME directory. Any JAR files I'd use from third parties would also go here to keep the compiler's classpath argument simple. So no matter where I am compiling from, the .class files end up in one place.
We won't need two full-blown web servers, as the directory entries suggest. We just need a way to deliver class files over HTTP; we'll explain why later. And when we do explain, we'll take a fun little side trip: how to write a tiny, dedicated web server that just returns class files.
You don't really need a $HOME/tmp directory either; I like to make things really clear, including the directory from which rmiregistry gets launched. This is an academic point, but I want to make sure everyone knows where rmiregistry is; it's important. In so doing, we'll also have another side-trip into classloader behavior.
While we're at it, you might as well create the following directories under $HOME/src:
mfe/services -- any interfaces that extend Remote
mfe/servers --- any implementations of services interfaces
mfe/clients --- users of services
mfe/agents ---- objects to run between clients and servers
 
Leverager of our synergies
Posts: 10065
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Ok, Ok, but... Michael, what are prerequisites for your tutorial? Is it for absolute beginners, or I must already be crazy with RMI? What if I am only a poor Russian woman? Will you make me think? Can I ask questions? I am even not sure I need this RMI thing in my household. I see that you want to process my Runnable. But why do I need my Runnable to be processed? You are starting a game and I do not know who all players are... Agents, clients, servers... Do they all want to execute my code? It's so intimidating...
 
Michael Ernest
High Plains Drifter
Posts: 7289
Netbeans IDE VI Editor
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I see someone snuck past the guard. Oh well, now that the questions have been asked:
MI: Michael, what are prerequisites for your tutorial?
ME: A desire to learn, honey.
MI: Is it for absolute beginners, or I must already be crazy with RMI?
ME: Yes.
MI: What if I am only a poor Russian woman?
ME: Depends; what magazines have you posed for?
MI: Will you make me think?
ME: I'm a teacher, not a miracle worker.
MI: But why do I need my Runnable to be processed?
ME: If you have to ask, you're too young to hear the answer.
MI: You are starting a game and I do not know who all players are... Agents, clients, servers... Do they all want to execute my code?
ME: Kids today sure have some interesting euphemisms. Some types, agents in particular, will execute any code they can get their hands on, so keep your eyes open and stay in well-lit areas.
MI: It's so intimidating...
ME: SOAP is easier, but you don't see anyone offering a free tutorial for that around here, do ya?
 
Michael Ernest
High Plains Drifter
Posts: 7289
Netbeans IDE VI Editor
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Writing a service is sometimes hard design work, but easy writing work, so we'll start by describing what a service is.
Services (or remote services, if you wish) are just interfaces that observe two rules. One, they each extend the java.rmi.Remote interface; two, each method in them says it throws, at a minimum, java.rmi.RemoteException.
That's right, services extend the Remote interface; we want to extend the Remote interface (i.e., add to its methods), not implement it. In this context, the extends keyword lets us do that. Cool, huh? Also, the Remote interface is a tag; it has no methods in it, but rather lets our Java tools recognize it as something that will be called on from elsewhere. It wouldn't make much sense to be forced to implement an empty interface, would it?
Forcing methods to throw RemoteException is a way of making us acknowledge the inherent "unreliability" of networks and distributed programs. All sorts of things can go wrong: clients can blink for too long, servers can cough, routers might bounce, even network cable or adapter cards can poop out now and then. Compared to the CPU, which might chug away for years and year executing hundreds of millions of instructions every sec, the network looks like clumsy, fault-ridden trasnportation at best. Programs that might make use of more than one machine should express an awareness of that condition, or at least Java's RMI group thinks they should.
But reading the explanation is more work than writing out the requirements, isn't it?

Easy! So a SomeService thing will be remote, or remotely available, meaning some application on another VM would be able to call getMessage() after getting a special type reference to this object know as a remote stub. We'll have more to say about that at the proper time.
For now, let's concentrate on designing the interface properly. What we have above isn't wrong, but in our haste to write something out, we haven't asked if a String message from another application is what our client really wants. It sounds nice, but it's a baby step to something more interesting, so we're going to pass on it for now.
What our client really wants to do is pass an object to a remotely available service, have the service process it, then receive the finished product back. So we're going to do this instead:

Now it's going to be interesting! Our client will have an instance of some Runnable thing, send it off to a Processor-defined service, and get it back -- only now the run() method has been executed for us.
Runnable itself is just another interface, so we still don't know what exactly is being executed. There's no code, no instructions to point to. All we've done is describe a way for a client to execute a Runnable on a remote machine. If you give this some thought, you'll realize that a Runnable thing can do just about anything it wants -- just so long as it's defined via a run() method. That doesn't eliminate very much. We only have to implement run(), and these two separate processes can share work.
The key to making this work; both client and server programs have to "know" this interface at compile-time. But big deal, we put up with that much every time we scan documentation for methods we can call some new (to us) kind of object. No big deal at all.
Questions so far?
[ January 31, 2002: Message edited by: Michael Ernest ]
 
Mapraputa Is
Leverager of our synergies
Posts: 10065
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Services (or remote services, if you wish) are just interfaces that observe two rules.
What? Just two rules? No moral obligations? They weren't even taught good manners? I felt they are unreliable...
That's right, services extend the Remote interface; we want to extend the Remote interface (i.e., add to its methods), not implement it. In this context, the extends keyword lets us do that. Cool, huh?
That's very cool, my tiger. But what's wrong with implementing the Remote interface? You said that services are interfaces, now you add that they must extend the Remote interface. Cannot they be classes that implement Remote? Classes also can have methods that weren't defined in implementing interface. Of course, you cannot call these methods if you use a reference of interface type... Oh, I see. You cannot define methods to be run in the Remote interface because you do not know in advance what they are and you do not want to know, but you still need to mark objects that can be called remotely. Making them of interface type that extends Remote satisfies both requirements. We could extend some class instead, but then we would have no chance to inherent something good from our other potential ancestors. It would be too sad. Am I right here?
Also, the Remote interface is a tag; it has no methods in it, but rather lets our Java tools recognize it as something that will be called on from elsewhere. It wouldn't make much sense to be forced to implement an empty interface, would it?

Mmm... It may be not so bad. You do not have to do any actual job, yet you get a nice-sound, very respectable title. People will call you Mr. Remote... And they will even treat you as if you were somebody important! On the other hand... What if I do not want this honor? If I want to continue my quiet lonely life? If I do not say I am Mr. Remote, they cannot bother me, or can they?
What our client really wants to do is pass an object to a remotely available service, have the service process it, then receive the finished product back.
I feel that you are trying to hide something from me, sunshine. Earlier you mentioned some darn Solaris box, so... Say, I need to darn a sock. You are saying you got a very big new machine to do the job. I can send you a sock and have darned thing back, but instead, what you suggest is "come to my place, honey, it will be fun, I promise, and yes, you can darn your sock on my new cool machine too". How you deal with my Runnables... um, Darnables really, makes me think you have the second variant in mind
Now it's going to be interesting! Our client will have an instance of some Runnable thing, send it off to a Processor-defined service, and get it back -- only now the run() method has been executed for us.
But of course! It's very interesting! How can I know that you did not do any harm to my Darnables I so credulous sent to you? You *can* harm them, cannot you, Mr. Remote?
 
Ranch Hand
Posts: 104
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Michael,
I like what you are doing, and I am very much interested in using this and learning RMI. But I dont have a Unix box, I have very feeble idea about UNIX, so the initial steps, would you be able to shed some hints about how to use in winNT machine.
Thanks
Nasser
[ January 31, 2002: Message edited by: Nasser Aboobaker ]
[ January 31, 2002: Message edited by: Nasser Aboobaker ]
 
Michael Ernest
High Plains Drifter
Posts: 7289
Netbeans IDE VI Editor
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Q. What's wrong with implementing the Remote interface?
A. I hope the answer to that will become evident in a couple more posts. But there is something wrong with it.
Q. I feel that you are trying to hide something from me, sunshine.
A. Like what, moonlight?
Q. But of course! It's very interesting! How can I know that you did not do any harm to my Darnables I so credulous sent to you? You *can* harm them, cannot you, Mr. Remote?
A. Mr. Remote is dangerous but under control. Fear not, and come stand near, real close.
 
Sheriff
Posts: 9109
12
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Michael Ernest:
... the Remote interface is a tag; it has no methods in it, but rather lets our Java tools recognize it as something that will be called on from elsewhere.


So the Remote interface is similar to the Cloneable and Serializable interfaces. It's just a tag?
 
Mapraputa Is
Leverager of our synergies
Posts: 10065
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Michael Ernest:
Now it's going to be interesting! Our client will have an instance of some Runnable thing, send it off to a Processor-defined service, and get it back -- only now the run() method has been executed for us.


Looks like Visitor pattern... Not quite... Need more details.
--------------------
Sun Certified Programmer for the Java™ 2 Platform
[ February 01, 2002: Message edited by: Mapraputa Is ]
 
Michael Ernest
High Plains Drifter
Posts: 7289
Netbeans IDE VI Editor
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
That's right, java.rmi.Remote is a tagging interface. This is from javadoc:

The Remote interface serves to identify interfaces whose methods may be invoked from a non-local virtual machine. Any object that is a remote object must directly or indirectly implement this interface. Only those methods specified in a "remote interface," an interface that extends java.rmi.Remote are available remotely.


So the documentation appears to say you can directly implement this interface. As far as the compiler is concerned, that's correct. However, what exactly do you get for your trouble? No methods; ergo, no actual "remote" behavior.
------------------------------------------------
Visitor designs separate layers of functionality from each other so that one function can be changed without kiboshing the program that layer supports. In our case, we're separating the processing of code from the machine destined to process it.
Our model, in one sense, makes the target (server) arbritrary; we'll be able to choose a machine that hosts the service we want. However, it also makes the source (client) arbitrary; our code may start in any program that understands our service protocol. If we were ambitious, we could create an agent that actually tours a series of programs, each with different service criteria, all of which our agent understands. THAT'S some real visiting going on, but it's also a couple steps ahead of where we're planning to go. Maybe for the next tutorial.
[ February 01, 2002: Message edited by: Michael Ernest ]
 
Michael Ernest
High Plains Drifter
Posts: 7289
Netbeans IDE VI Editor
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok, time to describe a service implementation, or what I am calling a server. We made our class a Remote thing at compile time; now we have to make it remotely available for run time. That's accomplished in two steps; first, by exporting the service object; and second, by making it easy to find for remote clients. We do that by binding to a facility known as a lookup service.
This is easy coding work. We use a class in java.rmi.server called UnicastRemoteObject, which is a concrete subclass of RemoteServer. Probably the best way for a beginner to use it is by subclassing it; that way, UnicastRemoteObject assures us that our "remote semantics" will be proper. We could instead use its static method exportObject(Remote rem), and save our one bite at inheritance. We'd then have to implement remote semantics ourselves, which boils down to overriding hashCode(), equals(), and toString() correctly. I don't want to explain what that's about anytime soon, so for now we subclass.
Review the hierarchy for UnicastRemoteObject. You'll discover that through this class we can get the names of clients that contact us as well as retrieve and set the stream of calls reported by the RMI subsystem. (Go! Find 'em! I'm not doing all the work around here...)

This is stripped down to the bone for now, and I'm using dots to get lines spaces out of UBB's CODE tag format. But that's the gist of the server. Note that the work of exporting the object is actually handled by UnicastRemoteObject's constructor, so that part is done. We still need to bind to a lookup service, and I want to say a little more about this, because the code I'm showing below hides a bunch o' stuff. Here's the code fragment for now, for those of your interested in investigating on your own:

[ February 05, 2002: Message edited by: Michael Ernest ]
 
Marilyn de Queiroz
Sheriff
Posts: 9109
12
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Michael Ernest:
This is stripped down to the bone for now, and I'm using dots to get lines spaces out of UBB's CODE tag format.

I'll have some questions shortly, but you don't need dots to get blank lines. Just make sure you have at least one space on the blank line to hold the line open.


5 spaces on line between line1 and line2
No spaces (I just hit enter twice) between line2 and line3. See the difference?
 
Marilyn de Queiroz
Sheriff
Posts: 9109
12
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Michael Ernest:
While we're at it, you might as well create the following directories under $HOME/src:
mfe/services -- any interfaces that extend Remote
mfe/servers --- any implementations of services interfaces
mfe/clients --- users of services
mfe/agents ---- objects to run between clients and servers


So now we have
$HOME/src/mfe/services
$HOME/src/mfe/servers
$HOME/src/mfe/clients
$HOME/src/mfe/agents

or is there a typo in here?
 
Marilyn de Queiroz
Sheriff
Posts: 9109
12
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Originally posted by Michael Ernest:
In our case, we're separating the processing of code from the machine destined to process it.


I'm not sure I follow what you're saying here. We're separating the processing from the machine?

We're separating the two machines that each do their own processing?

I understand the part about the client being independent of the server and vice-versa.
[ February 01, 2002: Message edited by: Marilyn deQueiroz ]
 
Michael Ernest
High Plains Drifter
Posts: 7289
Netbeans IDE VI Editor
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Marilyn deQueiroz:
I'm not sure I follow what you're saying here. We're separating the processing from the machine?

We're separating the two machines that each do their own processing?


Not exactly. What I'm trying to say is that the client and server will be passing a program back and forth. The client will know in advance "what kind" of program it is (something that implements Runnable), but it will not know what instructions make up that program. It will then ask the server to process the code it found, and send back the results.
By "separation from the machine" I was trying to convey the notion that neither side knows at compile time what this "mobile code" wants to do; they'll only know that it's got a method run() in it. Intriguing idea, don't you think?
 
Marilyn de Queiroz
Sheriff
Posts: 9109
12
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
So the client sends an object (in this case a Runnable object) to the server and the server does something with that object and sends back another (different?) Runnable object, right? How can you send a "program" back and forth? (Sorry to be so dense)
[ February 01, 2002: Message edited by: Marilyn deQueiroz ]
 
Michael Ernest
High Plains Drifter
Posts: 7289
Netbeans IDE VI Editor
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
To your first question, second part, yes and no. In sending the Runnable back and forth, we're going the change the state of the object; the behavior (program instructions) is what it is.
So we will get a 'different' object back. Now if we have a method signature like this:
public void Runnable execute(Runnable run) {...}
and we use two different references for the Runnable, then yes, we end up with a before and after object. But if our usage is:
runner = execute(runner);
then it's as if we just called a regular method and got back an 'updated' value.
As to the second question, the easiest answer for now is: you just can. That's what I'm trying to show. If I focus on justifying how it's done, instead of just doing it, this'll take a lot longer. Just wait, and you'll see all in the end, ok?
 
Marilyn de Queiroz
Sheriff
Posts: 9109
12
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
:roll: Ok, I'll try to be more patient.
 
Michael Ernest
High Plains Drifter
Posts: 7289
Netbeans IDE VI Editor
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ok, now we want to compile what we've written to date -- the includes the server interface and the service implementation. That could go something like this. In these examples, the environment variable $HOME is equivalent to the path /export/home/mfernest

The class files for these two will end up in $HOME/mfe/services and $HOME/mfe/servers, respectively. Using Workhorse.class, we also need to generate a stub, an object will act as a client-side proxy to the Workhorse object on the server side. This is done through rmic, a tool that's bundled with the JDK. All it does is generate and compile stub code, which we can inspect if we like:

Worth noting:
  • The argument is a class name, not a file
  • -keep keeps rmic from deleting the source file
  • -v1.2 keeps this a Java 2-only implementation

  • Browse through the sub source code if you wish; if you're unfamiliar with Java's Reflection facilities, though, it may be difficult to interpret. In that case, run rmic without with -v1.2 flag. This will generate Stub (client-side) and a Skeleton (server-side) class files. This is necessary with JDK 1.1.x; it might be easier to read, and of course it does about the same thing.
    We'll pause here for questions, then go on to talk about what UnicastRemoteObject "really is," and how a lookup service helps us make such things network-available.
    [ February 05, 2002: Message edited by: Michael Ernest ]
     
    Mapraputa Is
    Leverager of our synergies
    Posts: 10065
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    We should probably let you say all you need to say, and then we can attack you with our questions.
     
    Marilyn de Queiroz
    Sheriff
    Posts: 9109
    12
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    $ cd $HOME/src/mfe/services
    $ javac -d $HOME -classpath $HOME Process.java


    Wait! I'm . Is the name of the class Process.java or Processor.java?

    Also, Workhorse.java doesn't compile because the process() method doesn't have a return statement (returning a Runnable).
    This means I can't do the rmic thing because I don't have a Workhorse.class to rmic on.
    [ February 05, 2002: Message edited by: Marilyn deQueiroz ]
     
    Michael Ernest
    High Plains Drifter
    Posts: 7289
    Netbeans IDE VI Editor
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Thanks, Marilyn, I've corrected the posts. The correct source file name is Processor.java, and the method in Workhorse.java now includes a return statement. I've also made some modifications to the rmic invocation line so that everything ends up in the right place.
    [ February 05, 2002: Message edited by: Michael Ernest ]
     
    Marilyn de Queiroz
    Sheriff
    Posts: 9109
    12
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Seems to be much better now. What's next?
     
    Mapraputa Is
    Leverager of our synergies
    Posts: 10065
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    "I once saw a titan darning socks. It was his first titanic effort."
    Stanislaw Jerszy Lec, "Unkempt Thoughts".
    Never mind, just trying to keep you motivated
     
    Marilyn de Queiroz
    Sheriff
    Posts: 9109
    12
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Why does the default constructor need to throw RemoteException?
     
    Michael Ernest
    High Plains Drifter
    Posts: 7289
    Netbeans IDE VI Editor
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    tch tch, Marilyn, you haven't tried compiling without it?
    [ February 06, 2002: Message edited by: Michael Ernest ]
     
    Marilyn de Queiroz
    Sheriff
    Posts: 9109
    12
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I'm not at home now to try it. I'll try it as soon as I can. :roll:
     
    Michael Ernest
    High Plains Drifter
    Posts: 7289
    Netbeans IDE VI Editor
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    This last Q&A is a reminder that I need to plan out the next few points I want to make so I remember where I want to go. Probably doesn't help my focus that I'm writing this installment while sitting in an XML class (hee hee).
    Anyway: guess what happens when you export a Remote object? Correct! the object is made automagically network-available; it gets a ServerSocket for starters, and acquires a socket factory to deal with incoming clients. The system by default chooses a server port for you, but you can specify the port if you want. Then you could hardcode your client with the proper machine name and port, and start a remote conversation right then and there!
    Well, sort of. We've said our client will be aware at compile time of the Processor interface, and therefore knows how Processors behave. Our client, however, knows nothing about Processor implementations and their state model. We have to learn that dynamically if we're going to speak correctly to an actual Workhorse. So we need us some state data, which of course will have to be serialized and sent to us over the wire. We'll also need the class file so we can cast the deserialized data back to the proper form. This second piece is what the Remote object stub does for us.
    We could ease this requirement by placing the stub in the client's run-time classpath, but that's not fun. The larger point is, we don't really want to hardcode our client if we don't have to. Flexible is better; compiling once is what it's all about.
    RMI was designed to help us hide our ignorance of where services might live. We would rather use a lookup service, or name-for-service translator, and relax our need to know these things at compile-time. Furthermore, a well-named lookup might do a better job of suggesting a service's uses. When we want a service, the argument goes, we usually know what capability we're looking for (like Processor), but we don't always know the exact implementation name it goes by (Workhorse). A lookup service supported by thoughtful naming can save us a LOT of tedious searching.
    So, what do we need? Three things:
    1) A way to pass serialized object data to a client
    2) A way to pass that data's class file to a client
    3) A lookup service to help us find the live remote object's location.
    As it turns out, our lookup service, rmiregistry, handles 1) and 3) both. For 2), however, we need a file transfer sumpn-or-other. Our tool of choice here is HTTP: a web server.
    Not everyone knows how to set a webserver up -- I'm continually surprised how many people have never had to do it. And the good news is, you won't have to learn Apache or the like here if you don't want. I'll walk you setting up a very simple, very lightweight tool to do this. So before we can set up the registry, we'll take a side trip through establishing an HTTP-based class file server. But before we do that, any questions on the concepts?
    [ February 06, 2002: Message edited by: Michael Ernest ]
     
    Mapraputa Is
    Leverager of our synergies
    Posts: 10065
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Ernest, when you instantiate your Workhorse as
    Remote process = new Workhorse();
    shouldn't you catch RemoteException?
    (trying to revenge you for writing RMI tutorial sitting in XML class )
    MdQ:
    Why does the default constructor need to throw RemoteException?
    MI: I bet superclass' constructor throws this exception, so all subclass constructors must declare it.
    Yes!
    Here Subclass' constructors cannot catch it, because a call to a superclass' constructor must be the first statement, so they have no other choice but to declare it.
    [ February 06, 2002: Message edited by: Mapraputa Is ]
     
    Michael Ernest
    High Plains Drifter
    Posts: 7289
    Netbeans IDE VI Editor
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Yes, you do need to handle RemoteException in the code piece above, along with a few other exceptions. I showed this piece as a quick-and-dirty example, which by my standards means "won't compile, but gives you a peek." We have two more steps to go before we're ready to write complete client code, but when we do we'll fix this up.
    [ February 06, 2002: Message edited by: Michael Ernest ]
     
    Marilyn de Queiroz
    Sheriff
    Posts: 9109
    12
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    So, what do we need? Three things:
    1) A way to pass serialized object data to a client
    2) A way to pass that data's class file to a client
    3) A lookup service to help us find the live remote object's location.


    So the serialized data that you are passing is not contained in the fields of the class that you are passing?

    (Thanks, Map)
     
    Michael Ernest
    High Plains Drifter
    Posts: 7289
    Netbeans IDE VI Editor
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Marilyn deQueiroz:

    So the serialized data that you are passing is not contained in the fields of the class that you are passing?


    Good question. Answer: it will be, eventually. When we transfer a stub class to the client, we are not treating it as an object. It's just a file. By default, the client receives and keeps an in-memory copy of this file. By itself, it does not necessarily have the same state as the object we bound to the registry, and in fact we don't want to assume that. We use it instead only to make a Class object of Workhorse_Stub. Using this Class, we can then deserialize the state data we receive from rmiregistry.
    I'm working on an example to show that an object bound to a lookup service has its own (serialized) state, not one that evolves with the server object itself. It's a tangent, though, so for now I ask you to accept this at face value.
    [ February 07, 2002: Message edited by: Michael Ernest ]
     
    Marilyn de Queiroz
    Sheriff
    Posts: 9109
    12
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Ok. So the client has the Remote interface, the stub of the RemoteObject and the LookupService.

    The server has the implementation of the interface (the RemoteObject) and ...
     
    Mapraputa Is
    Leverager of our synergies
    Posts: 10065
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Michael Ernest:
    RMI was designed to help us hide our ignorance of where services might live. We would rather use a lookup service, or name-for-service translator, and relax our need to know these things at compile-time. Furthermore, a well-named lookup might do a better job of suggesting a service's uses. When we want a service, the argument goes, we usually know what capability we're looking for (like Processor), but we don't always know the exact implementation name it goes by (Workhorse). A lookup service supported by thoughtful naming can save us a LOT of tedious searching.


    Do not you mix up two levels of indirectness here? "Interface - implementation" (Processor - Workhorse in your case) is an inherent virtue of Java, the OO language, itself, whereas RMI lookup service in my understanding is built on top of Java. Its "service" concept is more generic than low-level "Java interface". Here is your example:
    public static void main(String args[]) {
    String serviceName = "Process server";
    Remote process = new Workhorse();
    Naming.rebind(serviceName, process);
    }
    should we then request a service by artificial "Process server" name, or by the name of the existent Processor interface?
    If we do not need to know interface name, maybe your quote above would be better as:
    "Furthermore, a well-named lookup might do a better job of suggesting a service's uses. When we want a service, the argument goes, we usually know what capability we're looking for (like Process server), but we don't always know the exact implementation name it goes by (Processor)."
    Or did I misunderstand you?
    [ February 07, 2002: Message edited by: Mapraputa Is ]
     
    Sheriff
    Posts: 17644
    300
    Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Mapraputa Is:
    If we do not need to know interface name, maybe your quote above would be better as:
    "Furthermore, a well-named lookup might do a better job of suggesting a service's uses. When we want a service, the argument goes, we usually know what capability we're looking for (like Process server), but we don't always know the exact implementation name it goes by (Processor)."


    If I may interject...
    I think we do need to know the interface name because the client code would be something like:

    What I don't quite understand is why process() needs to return a Runnable object. Couldn't we just change the state of the Runnable object that was passed in on invocation? Is this also a valid approach or are there disadvantages?
    Junilu
     
    Mapraputa Is
    Leverager of our synergies
    Posts: 10065
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I think we do need to know the interface name because the client code would be something like:

    cannot we use reflection (newInstance() and invoke() )instead?
    [ February 07, 2002: Message edited by: Mapraputa Is ]
     
    Michael Ernest
    High Plains Drifter
    Posts: 7289
    Netbeans IDE VI Editor
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Junilu Lacar:

    What I don't quite understand is why process() needs to return a Runnable object. Couldn't we just change the state of the Runnable object that was passed in on invocation? Is this also a valid approach or are there disadvantages?


    Another good question. So here's the deal: we're sending off a Runnable object as a parameter via the method process(). One of two things can happen to a parameter in a remote call:
    1) if the parameter is 'local-only,' the object gets serialized and sent over the wire; it is deserialized on the server side and exists apart from the client's copy.
    2) if the parameter is itself Remote, a stub gets sent in its place. The server "thinks" it is calling a local parameter, but in fact it only has a remote reference to the object residing on the client.
    We're doing 1) right now. 2) comes later.
    Pass-by-value semantics says the calling reference and called reference should point to the same thing in memory, but this is true when caller and called are sharing one process space (i.e., memory model). Here, they aren't. More on that later.
    To sum that up, if we don't return a Runnable thing, we'll never see the changes that got made to the Runnable we sent.
     
    Michael Ernest
    High Plains Drifter
    Posts: 7289
    Netbeans IDE VI Editor
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Mapraputa Is:

    cannot we use reflection (newInstance() and invoke() )instead?


    Mmm, I'm not sure I'm answering the question you're asking, but here goes: Naming.lookup() is going to return a Remote reference. We need to cast that back to the appropriate interface to get the behavior we started out wanting, which requires a compile-time knowledge of the interface. I don't believe Reflection can get us around that.
    [ February 07, 2002: Message edited by: Michael Ernest ]
     
    reply
      Bookmark Topic Watch Topic
    • New Topic