KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > rmi > ObjectImporter


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */

15
16 package javassist.rmi;
17
18 import java.io.*;
19 import java.net.*;
20 import java.applet.Applet JavaDoc;
21 import java.lang.reflect.*;
22
23 /**
24  * The object importer enables applets to call a method on a remote
25  * object running on the <code>Webserver</code>.
26  *
27  * <p>To access the remote
28  * object, the applet first calls <code>lookupObject()</code> and
29  * obtains a proxy object, which is a reference to that object.
30  * The class name of the proxy object is identical to that of
31  * the remote object.
32  * The proxy object provides the same set of methods as the remote object.
33  * If one of the methods is invoked on the proxy object,
34  * the invocation is delegated to the remote object.
35  * From the viewpoint of the applet, therefore, the two objects are
36  * identical. The applet can access the object on the server
37  * with the regular Java syntax without concern about the actual
38  * location.
39  *
40  * <p>The methods remotely called by the applet must be <code>public</code>.
41  * This is true even if the applet's class and the remote object's classs
42  * belong to the same package.
43  *
44  * <p>If class X is a class of remote objects, a subclass of X must be
45  * also a class of remote objects. On the other hand, this restriction
46  * is not applied to the superclass of X. The class X does not have to
47  * contain a constructor taking no arguments.
48  *
49  * <p>The parameters to a remote method is passed in the <i>call-by-value</i>
50  * manner. Thus all the parameter classes must implement
51  * <code>java.io.Serializable</code>. However, if the parameter is the
52  * proxy object, the reference to the remote object instead of a copy of
53  * the object is passed to the method.
54  *
55  * <p>Because of the limitations of the current implementation,
56  * <ul>
57  * <li>The parameter objects cannot contain the proxy
58  * object as a field value.
59  * <li>If class <code>C</code> is of the remote object, then
60  * the applet cannot instantiate <code>C</code> locally or remotely.
61  * </ul>
62  *
63  * <p>All the exceptions thrown by the remote object are converted
64  * into <code>RemoteException</code>. Since this exception is a subclass
65  * of <code>RuntimeException</code>, the caller method does not need
66  * to catch the exception. However, good programs should catch
67  * the <code>RuntimeException</code>.
68  *
69  * @see javassist.rmi.AppletServer
70  * @see javassist.rmi.RemoteException
71  * @see javassist.web.Viewer
72  */

