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
154
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
185
186
187 ObjectRef ref = (ObjectRef) _objIDMap.get(objID);
188 if (ref == null) {
189 throw new NoSuchObjectException("Object not exported");
190 }
191
192
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 }