View Javadoc

1   /***
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Exoffice Technologies.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Exoffice Technologies. Exolab is a registered
23   *    trademark of Exoffice Technologies.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 2003-2005 (C) Exoffice Technologies Inc. All Rights Reserved.
42   *
43   * $Id: AbstractORB.java,v 1.8 2005/11/18 03:25:51 tanderson Exp $
44   */
45  package org.exolab.jms.net.orb;
46  
47  import java.rmi.NoSuchObjectException;
48  import java.rmi.RemoteException;
49  import java.rmi.StubNotFoundException;
50  import java.rmi.server.ExportException;
51  import java.rmi.server.ObjID;
52  import java.util.HashMap;
53  import java.util.Map;
54  
55  import org.exolab.jms.net.proxy.Proxy;
56  import org.exolab.jms.net.uri.InvalidURIException;
57  import org.exolab.jms.net.uri.URI;
58  import org.exolab.jms.net.uri.URIHelper;
59  
60  
61  /***
62   * Abstract implementation of the {@link ORB} interface.
63   *
64   * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
65   * @version $Revision: 1.8 $ $Date: 2005/11/18 03:25:51 $
66   */
67  public abstract class AbstractORB implements ORB {
68  
69      /***
70       * A map of ObjID -> ObjectRef instances.
71       */
72      private HashMap _objIDMap = new HashMap();
73  
74      /***
75       * A map of Object -> ObjectRef instances.
76       */
77      private HashMap _objectMap = new HashMap();
78  
79      /***
80       * Configuration properties.
81       */
82      private final Map _properties;
83  
84      /***
85       * The default URI for exported objects.
86       */
87      private final String _defaultURI;
88  
89      /***
90       * A map of routes for exported objects. The key is a URI representing the
91       * URI the objects are listening on. The value is the URI of the router.
92       */
93      private HashMap _routes = new HashMap();
94  
95      /***
96       * The class loader used to load proxies.
97       */
98      private ClassLoader _loader;
99  
100 
101     /***
102      * Construct a new <code>AbstractORB</code>.
103      *
104      * @param loader the class loader to load proxies
105      * @param properties properties to configure this with. May be
106      * <code>null</code>.
107      */
108     public AbstractORB(ClassLoader loader, Map properties) {
109         if (loader == null) {
110             throw new IllegalArgumentException("Argument 'loader' is null");
111         }
112         _loader = loader;
113         if (properties != null) {
114             _properties = properties;
115             _defaultURI = (String) properties.get(PROVIDER_URI);
116         } else {
117             _properties = new HashMap();
118             _defaultURI = null;
119         }
120     }
121 
122     /***
123      * Add a route for exported objects.
124      *
125      * @param uri   the URI to route
126      * @param toURI the URI to route to
127      * @throws RemoteException for any error
128      */
129     public synchronized void addRoute(String uri, String toURI)
130             throws RemoteException {
131         if (uri == null) {
132             throw new IllegalArgumentException("Argument 'uri' is null");
133         }
134         if (toURI == null) {
135             throw new IllegalArgumentException("Argument 'toURI' is null");
136         }
137         _routes.put(URIHelper.parse(uri), URIHelper.parse(toURI));
138     }
139 
140     /***
141      * Returns the proxy associated with the specified object, and URI.
142      *
143      * @param object the object to look up the proxy for
144      * @param uri    the URI the object was exported on
145      * @return the proxy corresponding to <code>object</code> and
146      *         <code>uri</code>
147      * @throws NoSuchObjectException if the object hasn't been exported on the
148      *                               specified URI
149      */
150     public synchronized Proxy getProxy(Object object, String uri)
151             throws NoSuchObjectException {
152 
153 //         if (uri == null) {
154 //             throw new IllegalArgumentException("Argument 'uri' is null");
155 //         }
156         ObjectRef ref = (ObjectRef) _objectMap.get(object);
157         if (ref == null) {
158             throw new NoSuchObjectException("Object not exported");
159         }
160         URI parsed = null;
161         if (uri != null) {
162             try {
163                 parsed = URIHelper.parse(uri);
164             } catch (InvalidURIException exception) {
165                 throw new NoSuchObjectException(exception.getMessage());
166             }
167         }
168         return ref.getProxy(parsed);
169     }
170 
171     /***
172      * Returns the object associated with the specified ID, and URI.
173      *
174      * @param objID the identifier of the object
175      * @param uri   the URI the object was exported on
176      * @return the object corresponding to <code>objID</code> and
177      *         <code>uri</code>
178      * @throws NoSuchObjectException if the object hasn't been exported on the
179      *                               specified URI
180      */
181     public synchronized Object getObject(ObjID objID, String uri)
182             throws NoSuchObjectException {
183 
184 //         if (uri == null) {
185 //             throw new IllegalArgumentException("Argument 'uri' is null");
186 //         }
187         ObjectRef ref = (ObjectRef) _objIDMap.get(objID);
188         if (ref == null) {
189             throw new NoSuchObjectException("Object not exported");
190         }
191         // ref.getProxy(uri);
192         // ensures it has been exported on the specified uri
193         return ref.getObject();
194     }
195 
196     /***
197      * Export an object on a default URI.
198      *
199      * @param object the object to export
200      * @return a proxy which may be used to invoke methods on the object
201      * @throws ExportException       if the object cannot be exported
202      * @throws StubNotFoundException if the proxy class cannot be found
203      */
204     public Proxy exportObject(Object object)
205             throws ExportException, StubNotFoundException {
206         return exportObject(object, _defaultURI);
207     }
208 
209     /***
210      * Export an object on a specific URI.
211      *
212      * @param object the object to export
213      * @param uri    the URI via which connections to the object are made
214      * @return a proxy which may be used to invoke methods on the object
215      * @throws ExportException       if the object cannot be exported
216      * @throws StubNotFoundException if the proxy class cannot be found
217      */
218     public synchronized Proxy exportObject(Object object, String uri)
219             throws ExportException, StubNotFoundException {
220 
221         if (object == null) {
222             throw new IllegalArgumentException("Argument 'object' is null");
223         }
224         if (uri == null) {
225             throw new IllegalArgumentException("Argument 'uri' is null");
226         }
227 
228         URI parsed = null;
229         try {
230             parsed = URIHelper.parse(uri);
231         } catch (InvalidURIException exception) {
232             throw new ExportException(exception.getMessage(), exception);
233         }
234 
235         Proxy proxy = null;
236         ObjectRef ref = (ObjectRef) _objectMap.get(object);
237         if (ref != null) {
238             proxy = addProxy(ref, parsed, object, ref.getProxyClass());
239         } else {
240             ObjID objID = new ObjID();
241             proxy = doExport(object, objID, parsed, getProxyClass(object));
242         }
243 
244         return proxy;
245     }
246 
247     /***
248      * Export an object with a well known identifier on a default URI.
249      *
250      * @param object the object to export
251      * @param objID  the well known object identifier
252      * @return a proxy which may be used to invoke methods on the object
253      * @throws ExportException       if the object cannot be exported
254      * @throws StubNotFoundException if the proxy class cannot be found
255      */
256     public Proxy exportObject(Object object, ObjID objID)
257             throws ExportException, StubNotFoundException {
258         return exportObject(object, objID, _defaultURI);
259     }
260 
261     /***
262      * Export an object with a well known identifier on a specific URI.
263      *
264      * @param object the object to export
265      * @param objID  the well known object identifier
266      * @param uri    the URI via which connections to the object are made
267      * @return a proxy which may be used to invoke methods on the object
268      * @throws ExportException       if the object cannot be exported
269      * @throws StubNotFoundException if the proxy class cannot be found
270      */
271     public synchronized Proxy exportObject(Object object, ObjID objID,
272                                            String uri)
273             throws ExportException, StubNotFoundException {
274 
275         if (object == null) {
276             throw new IllegalArgumentException("Argument 'object' is null");
277         }
278         if (objID == null) {
279             throw new IllegalArgumentException("Argument 'objID' is null");
280         }
281         if (uri == null) {
282             throw new IllegalArgumentException("Argument 'uri' is null");
283         }
284         URI parsed = null;
285         try {
286             parsed = URIHelper.parse(uri);
287         } catch (InvalidURIException exception) {
288             throw new ExportException(exception.getMessage(), exception);
289 
290         }
291         Proxy proxy = null;
292         ObjectRef ref = (ObjectRef) _objectMap.get(object);
293         if (ref != null) {
294             proxy = addProxy(ref, parsed, object, ref.getProxyClass());
295         } else {
296             proxy = doExport(object, objID, parsed, getProxyClass(object));
297         }
298         return proxy;
299     }
300 
301     /***
302      * Export an object to a specific URI.
303      *
304      * @param object the object to export
305      * @param uri    the target URI from which connections to the object are
306      *               made.
307      * @return a proxy which may be used to invoke methods on the object
308      * @throws ExportException       if the object cannot be exported
309      * @throws StubNotFoundException if the proxy class cannot be found
310      */
311     public Proxy exportObjectTo(Object object, String uri)
312             throws ExportException, StubNotFoundException {
313         return exportObjectTo(object, uri, null, null);
314     }
315 
316     /***
317      * Export an object to a specific URI. Only callers from the target URI may
318      * perform invocations.
319      *
320      * @param object      the object to export
321      * @param uri         the target URI from which connections to the object
322      *                    are made.
323      * @param principal   the security principal. May be <code>null</code>
324      * @param credentials the security credentials. May be <code>null</code>
325      * @return a proxy which may be used to invoke methods on the object
326      * @throws ExportException       if the object cannot be exported
327      * @throws StubNotFoundException if the proxy class cannot be found
328      */
329     public Proxy exportObjectTo(Object object, String uri, String principal,
330                                 String credentials)
331             throws ExportException, StubNotFoundException {
332         if (object == null) {
333             throw new IllegalArgumentException("Argument 'object' is null");
334         }
335         if (uri == null) {
336             throw new IllegalArgumentException("Argument 'uri' is null");
337         }
338         URI remoteURI = null;
339         URI localURI = null;
340         try {
341             remoteURI = URIHelper.parse(uri);
342         } catch (InvalidURIException exception) {
343             throw new ExportException(exception.getMessage(), exception);
344         }
345 
346         localURI = connect(remoteURI, principal, credentials);
347 
348         return doExportTo(object, localURI);
349     }
350 
351     /***
352      * Unexport an object.
353      *
354      * @param object the object to export
355      * @throws NoSuchObjectException if the object isn't exported
356      */
357     public synchronized void unexportObject(Object object)
358             throws NoSuchObjectException {
359 
360         ObjectRef ref = (ObjectRef) _objectMap.remove(object);
361         if (ref != null) {
362             _objIDMap.remove(ref.getObjID());
363         } else {
364             throw new NoSuchObjectException("Object not exported");
365         }
366     }
367 
368     /***
369      * Connect to the specified URI.
370      *
371      * @param uri         the URI to establish a connection with
372      * @param principal   specifies the identity of the principal. If
373      *                    <code>null</code>, indicates to connect anonymously.
374      * @param credentials the credentials of the principal
375      * @return the local address that the connection is bound to
376      * @throws ExportException for any error
377      */
378     protected abstract URI connect(URI uri, String principal,
379                                    String credentials) throws ExportException;
380 
381     /***
382      * Accept connections on the specified URI.
383      *
384      * @param uri the URI to accept connections on
385      * @throws ExportException for any error
386      */
387     protected abstract void accept(URI uri) throws ExportException;
388 
389     /***
390      * Returns the proxy class loader.
391      *
392      * @return the proxy class loader
393      */
394     protected ClassLoader getProxyClassLoader() {
395         return _loader;
396     }
397 
398     /***
399      * Returns the configuration properties.
400      *
401      * @return the configuration properties
402      */
403     protected Map getProperties() {
404         return _properties;
405     }
406 
407     /***
408      * Export an object to a specific URI.
409      * 
410      * @param object the object to export
411      * @param uri the URI via which connections to the object are made
412      * @throws ExportException if the object cannot be exported
413      * @throws StubNotFoundException if the proxy class cannot be found
414      */ 
415     protected Proxy doExportTo(Object object, URI uri)
416             throws ExportException, StubNotFoundException {
417         Proxy proxy = null;
418         ObjectRef ref = (ObjectRef) _objectMap.get(object);
419         if (ref != null) {
420             proxy = addProxyTo(ref, uri, object, ref.getProxyClass());
421         } else {
422             ObjID objID = new ObjID();
423             proxy = doExportTo(object, objID, uri, getProxyClass(object));
424         }
425 
426         return proxy;
427     }
428 
429     /***
430      * Returns the no. of currently exported objects.
431      *
432      * @return the no. of exported objects
433      */
434     protected int getExported() {
435         return _objectMap.size();
436     }
437 
438     /***
439      * Export an object on a specific URI.
440      *
441      * @param object     the object to export
442      * @param objID      the identifier of the object
443      * @param uri        the URI via which connections to the object are made
444      * @param proxyClass the proxy class
445      * @return a proxy which may be used to invoke methods on the object
446      * @throws ExportException if the object cannot be exported
447      */
448     private Proxy doExport(Object object, ObjID objID, URI uri,
449                            Class proxyClass) throws ExportException {
450         accept(uri);
451         ObjectRef ref = new ObjectRef(objID, object, proxyClass);
452         Proxy proxy = ref.addProxy(getRoute(uri));
453         _objIDMap.put(objID, ref);
454         _objectMap.put(object, ref);
455         return proxy;
456     }
457     
458     /***
459      * Export an object to a specific URI.
460      *
461      * @param object     the object to export
462      * @param objID      the identifier of the object
463      * @param uri        the URI via which connections to the object are made
464      * @param proxyClass the proxy class
465      * @return a proxy which may be used to invoke methods on the object
466      * @throws ExportException if the object cannot be exported
467      */
468     private Proxy doExportTo(Object object, ObjID objID, URI uri,
469                              Class proxyClass) throws ExportException {
470         ObjectRef ref = new ObjectRef(objID, object, proxyClass);
471         Proxy proxy = ref.addProxy(getRoute(uri));
472         _objIDMap.put(objID, ref);
473         _objectMap.put(object, ref);
474         return proxy;
475     }
476 
477     /***
478      * Add a proxy for an exported object.
479      *
480      * @param ref        a reference to the exported object
481      * @param uri        the URI via which connections to the object are made
482      * @param object     the exported object
483      * @param proxyClass the proxy class
484      * @return a proxy which may be used to invoke methods on the object
485      * @throws ExportException if the object cannot be exported
486      */
487     private Proxy addProxy(ObjectRef ref, URI uri, Object object,
488                            Class proxyClass) throws ExportException {
489 
490         if (object != ref.getObject()) {
491             throw new ExportException("Cannot export object on URI=" + uri
492                                       + ": object mismatch");
493         }
494         if (proxyClass != ref.getProxyClass()) {
495             throw new ExportException("Cannot export object on URI=" + uri
496                                       + ": proxy class mismatch");
497         }
498 
499         accept(uri);
500         return ref.addProxy(getRoute(uri));
501     }
502 
503     /***
504      * Add a proxy for an exported object.
505      *
506      * @param ref        a reference to the exported object
507      * @param uri        the URI via which connections to the object are made
508      * @param object     the exported object
509      * @param proxyClass the proxy class
510      * @return a proxy which may be used to invoke methods on the object
511      * @throws ExportException if the object cannot be exported
512      */
513     private Proxy addProxyTo(ObjectRef ref, URI uri, Object object,
514                              Class proxyClass) throws ExportException {
515 
516         if (object != ref.getObject()) {
517             throw new ExportException("Cannot export object on URI=" + uri
518                                       + ": object mismatch");
519         }
520         if (proxyClass != ref.getProxyClass()) {
521             throw new ExportException("Cannot export object on URI=" + uri
522                                       + ": proxy class mismatch");
523         }
524 
525         return ref.addProxy(uri);
526     }
527 
528     /***
529      * Loads the proxy class for the supplied object.
530      *
531      * @param object the object to load the proxy for
532      * @return the proxy class corresponding to <code>object</code>
533      * @throws StubNotFoundException if the proxy class cannot be loaded
534      */
535     private Class getProxyClass(Object object) throws StubNotFoundException {
536         return getProxyClass(object.getClass());
537     }
538 
539     /***
540      * Loads the proxy class for the supplied class.
541      *
542      * @param clazz the class to load the proxy for
543      * @return the proxy class corresponding to <code>class</code>
544      * @throws StubNotFoundException if the proxy class cannot be loaded
545      */
546     private Class getProxyClass(Class clazz) throws StubNotFoundException {
547         String proxyName = clazz.getName() + "__Proxy";
548         Class proxyClass = null;
549         try {
550             proxyClass = _loader.loadClass(proxyName);
551             if (!Proxy.class.isAssignableFrom(proxyClass)) {
552                 throw new StubNotFoundException(proxyName);
553             }
554         } catch (ClassNotFoundException exception) {
555             Class superClass = clazz.getSuperclass();
556             if (superClass != null && !superClass.isInterface()) {
557                 proxyClass = getProxyClass(superClass);
558             } else {
559                 throw new StubNotFoundException(proxyName);
560             }
561         }
562         return proxyClass;
563     }
564 
565     /***
566      * Returns the route address of a URI.
567      *
568      * @param uri the URI
569      * @return the route address of <code>uri</code>, or <code>uri</code> if it
570      *         isn't routed
571      */
572     private URI getRoute(URI uri) {
573         URI result = (URI) _routes.get(uri);
574         return (result == null) ? uri : result;
575     }
576 
577 }