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 }