KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > exolab > jms > net > rmi > RMIManagedConnection


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: RMIManagedConnection.java,v 1.5 2005/06/04 14:28:52 tanderson Exp $
44  */

45 package org.exolab.jms.net.rmi;
46
47 import java.io.IOException JavaDoc;
48 import java.rmi.AccessException JavaDoc;
49 import java.rmi.MarshalException JavaDoc;
50 import java.rmi.MarshalledObject JavaDoc;
51 import java.rmi.NotBoundException JavaDoc;
52 import java.rmi.RemoteException JavaDoc;
53 import java.rmi.registry.LocateRegistry JavaDoc;
54 import java.rmi.registry.Registry JavaDoc;
55 import java.rmi.server.UnicastRemoteObject JavaDoc;
56 import java.security.Principal JavaDoc;
57
58 import org.apache.commons.logging.Log;
59 import org.apache.commons.logging.LogFactory;
60
61 import org.exolab.jms.common.uuid.UUIDGenerator;
62 import org.exolab.jms.net.connector.AbstractManagedConnection;
63 import org.exolab.jms.net.connector.Caller;
64 import org.exolab.jms.net.connector.CallerImpl;
65 import org.exolab.jms.net.connector.ConnectException;
66 import org.exolab.jms.net.connector.Connection;
67 import org.exolab.jms.net.connector.IllegalStateException;
68 import org.exolab.jms.net.connector.InvocationHandler;
69 import org.exolab.jms.net.connector.Request;
70 import org.exolab.jms.net.connector.ResourceException;
71 import org.exolab.jms.net.connector.Response;
72 import org.exolab.jms.net.connector.SecurityException;
73 import org.exolab.jms.net.connector.MarshalledInvocation;
74 import org.exolab.jms.net.uri.InvalidURIException;
75 import org.exolab.jms.net.uri.URI;
76 import org.exolab.jms.net.uri.URIHelper;
77
78
79 /**
80  * <code>RMIManagedConnection</code> manages multiple <code>RMIConnection</code>
81  * instances.
82  *
83  * @author <a HREF="mailto:tma@netspace.net.au">Tim Anderson</a>
84  * @version $Revision: 1.5 $ $Date: 2005/06/04 14:28:52 $
85  */

