Is there a convenient way to transmit an object including its code (the class) over a network (not just the instance data)?
Don't ask me why I want to do this. It's in an assignment. I asked several times if that is really what they meant and the didn't rephrase their answer so I guess they really want us to transmit code (not just the field data) over a network. To be honest I have no clue why we need a Proxy in this assignment anyway, just writing a simple class would do IMO. The assignment says that we should instantiate the proxy on the server and transmit it to the client (and yes, they talk about a java.lang.reflect.Proxy, they name this class). Because there is no class file for a proxy I can't deploy that. I guess I would have to somehow read out the bytecode of the generated Proxy, transmit it to the client and then load it. Which makes absolutely no sense at all, but this seems what they want us to do. I don't get why.
This is the core value proposition of the Apache River project (formerly known as Jini when it was run by Sun).
You put the code you need to run remotely in a jar on a "codebase" http server and publish your proxy to a lookup server. River annotates that proxy (which is a serialized instance) with the codebase URL(s). When a client fetches that proxy from the lookup server and instantiates it, the codebase jars are used in a sandboxed classloader. It's common to create "smart proxies" which load a bunch of code to run on the client to manage communication back to the source service, or you can use a simpler proxy to just make RMI calls.
The technology encapsulated by River is complicated, but profound.
Related
I have a hard time understanding codebase in Java RMI. I'm supposed to download a class from the Client to use it on the server side. I'm not really sure how to understand that. Is the point to create an object on the Server side that is not distributed ? Because when I have distributed objects I never needed to use codebase and yet the Server didn't have the classes. But then why would the classes be in the codebase and not in Server classpath ? Does it have anything to do with interfaces ?
So basically I really don't get in what type of case would I need to do that.
If the classes were only located in the codebase, I would find it easier to understand, but it appears that the classes are also in the client classpath which is very confusing.
And then, what does codebase look like anyway ? I couldn't find a single visual representation that I could replicate.
I've got a java web server and I made it so that the server will respond to a certain a http* request by sending back a java object that contains a "execute" method.
I'd like to be able to execute a remote object's method.
I can't use reflection because I don't send the class, thinking about making a local class that has the same method + package-name so i can try to object.getClass()
I won't like to put the entire block of code in the toString() from the object that I will send. (Override)
I can't cast to an interface.
I'm also thinking about making a .jar library that has the definition for the class file that will be created on the server and accessed on the client, how can this work?
I couldn't find another question regarding this, so I will leave this here.
EDIT:
I'm using URLConnection to communicate with a servlet, the servlet makes an instance of the object on the server then it will send it to the client using ObjectOutputStream, as well as ObjectInputStream on the client for it to get it.
Looking for some alternatives to RMI, if none, I will lookup some RMI tutorials.
Regarding about my choice to not use RMI in the first place: maybe I don't want every time to make a connection between client-server , maybe I want to deserialize objects and check/invoke it's methods.
If you are going to "send" serialized objects from one java virtual machine (java process) to another, you need to have the .class files already present at both ends. If you decide to continue with your current approach, you would need the following:
Your client must be Java, or be able to run Java, and have the .class files that correspond to the objects that it is receiving locally available, or must download them from the server before accessing them.
You must somehow wrap serialized object streams within HTTP. HTTP is a protocol for requesting and sending web pages. It is incompatible with Java's serialization protocol (it contains extra headers, for example), and you would need to wrap Java serialization inside HTTP payloads for things to work as you seem to expect.
When you send serialized objects, you are actually sending "object graphs" (the object and all objects accessible by navigating its fields). This can end up being inefficient. Serialization may not be the best answer for you for this reason.
It is far easier to use other mechanisms:
If you avoid HTTP, you avoid the need for extra wrappers. Writing a simple server that, when connected to, receives and sends serialized objects is much easier and efficient than writing a wrapper for HTTP within a traditional Java webapp (Java app servers tend to be resource-hungry).
Consider using Kryo or other Java serialization/networking libraries - they come with built-in servers, and allow very fine-grained control over what is being sent.
Java has in-built support for RMI ("Remote Method Invocation"). This seems to be what you are actually trying to achieve. You no longer need to be aware that objects are local or remote - they appear to work the same, and all required networking and serialization is done behind the scenes. Read all about it.
I'm experimenting with RMI lately and found out that I seem to be unable to send a serialized object if the class file isn't also stored at the webserver. Does this mean that all my serializable classes need to be put in the webservers classpath?
Doesn't really seem like the best design to me IMHO.
No. All these answers are wrong.
The classes don't need to exist at both sides if you use the RMI codebase feature. You can set up a Web server to host the JAR files and set -Djava.rmi.server.codebase= to define where those classes are available as a list of URLs of those JAR files. You set that at either the server or the client or both depending on who is going to be sending classes that the other side doesn't have. Then RMI annotates those classes with those URLs so the target knows where to get them, and downloads them as needed.
Yes, the classes must exist on both sides.
Yes, the class file must exist on the webserver as well, as RMI was intended (way back when) to send an instance of a class across the wire. If you are simply looking to send data to a web server without any encapsulating class business behavior, then there are much newer and simpler ways (JSON, XML, SOAP, etc) to simply send data.
Ive managed to create an RMI application that does what i need it to do quite succesfully, but im having a bit of trouble getting my head around where client obtains definitions for remote objects. for example:
I have a server that registers itself with the rmiregistry (allowing clients to call methods on it).
UnicastRemoteObject.exportObject(new Server(), 0);
running reg.list() confirms that my server has indeed been added to the registry. I have another remote object (rObj) running on the same JVM as the server. This is not added to the registry.
In my client, i can get the definition of my Server class by looking up Server in the rmiregistry:
reg.lookup("Server")
after this can freely create instances of rObj. The crux of my question is, where does my client get a definition for rObj even though its never been added to registry.
I know it must come from the server as thats where the class and interface are stored. Does the connection to Server automatically open the pipe for other remote classes to received?
If so, how does the client know to look on the server for the remote class. Is the server treated almost as an extension to the clients classpath (it will resort to checking the server for classes that arent in its own classpath)?
First of all, realize that it's not necessary to set up dynamic classloading from the server in order to use RMI. If you compile the interface and implementation into both the client and server jars, then everything will work fine. That is how I've almost always implemented RMI.
If you have a good reason for loading the classes dynamically from the server, you'll need to set up an HTTP server somewhere that has the interfaces and implementation classes (preferably in a jar file, although a class directory will work too). This doesn't happen automatically as part of RMI, you need to build the jars and put them somewhere on your web server. Then launch the client with a system property indicating the URL to this jar file:
-Djava.rmi.server.codebase=http://webline/public/mystuff.jar
This is explained in full detail here: http://download.oracle.com/javase/1.5.0/docs/guide/rmi/codebase.html
If you use new to create new instances of the same type (say, T) as rObj, then of course the Java compiler knew the definition of T, and your application also knows it at runtime. In this case, no RMI is involved at all.
But maybe I misunderstood your question? How exactly do you "freely create instances of rObj"?
Update: I'm eating my words here, of course being able to compile the file, and having the class available on the classpath at runtime or two different issues. Since you were not mentioning the classpath at all, I was assuming you'd somehow ended up having the classes on the client-side anyway.
Basically I write an application which copies/moves files from the local file system to a remote file system over some FTP-like protocol.
Would it be a good approach to encapsulate the protocol-specific bits inside of the file system service provider interface?
As far as I understand that would make my library work with other applications using the new IO API, right?
It seems that you are thinking of creating a RemoteFileSystemProvider class specifically for your remote file system. This class would mirror FileSystemProvider, providing similar functionality to access the remote file system you are using. If this is something that your project or team can get repeated use from, then it is worthwhile to mirror the FileSystemProvider object when creating your code. This allows anyone familiar with the java.nio.file package can easily understand how to use yours.
Keep in mind, however, that FileSystemProvider itself does not conform to any interfaces or extend any classes within the package. It is an entry point, and your class would also be an entry point. However, if you mimicked the method structure, you would be generating Channel objects to read and write, which would conform to the java.nio specifications that could be reused. This would allow any code which knows how to work with channels to be able to work with channels generated by your remote file system provider.
My first step in building something like this, however, would be to just build a package specifically for this remote file system. It would handle all of the communication and implement the basic functions like getUploadChannel, getDownloadChannel, renameRemoteFile, copyRemoteFile, deleteRemoteFile, and whatever other functionality is necessary. This will give you a good common-sense interface defined for this specific file system and its functionality. This package could be used in any context to just implement a connection to this file system. If you make sure that this object uses channels to upload and download files, then it will be ready to integrate with any API which uses java.nio.
Only after this was completed, tested, and working, would I consider which interface I'd like to mimic or implement for delivery to the rest of the team. This will ensure that any changes to the remote file system protocol or to the java API will have minimal impact on the overall system.
I would get down and dirty and use the FTP-like protocol. The trouble with implementing low-level APIs over high-level APIs is that you disguise all the true costs,and make things look easy that are in fact extremely hard, or expensive. Consider seek() for example.