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: VMManagedConnection.java,v 1.7 2006/12/16 12:37:17 tanderson Exp $
44 */
45 package org.exolab.jms.net.vm;
46
47 import org.exolab.jms.common.uuid.UUIDGenerator;
48 import org.exolab.jms.net.connector.AbstractManagedConnection;
49 import org.exolab.jms.net.connector.Caller;
50 import org.exolab.jms.net.connector.CallerImpl;
51 import org.exolab.jms.net.connector.Connection;
52 import org.exolab.jms.net.connector.IllegalStateException;
53 import org.exolab.jms.net.connector.InvocationHandler;
54 import org.exolab.jms.net.connector.ManagedConnectionListener;
55 import org.exolab.jms.net.connector.MarshalledInvocation;
56 import org.exolab.jms.net.connector.Request;
57 import org.exolab.jms.net.connector.ResourceException;
58 import org.exolab.jms.net.connector.Response;
59 import org.exolab.jms.net.connector.URIRequestInfo;
60 import org.exolab.jms.net.uri.InvalidURIException;
61 import org.exolab.jms.net.uri.URI;
62 import org.exolab.jms.net.uri.URIHelper;
63
64 import java.io.IOException;
65 import java.rmi.MarshalException;
66 import java.rmi.MarshalledObject;
67 import java.security.Principal;
68
69
70 /***
71 * <code>VMManagedConnection</code> manages multiple <code>VMConnection</code>
72 * instances.
73 *
74 * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
75 * @version $Revision: 1.7 $ $Date: 2006/12/16 12:37:17 $
76 */
77 class VMManagedConnection extends AbstractManagedConnection {
78
79 /***
80 * The invoker for delegating invocations to the remote managed connection.
81 */
82 private VMInvoker _remoteInvoker;
83
84 /***
85 * The invocation handler.
86 */
87 private InvocationHandler _invoker;
88
89 /***
90 * The remote address to which this is connected.
91 */
92 private URI _remoteURI;
93
94 /***
95 * The the local address that this connection is bound to.
96 */
97 private URI _localURI;
98
99 /***
100 * The security principal.
101 */
102 private Principal _principal;
103
104 /***
105 * Cached caller instance. Non-null if this is a server-side instance.
106 */
107 private Caller _caller;
108
109
110 /***
111 * Construct a new client <code>VMManagedConnection</code>.
112 *
113 * @param principal the security principal
114 * @param info the connection request info
115 * @throws ResourceException for any error
116 */
117 protected VMManagedConnection(Principal principal, URIRequestInfo info)
118 throws ResourceException {
119 _remoteURI = info.getURI();
120 try {
121 _localURI = URIHelper.create("vm", null, -1,
122 UUIDGenerator.create());
123 } catch (InvalidURIException exception) {
124 throw new ResourceException("Failed to generate local URI",
125 exception);
126 }
127 VMInvoker invoker = new VMInvoker(this);
128 _remoteInvoker = VMManagedConnectionAcceptor.connect(principal, info,
129 invoker,
130 _localURI);
131 _principal = principal;
132 }
133
134 /***
135 * Construct a new server <code>VMManagedConnection</code>.
136 *
137 * @param principal the security principal
138 * @param info the connection request info
139 * @param client the invoker which delegates invocations to the client
140 * managed connection
141 * @param uri the URI representing the client
142 */
143 protected VMManagedConnection(Principal principal, URIRequestInfo info,
144 VMInvoker client, URI uri) {
145 _localURI = info.getURI();
146 _remoteInvoker = client;
147 _remoteURI = uri;
148 _caller = new CallerImpl(_remoteURI, _localURI);
149 _principal = principal;
150 }
151
152 /***
153 * Creates a new connection handle for the underlying physical connection.
154 *
155 * @return a new connection handle
156 * @throws IllegalStateException if an invocation handler hasn't been
157 * registered
158 */
159 public synchronized Connection getConnection()
160 throws IllegalStateException {
161 if (_invoker == null) {
162 throw new IllegalStateException("No InvocationHandler registered");
163 }
164 return new VMConnection(this);
165 }
166
167 /***
168 * Registers a handler for handling invocations on objects exported via this
169 * connection.
170 *
171 * @param handler the invocation handler
172 * @throws IllegalStateException if a handler is already registered
173 * @throws ResourceException for any error
174 */
175 public synchronized void setInvocationHandler(InvocationHandler handler)
176 throws ResourceException {
177 if (_invoker != null) {
178 throw new IllegalStateException(
179 "An invocation handler is already registered");
180 }
181 _invoker = handler;
182 }
183
184 /***
185 * Ping the connection. The connection event listener will be notified
186 * if the ping succeeds.
187 *
188 * @throws ResourceException for any error
189 */
190 public void ping() throws ResourceException {
191 VMInvoker invoker;
192 synchronized (this) {
193 invoker = _remoteInvoker;
194 }
195 if (invoker == null) {
196 throw new IllegalStateException("No connection");
197 }
198 if (invoker.isAlive()) {
199 ManagedConnectionListener listener = getConnectionEventListener();
200 if (listener != null) {
201 listener.pinged(this);
202 }
203 }
204 }
205
206 /***
207 * Destroys the physical connection.
208 *
209 * @throws ResourceException for any error
210 */
211 public void destroy() throws ResourceException {
212 VMInvoker invoker;
213 synchronized (this) {
214 invoker = _remoteInvoker;
215 _remoteInvoker = null;
216 }
217 if (invoker != null) {
218 invoker.destroy();
219 }
220 }
221
222 /***
223 * Returns the remote address to which this is connected.
224 *
225 * @return the remote address to which this is connected
226 */
227 public URI getRemoteURI() {
228 return _remoteURI;
229 }
230
231 /***
232 * Returns the local address that this connection is bound to.
233 *
234 * @return the local address that this connection is bound to
235 */
236 public URI getLocalURI() {
237 return _localURI;
238 }
239
240 /***
241 * Returns the principal associated with this connection.
242 *
243 * @return the principal associated with this connection,
244 * or <code>null<code> if none is set
245 */
246 public Principal getPrincipal() {
247 return _principal;
248 }
249
250 /***
251 * Determines if the security principal that owns this connection is the
252 * same as that supplied.
253 *
254 * @param principal the principal to compare. May be <code>null</code>.
255 * @return <code>true</code> if the principal that owns this connection is
256 * the same as <code>principal</code>
257 */
258 public boolean hasPrincipal(Principal principal) {
259 boolean result = false;
260 if ((_principal != null && _principal.equals(principal))
261 || (_principal == null && principal == null)) {
262 result = true;
263 }
264 return result;
265 }
266
267 /***
268 * Invoke a method on a remote object.
269 *
270 * @param connection the connection performing the invocation
271 * @param request the request
272 * @return the result of the invocation
273 */
274 protected Response invoke(Connection connection, Request request) {
275 Response response;
276 try {
277 MarshalledObject wrappedRequest = new MarshalledObject(request);
278 MarshalledObject wrappedResponse =
279 _remoteInvoker.invoke(wrappedRequest);
280 response = (Response) wrappedResponse.get();
281 } catch (ClassNotFoundException exception) {
282 response = new Response(exception);
283 } catch (IOException exception) {
284 response = new Response(exception);
285 }
286 return response;
287 }
288
289 /***
290 * Invoke a method on a local object.
291 *
292 * @param request the wrapped <code>Request</code>
293 * @return the wrapped <code>Response</code>
294 * @throws MarshalException if the request can't be unmarshalled or the
295 * response can't be marshalled
296 */
297 protected MarshalledObject invokeLocal(MarshalledObject request)
298 throws MarshalException {
299 MarshalledInvocation invocation
300 = new MarshalledInvocation(request, _caller);
301
302 _invoker.invoke(invocation);
303 MarshalledObject response;
304 try {
305 response = invocation.getMarshalledResponse();
306 } catch (Exception exception) {
307 throw new MarshalException("Failed to marshal response",
308 exception);
309 }
310 return response;
311 }
312
313 /***
314 * Determines if the local end of the connection is alive.
315 *
316 * @return <code>true</code> if the connection is alive
317 */
318 protected boolean isAliveLocal() {
319 boolean alive;
320 synchronized (this) {
321 alive = (_remoteInvoker != null);
322 }
323 return alive;
324 }
325
326 /***
327 * Destroys the connection.
328 *
329 * @throws ResourceException for any error
330 */
331 protected void destroyLocal() throws ResourceException {
332 synchronized (this) {
333 _remoteInvoker = null;
334 }
335 ManagedConnectionListener listener = getConnectionEventListener();
336 if (listener != null) {
337 listener.closed(this);
338 }
339 }
340
341 }