86 class RMIManagedConnection extends AbstractManagedConnection {
87
88     /**
89      * The invoker for serving invocations from the remote managed connection.
90      */

91     private RMIInvokerImpl _localInvoker;
92
93     /**
94      * The invoker for delegating invocations to the remote managed connection.
95      */

96     private RMIInvoker _remoteInvoker;
97
98     /**
99      * The invocation handler.
100      */

101     private InvocationHandler _invoker;
102
103     /**
104      * The remote address to which this is connected.
105      */

106     private URI _remoteURI;
107
108     /**
109      * The the local address that this connection is bound to.
110      */

111     private URI _localURI;
112
113     /**
114      * The security principal.
115      */

116     private Principal JavaDoc _principal;
117
118     /**
119      * Cached caller instance. Non-null if this is a server-side instance.
120      */

121     private Caller _caller;
122
123     /**
124      * The logger.
125      */

126     private static final Log _log =
127             LogFactory.getLog(RMIManagedConnection.class);
128
129
130     /**
131      * Construct a new client <code>RMIManagedConnection</code>.
132      *
133      * @param principal the security principal
134      * @param info the connection request info
135      * @throws ResourceException if a connection cannot be established
136      */

137     protected RMIManagedConnection(Principal JavaDoc principal, RMIRequestInfo info)
138             throws ResourceException {
139
140         Registry JavaDoc registry;
141         _remoteURI = URIHelper.convertHostToAddress(info.getURI());
142         _localURI = generateLocalURI();
143
144         try {
145             registry = LocateRegistry.getRegistry(info.getHost(),
146                                                   info.getPort());
147         } catch (RemoteException JavaDoc exception) {
148             throw new ConnectException("Failed to get registry"
149                                        + ", host=" + info.getHost()
150                                        + ", port=" + info.getPort(),
151                                        exception);
152         }
153
154         String JavaDoc name = RegistryHelper.getName(_remoteURI);
155         RMIInvokerFactory factory;
156         try {
157             factory = (RMIInvokerFactory) registry.lookup(name);
158         } catch (RemoteException JavaDoc exception) {
159             throw new ConnectException("Failed to lookup connection proxy"
160                                        + ", host=" + info.getHost()
161                                        + ", port=" + info.getPort(),
162                                        exception);
163         } catch (NotBoundException JavaDoc exception) {
164             throw new ConnectException("Connection proxy=" + name
165                                        + " not bound in "
166                                        + "registry, host=" + info.getHost()
167                                        + ", port=" + info.getPort(),
168                                        exception);
169         }
170
171         _localInvoker = new RMIInvokerImpl();
172         _localInvoker.setConnection(this);
173         try {
174             UnicastRemoteObject.exportObject(_localInvoker);
175         } catch (RemoteException JavaDoc exception) {
176             throw new ResourceException("Failed to export invocation handler",
177                                         exception);
178         }
179         try {
180             _remoteInvoker = factory.createInvoker(principal, _localInvoker,
181                                                    _localURI.toString());
182         } catch (AccessException JavaDoc exception) {
183             throw new SecurityException JavaDoc(exception.getMessage(), exception);
184         } catch (RemoteException JavaDoc exception) {
185             if (exception.detail instanceof AccessException JavaDoc) {
186                 throw new SecurityException JavaDoc(exception.getMessage(),
187                                             exception.detail);
188             }
189             throw new ResourceException("Failed to create invocation handler",
190                                         exception);
191         }
192         _principal = principal;
193     }
194
195     /**
196      * Construct a new server <code>RMIManagedConnection</code>. This is
197      * responsible for exporting the supplied local invoker on the port
198      * specified by the URI.
199      *
200      * @param principal the security principal
201      * @param localInvoker the invoker which delegates invocations to this
202      * @param localURI the URI to export the connection proxy on
203      * @param remoteInvoker the invoker which delegates invocations to the
204      * remote managed connection
205      * @param remoteURI the URI representing the remote connection
206      * @throws RemoteException if the connection proxy can't be exported
207      */

208     protected RMIManagedConnection(Principal JavaDoc principal,
209                                    RMIInvokerImpl localInvoker,
210                                    URI localURI,
211                                    RMIInvoker remoteInvoker,
212                                    URI remoteURI)
213
214             throws RemoteException JavaDoc {
215         localInvoker.setConnection(this);
216         UnicastRemoteObject.exportObject(localInvoker, localURI.getPort());
217         _localInvoker = localInvoker;
218         _localURI = localURI;
219         _remoteInvoker = remoteInvoker;
220         _remoteURI = remoteURI;
221         _principal = principal;
222         _caller = new CallerImpl(_remoteURI, _localURI);
223     }
224
225     /**
226      * Creates a new connection handle for the underlying physical connection.
227      *
228      * @return a new connection handle
229      * @throws IllegalStateException if an invocation handler hasn't been
230      * registered
231      */

232     public synchronized Connection getConnection()
233             throws IllegalStateException JavaDoc {
234         if (_invoker == null) {
235             throw new IllegalStateException JavaDoc("No InvocationHandler registered");
236         }
237         return new RMIConnection(this);
238     }
239
240     /**
241      * Registers a handler for handling invocations.
242      *
243      * @param handler the invocation handler
244      * @throws IllegalStateException if a handler is already registered
245      */

246     public synchronized void setInvocationHandler(InvocationHandler handler)
247             throws IllegalStateException JavaDoc {
248         if (_invoker != null) {
249             throw new IllegalStateException JavaDoc(
250                     "An invocation handler is already registered");
251         }
252         _invoker = handler;
253     }
254
255     /**
256      * Determines if the underlying physical connection is alive.
257      *
258      * @return <code>true</code> if the connection is alive
259      */

260     public boolean isAlive() {
261         boolean alive = false;
262         RMIInvoker invoker;
263         synchronized (this) {
264             invoker = _remoteInvoker;
265         }
266         if (invoker != null) {
267             try {
268                 invoker.ping();
269                 alive = true;
270             } catch (RemoteException JavaDoc exception) {
271                 _log.debug("Failed to ping remote server", exception);
272             }
273         }
274         return alive;
275     }
276
277     /**
278      * Destroys the physical connection.
279      *
280      * @throws ResourceException for any error
281      */

282     public void destroy() throws ResourceException {
283         try {
284             RMIInvoker invoker;
285             synchronized (this) {
286                 invoker = _localInvoker;
287             }
288             if (invoker != null) {
289                 if (!UnicastRemoteObject.unexportObject(invoker, true)) {
290                     _log.warn("Failed to unexport invocation handler");
291                 }
292             }
293         } catch (RemoteException JavaDoc exception) {
294             throw new ResourceException(
295                     "Failed to unexport invocation handler", exception);
296         } finally {
297             synchronized (this) {
298                 _localInvoker = null;
299                 _remoteInvoker = null;
300             }
301         }
302     }
303
304     /**
305      * Returns the remote address to which this is connected.
306      *
307      * @return the remote address to which this is connected
308      */

309     public URI getRemoteURI() {
310         return _remoteURI;
311     }
312
313     /**
314      * Returns the local address that this connection is bound to.
315      *
316      * @return the local address that this connection is bound to
317      */

318     public URI getLocalURI() {
319         return _localURI;
320     }
321
322     /**
323      * Determines if the security principal that owns this connection is the
324      * same as that supplied.
325      *
326      * @param principal the principal to compare. May be <code>null</code>.
327      * @return <code>true</code> if the principal that owns this connection is
328      * the same as <code>principal</code>
329      */

330     public boolean hasPrincipal(Principal JavaDoc principal) {
331         boolean result = false;
332         if ((_principal != null && _principal.equals(principal))
333                 || (_principal == null && principal == null)) {
334             result = true;
335         }
336         return result;
337     }
338
339     /**
340      * Invoke a method on a remote object.
341      *
342      * @param connection the connection performing the invocation
343      * @param request the request
344      * @return the result of the invocation
345      * @throws RemoteException if the distributed call cannot be made
346      */

347     protected Response invoke(Connection connection, Request request)
348             throws RemoteException JavaDoc {
349         Response response = null;
350         try {
351             MarshalledObject JavaDoc wrappedRequest = new MarshalledObject JavaDoc(request);
352             MarshalledObject JavaDoc wrappedResponse =
353                     _remoteInvoker.invoke(wrappedRequest);
354             response = (Response) wrappedResponse.get();
355         } catch (ClassNotFoundException JavaDoc exception) {
356             response = new Response(exception);
357         } catch (IOException JavaDoc exception) {
358             response = new Response(exception);
359         }
360         return response;
361     }
362
363     /**
364      * Invoke a method on a local object.
365      *
366      * @param request the wrapped <code>Request</code>
367      * @return the wrapped <code>Response</code>
368      * @throws MarshalException if the response can't be marshalled
369      */

370     protected MarshalledObject JavaDoc invokeLocal(MarshalledObject JavaDoc request)
371             throws MarshalException JavaDoc {
372         MarshalledInvocation invocation
373                 = new MarshalledInvocation(request, _caller);
374         _invoker.invoke(invocation);
375
376         MarshalledObject JavaDoc response = null;
377         try {
378             response = invocation.getMarshalledResponse();
379         } catch (IOException JavaDoc exception) {
380             throw new MarshalException JavaDoc("Failed to marshal response",
381                                        exception);
382         }
383         return response;
384     }
385
386     /**
387      * Helper to generate a URI for a client RMIManagedConnection instance.
388      *
389      * @return a URI that uniquely identifies a client RMIManagedConnection
390      * @throws ResourceException if the URI cannot be generated
391      */

392     private URI generateLocalURI() throws ResourceException {
393         URI result;
394         String JavaDoc path = UUIDGenerator.create();
395         try {
396             result = URIHelper.create("rmi", null, -1, path);
397         } catch (InvalidURIException exception) {
398             throw new ResourceException("Failed to generate local URI",
399                                         exception);
400         }
401         return result;
402     }
403
404 }
405
Popular Tags