73 public class ObjectImporter implements java.io.Serializable JavaDoc {
74     private final byte[] endofline = { 0x0d, 0x0a };
75     private String JavaDoc servername, orgServername;
76     private int port, orgPort;
77
78     protected byte[] lookupCommand = "POST /lookup HTTP/1.0".getBytes();
79     protected byte[] rmiCommand = "POST /rmi HTTP/1.0".getBytes();
80
81     /**
82      * Constructs an object importer.
83      *
84      * <p>Remote objects are imported from the web server that the given
85      * applet has been loaded from.
86      *
87      * @param applet the applet loaded from the <code>Webserver</code>.
88      */

89     public ObjectImporter(Applet JavaDoc applet) {
90         URL codebase = applet.getCodeBase();
91         orgServername = servername = codebase.getHost();
92         orgPort = port = codebase.getPort();
93     }
94
95     /**
96      * Constructs an object importer.
97      *
98      * <p>If you run a program with <code>javassist.web.Viewer</code>,
99      * you can construct an object importer as follows:
100      *
101      * <ul><pre>
102      * Viewer v = (Viewer)this.getClass().getClassLoader();
103      * ObjectImporter oi = new ObjectImporter(v.getServer(), v.getPort());
104      * </pre></ul>
105      *
106      * @see javassist.web.Viewer
107      */

108     public ObjectImporter(String JavaDoc servername, int port) {
109         this.orgServername = this.servername = servername;
110         this.orgPort = this.port = port;
111     }
112
113     /**
114      * Finds the object exported by a server with the specified name.
115      * If the object is not found, this method returns null.
116      *
117      * @param name the name of the exported object.
118      * @return the proxy object or null.
119      */

120     public Object JavaDoc getObject(String JavaDoc name) {
121         try {
122             return lookupObject(name);
123         }
124         catch (ObjectNotFoundException e) {
125             return null;
126         }
127     }
128
129     /**
130      * Sets an http proxy server. After this method is called, the object
131      * importer connects a server through the http proxy server.
132      */

133     public void setHttpProxy(String JavaDoc host, int port) {
134         String JavaDoc proxyHeader = "POST http://" + orgServername + ":" + orgPort;
135         String JavaDoc cmd = proxyHeader + "/lookup HTTP/1.0";
136         lookupCommand = cmd.getBytes();
137         cmd = proxyHeader + "/rmi HTTP/1.0";
138         rmiCommand = cmd.getBytes();
139         this.servername = host;
140         this.port = port;
141     }
142
143     /**
144      * Finds the object exported by the server with the specified name.
145      * It sends a POST request to the server (via an http proxy server
146      * if needed).
147      *
148      * @param name the name of the exported object.
149      * @return the proxy object.
150      */

151     public Object JavaDoc lookupObject(String JavaDoc name) throws ObjectNotFoundException
152     {
153         try {
154             Socket sock = new Socket(servername, port);
155             OutputStream out = sock.getOutputStream();
156             out.write(lookupCommand);
157             out.write(endofline);
158             out.write(endofline);
159
160             ObjectOutputStream dout = new ObjectOutputStream(out);
161             dout.writeUTF(name);
162             dout.flush();
163
164             InputStream in = new BufferedInputStream(sock.getInputStream());
165             skipHeader(in);
166             ObjectInputStream din = new ObjectInputStream(in);
167             int n = din.readInt();
168             String JavaDoc classname = din.readUTF();
169             din.close();
170             dout.close();
171             sock.close();
172
173             if (n >= 0)
174                 return createProxy(n, classname);
175         }
176         catch (Exception JavaDoc e) {
177             e.printStackTrace();
178             throw new ObjectNotFoundException(name, e);
179         }
180
181         throw new ObjectNotFoundException(name);
182     }
183
184     private static final Class JavaDoc[] proxyConstructorParamTypes
185         = new Class JavaDoc[] { ObjectImporter.class, int.class };
186
187     private Object JavaDoc createProxy(int oid, String JavaDoc classname) throws Exception JavaDoc {
188         Class JavaDoc c = Class.forName(classname);
189         Constructor cons = c.getConstructor(proxyConstructorParamTypes);
190         return cons.newInstance(new Object JavaDoc[] { this, new Integer JavaDoc(oid) });
191     }
192
193     /**
194      * Calls a method on a remote object.
195      * It sends a POST request to the server (via an http proxy server
196      * if needed).
197      *
198      * <p>This method is called by only proxy objects.
199      */

200     public Object JavaDoc call(int objectid, int methodid, Object JavaDoc[] args)
201         throws RemoteException
202     {
203         boolean result;
204         Object JavaDoc rvalue;
205         String JavaDoc errmsg;
206
207         try {
208             /* This method establishes a raw tcp connection for sending
209              * a POST message. Thus the object cannot communicate a
210              * remote object beyond a fire wall. To avoid this problem,
211              * the connection should be established with a mechanism
212              * collaborating a proxy server. Unfortunately, java.lang.URL
213              * does not seem to provide such a mechanism.
214              *
215              * You might think that using HttpURLConnection is a better
216              * way than constructing a raw tcp connection. Unfortunately,
217              * URL.openConnection() does not return an HttpURLConnection
218              * object in Netscape's JVM. It returns a
219              * netscape.net.URLConnection object.
220              *
221              * lookupObject() has the same problem.
222              */

223             Socket sock = new Socket(servername, port);
224             OutputStream out = new BufferedOutputStream(
225                                                 sock.getOutputStream());
226             out.write(rmiCommand);
227             out.write(endofline);
228             out.write(endofline);
229
230             ObjectOutputStream dout = new ObjectOutputStream(out);
231             dout.writeInt(objectid);
232             dout.writeInt(methodid);
233             writeParameters(dout, args);
234             dout.flush();
235
236             InputStream ins = new BufferedInputStream(sock.getInputStream());
237             skipHeader(ins);
238             ObjectInputStream din = new ObjectInputStream(ins);
239             result = din.readBoolean();
240             rvalue = null;
241             errmsg = null;
242             if (result)
243                 rvalue = din.readObject();
244             else
245                 errmsg = din.readUTF();
246
247             din.close();
248             dout.close();
249             sock.close();
250
251             if (rvalue instanceof RemoteRef) {
252                 RemoteRef ref = (RemoteRef)rvalue;
253                 rvalue = createProxy(ref.oid, ref.classname);
254             }
255         }
256         catch (ClassNotFoundException JavaDoc e) {
257             throw new RemoteException(e);
258         }
259         catch (IOException e) {
260             throw new RemoteException(e);
261         }
262         catch (Exception JavaDoc e) {
263             throw new RemoteException(e);
264         }
265
266         if (result)
267             return rvalue;
268         else
269             throw new RemoteException(errmsg);
270     }
271
272     private void skipHeader(InputStream in) throws IOException {
273         int len;
274         do {
275             int c;
276             len = 0;
277             while ((c = in.read()) >= 0 && c != 0x0d)
278                 ++len;
279
280             in.read(); /* skip 0x0a (LF) */
281         } while (len > 0);
282     }
283
284     private void writeParameters(ObjectOutputStream dout, Object JavaDoc[] params)
285         throws IOException
286     {
287         int n = params.length;
288         dout.writeInt(n);
289         for (int i = 0; i < n; ++i)
290             if (params[i] instanceof Proxy) {
291                 Proxy p = (Proxy)params[i];
292                 dout.writeObject(new RemoteRef(p._getObjectId()));
293             }
294             else
295                 dout.writeObject(params[i]);
296     }
297 }
298
Popular Tags