1 16 17 package org.springframework.remoting.jaxrpc; 18 19 import java.lang.reflect.InvocationTargetException ; 20 import java.rmi.Remote ; 21 import java.rmi.RemoteException ; 22 import java.util.HashMap ; 23 import java.util.Iterator ; 24 import java.util.Map ; 25 import java.util.Properties ; 26 27 import javax.xml.namespace.QName ; 28 import javax.xml.rpc.Call ; 29 import javax.xml.rpc.JAXRPCException ; 30 import javax.xml.rpc.Service ; 31 import javax.xml.rpc.ServiceException ; 32 import javax.xml.rpc.Stub ; 33 34 import org.aopalliance.intercept.MethodInterceptor; 35 import org.aopalliance.intercept.MethodInvocation; 36 37 import org.springframework.aop.support.AopUtils; 38 import org.springframework.beans.factory.InitializingBean; 39 import org.springframework.remoting.RemoteLookupFailureException; 40 import org.springframework.remoting.RemoteProxyFailureException; 41 import org.springframework.remoting.rmi.RmiClientInterceptorUtils; 42 import org.springframework.util.CollectionUtils; 43 44 76 public class JaxRpcPortClientInterceptor extends LocalJaxRpcServiceFactory 77 implements MethodInterceptor, InitializingBean { 78 79 private Service jaxRpcService; 80 81 private Service serviceToUse; 82 83 private String portName; 84 85 private String username; 86 87 private String password; 88 89 private String endpointAddress; 90 91 private boolean maintainSession; 92 93 94 private final Map customPropertyMap = new HashMap (); 95 96 private Class serviceInterface; 97 98 private Class portInterface; 99 100 private boolean lookupServiceOnStartup = true; 101 102 private boolean refreshServiceAfterConnectFailure = false; 103 104 private QName portQName; 105 106 private Remote portStub; 107 108 private final Object preparationMonitor = new Object (); 109 110 111 121 public void setJaxRpcService(Service jaxRpcService) { 122 this.jaxRpcService = jaxRpcService; 123 } 124 125 128 public Service getJaxRpcService() { 129 return this.jaxRpcService; 130 } 131 132 136 public void setPortName(String portName) { 137 this.portName = portName; 138 } 139 140 143 public String getPortName() { 144 return this.portName; 145 } 146 147 152 public void setUsername(String username) { 153 this.username = username; 154 } 155 156 159 public String getUsername() { 160 return this.username; 161 } 162 163 168 public void setPassword(String password) { 169 this.password = password; 170 } 171 172 175 public String getPassword() { 176 return this.password; 177 } 178 179 184 public void setEndpointAddress(String endpointAddress) { 185 this.endpointAddress = endpointAddress; 186 } 187 188 191 public String getEndpointAddress() { 192 return this.endpointAddress; 193 } 194 195 200 public void setMaintainSession(boolean maintainSession) { 201 this.maintainSession = maintainSession; 202 } 203 204 207 public boolean isMaintainSession() { 208 return this.maintainSession; 209 } 210 211 218 public void setCustomProperties(Properties customProperties) { 219 CollectionUtils.mergePropertiesIntoMap(customProperties, this.customPropertyMap); 220 } 221 222 228 public void setCustomPropertyMap(Map customProperties) { 229 if (customProperties != null) { 230 Iterator it = customProperties.entrySet().iterator(); 231 while (it.hasNext()) { 232 Map.Entry entry = (Map.Entry ) it.next(); 233 if (!(entry.getKey() instanceof String )) { 234 throw new IllegalArgumentException ( 235 "Illegal property key [" + entry.getKey() + "]: only Strings allowed"); 236 } 237 addCustomProperty((String ) entry.getKey(), entry.getValue()); 238 } 239 } 240 } 241 242 249 public Map getCustomPropertyMap() { 250 return this.customPropertyMap; 251 } 252 253 260 public void addCustomProperty(String name, Object value) { 261 this.customPropertyMap.put(name, value); 262 } 263 264 279 public void setServiceInterface(Class serviceInterface) { 280 if (serviceInterface != null && !serviceInterface.isInterface()) { 281 throw new IllegalArgumentException ("serviceInterface must be an interface"); 282 } 283 this.serviceInterface = serviceInterface; 284 } 285 286 289 public Class getServiceInterface() { 290 return this.serviceInterface; 291 } 292 293 307 public void setPortInterface(Class portInterface) { 308 if (portInterface != null && 309 (!portInterface.isInterface() || !Remote .class.isAssignableFrom(portInterface))) { 310 throw new IllegalArgumentException ( 311 "portInterface must be an interface derived from [java.rmi.Remote]"); 312 } 313 this.portInterface = portInterface; 314 } 315 316 319 public Class getPortInterface() { 320 return this.portInterface; 321 } 322 323 329 public void setLookupServiceOnStartup(boolean lookupServiceOnStartup) { 330 this.lookupServiceOnStartup = lookupServiceOnStartup; 331 } 332 333 341 public void setRefreshServiceAfterConnectFailure(boolean refreshServiceAfterConnectFailure) { 342 this.refreshServiceAfterConnectFailure = refreshServiceAfterConnectFailure; 343 } 344 345 346 350 public void afterPropertiesSet() throws ServiceException { 351 if (this.lookupServiceOnStartup) { 352 prepare(); 353 } 354 } 355 356 373 public void prepare() throws ServiceException , RemoteLookupFailureException { 374 if (getPortName() == null) { 375 throw new IllegalArgumentException ("Property 'portName' is required"); 376 } 377 378 synchronized (this.preparationMonitor) { 379 this.serviceToUse = null; 380 381 this.portQName = getQName(getPortName()); 383 384 Service service = getJaxRpcService(); 385 if (service == null) { 386 service = createJaxRpcService(); 387 } 388 else { 389 postProcessJaxRpcService(service); 390 } 391 392 Class portInterface = getPortInterface(); 393 if (portInterface != null && !alwaysUseJaxRpcCall()) { 394 396 if (logger.isDebugEnabled()) { 397 logger.debug("Creating JAX-RPC proxy for JAX-RPC port [" + this.portQName + 398 "], using port interface [" + portInterface.getName() + "]"); 399 } 400 Remote remoteObj = service.getPort(this.portQName, portInterface); 401 402 if (logger.isDebugEnabled()) { 403 Class serviceInterface = getServiceInterface(); 404 if (serviceInterface != null) { 405 boolean isImpl = serviceInterface.isInstance(remoteObj); 406 logger.debug("Using service interface [" + serviceInterface.getName() + "] for JAX-RPC port [" + 407 this.portQName + "] - " + (!isImpl ? "not" : "") + " directly implemented"); 408 } 409 } 410 411 if (!(remoteObj instanceof Stub )) { 412 throw new RemoteLookupFailureException("Port stub of class [" + remoteObj.getClass().getName() + 413 "] is not a valid JAX-RPC stub: it does not implement interface [javax.xml.rpc.Stub]"); 414 } 415 Stub stub = (Stub ) remoteObj; 416 417 preparePortStub(stub); 419 420 postProcessPortStub(stub); 422 423 this.portStub = remoteObj; 424 } 425 426 else { 427 if (logger.isDebugEnabled()) { 429 logger.debug("Using JAX-RPC dynamic calls for JAX-RPC port [" + this.portQName + "]"); 430 } 431 } 432 433 this.serviceToUse = service; 434 } 435 } 436 437 449 protected boolean alwaysUseJaxRpcCall() { 450 return false; 451 } 452 453 457 protected void reset() { 458 synchronized (this.preparationMonitor) { 459 this.serviceToUse = null; 460 } 461 } 462 463 467 protected boolean isPrepared() { 468 synchronized (this.preparationMonitor) { 469 return (this.serviceToUse != null); 470 } 471 } 472 473 478 protected QName getPortQName() { 479 return this.portQName; 480 } 481 482 483 499 protected void preparePortStub(Stub stub) { 500 String username = getUsername(); 501 if (username != null) { 502 stub._setProperty(Stub.USERNAME_PROPERTY, username); 503 } 504 String password = getPassword(); 505 if (password != null) { 506 stub._setProperty(Stub.PASSWORD_PROPERTY, password); 507 } 508 String endpointAddress = getEndpointAddress(); 509 if (endpointAddress != null) { 510 stub._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, endpointAddress); 511 } 512 if (isMaintainSession()) { 513 stub._setProperty(Stub.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE); 514 } 515 if (this.customPropertyMap != null) { 516 for (Iterator it = this.customPropertyMap.keySet().iterator(); it.hasNext();) { 517 String key = (String ) it.next(); 518 stub._setProperty(key, this.customPropertyMap.get(key)); 519 } 520 } 521 } 522 523 535 protected void postProcessPortStub(Stub stub) { 536 } 537 538 542 protected Remote getPortStub() { 543 return this.portStub; 544 } 545 546 547 554 public Object invoke(MethodInvocation invocation) throws Throwable { 555 if (AopUtils.isToStringMethod(invocation.getMethod())) { 556 return "JAX-RPC proxy for port [" + getPortName() + "] of service [" + getServiceName() + "]"; 557 } 558 559 if (!this.lookupServiceOnStartup || this.refreshServiceAfterConnectFailure) { 561 synchronized (this.preparationMonitor) { 562 if (!isPrepared()) { 563 try { 564 prepare(); 565 } 566 catch (ServiceException ex) { 567 throw new RemoteLookupFailureException("Preparation of JAX-RPC service failed", ex); 568 } 569 } 570 } 571 } 572 else { 573 if (!isPrepared()) { 574 throw new IllegalStateException ("JaxRpcClientInterceptor is not properly initialized - " + 575 "invoke 'prepare' before attempting any operations"); 576 } 577 } 578 579 return doInvoke(invocation); 580 } 581 582 593 protected Object doInvoke(MethodInvocation invocation) throws Throwable { 594 Remote stub = getPortStub(); 595 if (stub != null) { 596 if (logger.isTraceEnabled()) { 598 logger.trace("Invoking operation '" + invocation.getMethod().getName() + "' on JAX-RPC port stub"); 599 } 600 return doInvoke(invocation, stub); 601 } 602 else { 603 if (logger.isTraceEnabled()) { 605 logger.trace("Invoking operation '" + invocation.getMethod().getName() + "' as JAX-RPC dynamic call"); 606 } 607 return performJaxRpcCall(invocation); 608 } 609 } 610 611 621 protected Object doInvoke(MethodInvocation invocation, Remote portStub) throws Throwable { 622 try { 623 return RmiClientInterceptorUtils.doInvoke(invocation, portStub); 624 } 625 catch (InvocationTargetException ex) { 626 Throwable targetEx = ex.getTargetException(); 627 if (targetEx instanceof RemoteException ) { 628 RemoteException rex = (RemoteException ) targetEx; 629 boolean isConnectFailure = isConnectFailure(rex); 630 if (isConnectFailure && this.refreshServiceAfterConnectFailure) { 631 reset(); 632 } 633 throw RmiClientInterceptorUtils.convertRmiAccessException( 634 invocation.getMethod(), rex, isConnectFailure, portQName.toString()); 635 } 636 else if (targetEx instanceof JAXRPCException ) { 637 throw new RemoteProxyFailureException("Invalid call on JAX-RPC port stub", targetEx); 638 } 639 else { 640 throw targetEx; 641 } 642 } 643 } 644 645 650 protected Object performJaxRpcCall(MethodInvocation invocation) throws Throwable { 651 return performJaxRpcCall(invocation, this.serviceToUse); 652 } 653 654 669 protected Object performJaxRpcCall(MethodInvocation invocation, Service service) throws Throwable { 670 QName portQName = getPortQName(); 671 672 Call call = null; 675 synchronized (service) { 676 call = service.createCall(portQName, invocation.getMethod().getName()); 677 } 678 679 prepareJaxRpcCall(call); 681 682 postProcessJaxRpcCall(call, invocation); 684 685 try { 687 return call.invoke(invocation.getArguments()); 688 } 689 catch (RemoteException ex) { 690 boolean isConnectFailure = isConnectFailure(ex); 691 if (isConnectFailure && this.refreshServiceAfterConnectFailure) { 692 reset(); 693 } 694 throw RmiClientInterceptorUtils.convertRmiAccessException( 695 invocation.getMethod(), ex, isConnectFailure, portQName.toString()); 696 } 697 catch (JAXRPCException ex) { 698 throw new RemoteProxyFailureException("Invalid JAX-RPC call configuration", ex); 699 } 700 } 701 702 718 protected void prepareJaxRpcCall(Call call) { 719 String username = getUsername(); 720 if (username != null) { 721 call.setProperty(Call.USERNAME_PROPERTY, username); 722 } 723 String password = getPassword(); 724 if (password != null) { 725 call.setProperty(Call.PASSWORD_PROPERTY, password); 726 } 727 String endpointAddress = getEndpointAddress(); 728 if (endpointAddress != null) { 729 call.setTargetEndpointAddress(endpointAddress); 730 } 731 if (isMaintainSession()) { 732 call.setProperty(Call.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE); 733 } 734 if (this.customPropertyMap != null) { 735 for (Iterator it = this.customPropertyMap.keySet().iterator(); it.hasNext();) { 736 String key = (String ) it.next(); 737 call.setProperty(key, this.customPropertyMap.get(key)); 738 } 739 } 740 } 741 742 757 protected void postProcessJaxRpcCall(Call call, MethodInvocation invocation) { 758 } 759 760 769 protected boolean isConnectFailure(RemoteException ex) { 770 return true; 771 } 772 773 } 774 | Popular Tags |