1 16 17 package org.springframework.remoting.rmi; 18 19 import java.lang.reflect.InvocationTargetException ; 20 import java.rmi.Remote ; 21 import java.rmi.RemoteException ; 22 23 import javax.naming.NamingException ; 24 import javax.rmi.PortableRemoteObject ; 25 26 import org.aopalliance.intercept.MethodInterceptor; 27 import org.aopalliance.intercept.MethodInvocation; 28 29 import org.springframework.aop.support.AopUtils; 30 import org.springframework.beans.factory.InitializingBean; 31 import org.springframework.jndi.JndiObjectLocator; 32 import org.springframework.remoting.RemoteConnectFailureException; 33 import org.springframework.remoting.RemoteLookupFailureException; 34 import org.springframework.remoting.RemoteProxyFailureException; 35 import org.springframework.remoting.support.DefaultRemoteInvocationFactory; 36 import org.springframework.remoting.support.RemoteInvocation; 37 import org.springframework.remoting.support.RemoteInvocationFactory; 38 39 75 public class JndiRmiClientInterceptor extends JndiObjectLocator 76 implements MethodInterceptor, InitializingBean { 77 78 private Class serviceInterface; 79 80 private RemoteInvocationFactory remoteInvocationFactory = new DefaultRemoteInvocationFactory(); 81 82 private boolean lookupStubOnStartup = true; 83 84 private boolean cacheStub = true; 85 86 private boolean refreshStubOnConnectFailure = false; 87 88 private Remote cachedStub; 89 90 private final Object stubMonitor = new Object (); 91 92 93 99 public void setServiceInterface(Class serviceInterface) { 100 if (serviceInterface != null && !serviceInterface.isInterface()) { 101 throw new IllegalArgumentException ("'serviceInterface' must be an interface"); 102 } 103 this.serviceInterface = serviceInterface; 104 } 105 106 109 public Class getServiceInterface() { 110 return this.serviceInterface; 111 } 112 113 119 public void setRemoteInvocationFactory(RemoteInvocationFactory remoteInvocationFactory) { 120 this.remoteInvocationFactory = remoteInvocationFactory; 121 } 122 123 126 public RemoteInvocationFactory getRemoteInvocationFactory() { 127 return this.remoteInvocationFactory; 128 } 129 130 136 public void setLookupStubOnStartup(boolean lookupStubOnStartup) { 137 this.lookupStubOnStartup = lookupStubOnStartup; 138 } 139 140 147 public void setCacheStub(boolean cacheStub) { 148 this.cacheStub = cacheStub; 149 } 150 151 162 public void setRefreshStubOnConnectFailure(boolean refreshStubOnConnectFailure) { 163 this.refreshStubOnConnectFailure = refreshStubOnConnectFailure; 164 } 165 166 167 public void afterPropertiesSet() throws NamingException { 168 super.afterPropertiesSet(); 169 prepare(); 170 } 171 172 181 public void prepare() throws NamingException , RemoteLookupFailureException { 182 if (this.lookupStubOnStartup) { 184 Remote remoteObj = lookupStub(); 185 if (logger.isDebugEnabled()) { 186 if (remoteObj instanceof RmiInvocationHandler) { 187 logger.debug("JNDI RMI object [" + getJndiName() + "] is an RMI invoker"); 188 } 189 else if (getServiceInterface() != null) { 190 boolean isImpl = getServiceInterface().isInstance(remoteObj); 191 logger.debug("Using service interface [" + getServiceInterface().getName() + 192 "] for JNDI RMI object [" + getJndiName() + "] - " + 193 (!isImpl ? "not " : "") + "directly implemented"); 194 } 195 } 196 if (this.cacheStub) { 197 this.cachedStub = remoteObj; 198 } 199 } 200 } 201 202 214 protected Remote lookupStub() throws NamingException , RemoteLookupFailureException { 215 Object stub = lookup(); 216 if (getServiceInterface() != null && Remote .class.isAssignableFrom(getServiceInterface())) { 217 try { 218 stub = PortableRemoteObject.narrow(stub, getServiceInterface()); 219 } 220 catch (ClassCastException ex) { 221 throw new RemoteLookupFailureException( 222 "Could not narrow RMI stub to service interface [" + getServiceInterface().getName() + "]", ex); 223 } 224 } 225 if (!(stub instanceof Remote )) { 226 throw new RemoteLookupFailureException("Located RMI stub of class [" + stub.getClass().getName() + 227 "], with JNDI name [" + getJndiName() + "], does not implement interface [java.rmi.Remote]"); 228 } 229 return (Remote ) stub; 230 } 231 232 243 protected Remote getStub() throws NamingException , RemoteLookupFailureException { 244 if (!this.cacheStub || (this.lookupStubOnStartup && !this.refreshStubOnConnectFailure)) { 245 return (this.cachedStub != null ? this.cachedStub : lookupStub()); 246 } 247 else { 248 synchronized (this.stubMonitor) { 249 if (this.cachedStub == null) { 250 this.cachedStub = lookupStub(); 251 } 252 return this.cachedStub; 253 } 254 } 255 } 256 257 258 269 public Object invoke(MethodInvocation invocation) throws Throwable { 270 Remote stub = null; 271 try { 272 stub = getStub(); 273 } 274 catch (NamingException ex) { 275 throw new RemoteLookupFailureException("JNDI lookup for RMI service [" + getJndiName() + "] failed", ex); 276 } 277 try { 278 return doInvoke(invocation, stub); 279 } 280 catch (RemoteConnectFailureException ex) { 281 return handleRemoteConnectFailure(invocation, ex); 282 } 283 catch (RemoteException ex) { 284 if (isConnectFailure(ex)) { 285 return handleRemoteConnectFailure(invocation, ex); 286 } 287 else { 288 throw ex; 289 } 290 } 291 } 292 293 300 protected boolean isConnectFailure(RemoteException ex) { 301 return RmiClientInterceptorUtils.isConnectFailure(ex); 302 } 303 304 313 private Object handleRemoteConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable { 314 if (this.refreshStubOnConnectFailure) { 315 if (logger.isDebugEnabled()) { 316 logger.debug("Could not connect to RMI service [" + getJndiName() + "] - retrying", ex); 317 } 318 else if (logger.isWarnEnabled()) { 319 logger.warn("Could not connect to RMI service [" + getJndiName() + "] - retrying"); 320 } 321 return refreshAndRetry(invocation); 322 } 323 else { 324 throw ex; 325 } 326 } 327 328 336 protected Object refreshAndRetry(MethodInvocation invocation) throws Throwable { 337 Remote freshStub = null; 338 synchronized (this.stubMonitor) { 339 try { 340 freshStub = lookupStub(); 341 } 342 catch (NamingException ex) { 343 throw new RemoteLookupFailureException("JNDI lookup for RMI service [" + getJndiName() + "] failed", ex); 344 } 345 if (this.cacheStub) { 346 this.cachedStub = freshStub; 347 } 348 } 349 return doInvoke(invocation, freshStub); 350 } 351 352 359 protected Object doInvoke(MethodInvocation invocation, Remote stub) throws Throwable { 360 if (stub instanceof RmiInvocationHandler) { 361 try { 363 return doInvoke(invocation, (RmiInvocationHandler) stub); 364 } 365 catch (RemoteException ex) { 366 throw RmiClientInterceptorUtils.convertRmiAccessException( 367 invocation.getMethod(), ex, isConnectFailure(ex), getJndiName()); 368 } 369 catch (InvocationTargetException ex) { 370 throw ex.getTargetException(); 371 } 372 catch (Throwable ex) { 373 throw new RemoteProxyFailureException( 374 "Failed to invoke RMI stub for remote service [" + getJndiName() + "]", ex); 375 } 376 } 377 else { 378 try { 380 return RmiClientInterceptorUtils.doInvoke(invocation, stub); 381 } 382 catch (InvocationTargetException ex) { 383 Throwable targetEx = ex.getTargetException(); 384 if (targetEx instanceof RemoteException ) { 385 RemoteException rex = (RemoteException ) targetEx; 386 throw RmiClientInterceptorUtils.convertRmiAccessException( 387 invocation.getMethod(), rex, isConnectFailure(rex), getJndiName()); 388 } 389 else { 390 throw targetEx; 391 } 392 } 393 } 394 } 395 396 408 protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler) 409 throws RemoteException , NoSuchMethodException , IllegalAccessException , InvocationTargetException { 410 411 if (AopUtils.isToStringMethod(methodInvocation.getMethod())) { 412 return "RMI invoker proxy for service URL [" + getJndiName() + "]"; 413 } 414 415 return invocationHandler.invoke(createRemoteInvocation(methodInvocation)); 416 } 417 418 430 protected RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { 431 return getRemoteInvocationFactory().createRemoteInvocation(methodInvocation); 432 } 433 434 } 435 | Popular Tags |