KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > remoting > jaxrpc > JaxRpcPortClientInterceptor


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.remoting.jaxrpc;
18
19 import java.lang.reflect.InvocationTargetException JavaDoc;
20 import java.rmi.Remote JavaDoc;
21 import java.rmi.RemoteException JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.Properties JavaDoc;
26
27 import javax.xml.namespace.QName JavaDoc;
28 import javax.xml.rpc.Call JavaDoc;
29 import javax.xml.rpc.JAXRPCException JavaDoc;
30 import javax.xml.rpc.Service JavaDoc;
31 import javax.xml.rpc.ServiceException JavaDoc;
32 import javax.xml.rpc.Stub JavaDoc;
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 /**
45  * Interceptor for accessing a specific port of a JAX-RPC service.
46  * Uses either {@link LocalJaxRpcServiceFactory}'s facilities underneath,
47  * or takes an explicit reference to an existing JAX-RPC Service instance
48  * (e.g. obtained via {@link org.springframework.jndi.JndiObjectFactoryBean}).
49  *
50  * <p>Allows to set JAX-RPC's standard stub properties directly, via the
51  * "username", "password", "endpointAddress" and "maintainSession" properties.
52  * For typical usage, it is not necessary to specify those.
53  *
54  * <p>In standard JAX-RPC style, this invoker is used with an RMI service interface.
55  * Alternatively, this invoker can also proxy a JAX-RPC service with a matching
56  * non-RMI business interface, that is, an interface that declares the service methods
57  * without RemoteExceptions. In the latter case, RemoteExceptions thrown by JAX-RPC
58  * will automatically get converted to Spring's unchecked RemoteAccessException.
59  *
60  * <p>Setting "serviceInterface" is usually sufficient: The invoker will automatically
61  * use JAX-RPC "dynamic invocations" via the Call API in this case, no matter whether
62  * the specified interface is an RMI or non-RMI interface. Alternatively, a corresponding
63  * JAX-RPC port interface can be specified as "portInterface", which will turn this
64  * invoker into "static invocation" mode (operating on a standard JAX-RPC port stub).
65  *
66  * @author Juergen Hoeller
67  * @since 15.12.2003
68  * @see #setPortName
69  * @see #setServiceInterface
70  * @see #setPortInterface
71  * @see javax.xml.rpc.Service#createCall
72  * @see javax.xml.rpc.Service#getPort
73  * @see org.springframework.remoting.RemoteAccessException
74  * @see org.springframework.jndi.JndiObjectFactoryBean
75  */

76 public class JaxRpcPortClientInterceptor extends LocalJaxRpcServiceFactory
77         implements MethodInterceptor, InitializingBean {
78
79     private Service JavaDoc jaxRpcService;
80
81     private Service JavaDoc serviceToUse;
82
83     private String JavaDoc portName;
84
85     private String JavaDoc username;
86
87     private String JavaDoc password;
88
89     private String JavaDoc endpointAddress;
90
91     private boolean maintainSession;
92
93     /** Map of custom properties, keyed by property name (String) */
94     private final Map JavaDoc customPropertyMap = new HashMap JavaDoc();
95
96     private Class JavaDoc serviceInterface;
97
98     private Class JavaDoc portInterface;
99
100     private boolean lookupServiceOnStartup = true;
101
102     private boolean refreshServiceAfterConnectFailure = false;
103
104     private QName JavaDoc portQName;
105
106     private Remote JavaDoc portStub;
107
108     private final Object JavaDoc preparationMonitor = new Object JavaDoc();
109
110
111     /**
112      * Set a reference to an existing JAX-RPC Service instance,
113      * for example obtained via {@link org.springframework.jndi.JndiObjectFactoryBean}.
114      * If not set, LocalJaxRpcServiceFactory's properties have to be specified.
115      * @see #setServiceFactoryClass
116      * @see #setWsdlDocumentUrl
117      * @see #setNamespaceUri
118      * @see #setServiceName
119      * @see org.springframework.jndi.JndiObjectFactoryBean
120      */

121     public void setJaxRpcService(Service JavaDoc jaxRpcService) {
122         this.jaxRpcService = jaxRpcService;
123     }
124
125     /**
126      * Return a reference to an existing JAX-RPC Service instance, if any.
127      */

128     public Service JavaDoc getJaxRpcService() {
129         return this.jaxRpcService;
130     }
131
132     /**
133      * Set the name of the port.
134      * Corresponds to the "wsdl:port" name.
135      */

136     public void setPortName(String JavaDoc portName) {
137         this.portName = portName;
138     }
139
140     /**
141      * Return the name of the port.
142      */

143     public String JavaDoc getPortName() {
144         return this.portName;
145     }
146
147     /**
148      * Set the username to specify on the stub or call.
149      * @see javax.xml.rpc.Stub#USERNAME_PROPERTY
150      * @see javax.xml.rpc.Call#USERNAME_PROPERTY
151      */

152     public void setUsername(String JavaDoc username) {
153         this.username = username;
154     }
155
156     /**
157      * Return the username to specify on the stub or call.
158      */

159     public String JavaDoc getUsername() {
160         return this.username;
161     }
162
163     /**
164      * Set the password to specify on the stub or call.
165      * @see javax.xml.rpc.Stub#PASSWORD_PROPERTY
166      * @see javax.xml.rpc.Call#PASSWORD_PROPERTY
167      */

168     public void setPassword(String JavaDoc password) {
169         this.password = password;
170     }
171
172     /**
173      * Return the password to specify on the stub or call.
174      */

175     public String JavaDoc getPassword() {
176         return this.password;
177     }
178
179     /**
180      * Set the endpoint address to specify on the stub or call.
181      * @see javax.xml.rpc.Stub#ENDPOINT_ADDRESS_PROPERTY
182      * @see javax.xml.rpc.Call#setTargetEndpointAddress
183      */

184     public void setEndpointAddress(String JavaDoc endpointAddress) {
185         this.endpointAddress = endpointAddress;
186     }
187
188     /**
189      * Return the endpoint address to specify on the stub or call.
190      */

191     public String JavaDoc getEndpointAddress() {
192         return this.endpointAddress;
193     }
194
195     /**
196      * Set the maintain session flag to specify on the stub or call.
197      * @see javax.xml.rpc.Stub#SESSION_MAINTAIN_PROPERTY
198      * @see javax.xml.rpc.Call#SESSION_MAINTAIN_PROPERTY
199      */

200     public void setMaintainSession(boolean maintainSession) {
201         this.maintainSession = maintainSession;
202     }
203
204     /**
205      * Return the maintain session flag to specify on the stub or call.
206      */

207     public boolean isMaintainSession() {
208         return this.maintainSession;
209     }
210
211     /**
212      * Set custom properties to be set on the stub or call.
213      * <p>Can be populated with a String "value" (parsed via PropertiesEditor)
214      * or a "props" element in XML bean definitions.
215      * @see javax.xml.rpc.Stub#_setProperty
216      * @see javax.xml.rpc.Call#setProperty
217      */

218     public void setCustomProperties(Properties JavaDoc customProperties) {
219         CollectionUtils.mergePropertiesIntoMap(customProperties, this.customPropertyMap);
220     }
221
222     /**
223      * Set custom properties to be set on the stub or call.
224      * <p>Can be populated with a "map" or "props" element in XML bean definitions.
225      * @see javax.xml.rpc.Stub#_setProperty
226      * @see javax.xml.rpc.Call#setProperty
227      */

228     public void setCustomPropertyMap(Map JavaDoc customProperties) {
229         if (customProperties != null) {
230             Iterator JavaDoc it = customProperties.entrySet().iterator();
231             while (it.hasNext()) {
232                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
233                 if (!(entry.getKey() instanceof String JavaDoc)) {
234                     throw new IllegalArgumentException JavaDoc(
235                             "Illegal property key [" + entry.getKey() + "]: only Strings allowed");
236                 }
237                 addCustomProperty((String JavaDoc) entry.getKey(), entry.getValue());
238             }
239         }
240     }
241
242     /**
243      * Allow Map access to the custom properties to be set on the stub
244      * or call, with the option to add or override specific entries.
245      * <p>Useful for specifying entries directly, for example via
246      * "customPropertyMap[myKey]". This is particularly useful for
247      * adding or overriding entries in child bean definitions.
248      */

249     public Map JavaDoc getCustomPropertyMap() {
250         return this.customPropertyMap;
251     }
252
253     /**
254      * Add a custom property to this JAX-RPC Stub/Call.
255      * @param name the name of the attribute to expose
256      * @param value the attribute value to expose
257      * @see javax.xml.rpc.Stub#_setProperty
258      * @see javax.xml.rpc.Call#setProperty
259      */

260     public void addCustomProperty(String JavaDoc name, Object JavaDoc value) {
261         this.customPropertyMap.put(name, value);
262     }
263
264     /**
265      * Set the interface of the service that this factory should create a proxy for.
266      * This will typically be a non-RMI business interface, although you can also
267      * use an RMI port interface as recommended by JAX-RPC here.
268      * <p>Calls on the specified service interface will either be translated to the
269      * underlying RMI port interface (in case of a "portInterface" being specified)
270      * or to dynamic calls (using the JAX-RPC Dynamic Invocation Interface).
271      * <p>The dynamic call mechanism has the advantage that you don't need to
272      * maintain an RMI port interface in addition to an existing non-RMI business
273      * interface. In terms of configuration, specifying the business interface
274      * as "serviceInterface" will be enough; this interceptor will automatically
275      * use dynamic calls in such a scenario.
276      * @see javax.xml.rpc.Service#createCall
277      * @see #setPortInterface
278      */

279     public void setServiceInterface(Class JavaDoc serviceInterface) {
280         if (serviceInterface != null && !serviceInterface.isInterface()) {
281             throw new IllegalArgumentException JavaDoc("serviceInterface must be an interface");
282         }
283         this.serviceInterface = serviceInterface;
284     }
285
286     /**
287      * Return the interface of the service that this factory should create a proxy for.
288      */

289     public Class JavaDoc getServiceInterface() {
290         return this.serviceInterface;
291     }
292
293     /**
294      * Set the JAX-RPC port interface to use. Only needs to be set if a JAX-RPC
295      * port stub should be used instead of the dynamic call mechanism.
296      * See the javadoc of the "serviceInterface" property for more details.
297      * <p>The interface must be suitable for a JAX-RPC port, that is, it must be
298      * an RMI service interface (that extends <code>java.rmi.Remote</code>).
299      * <p><b>NOTE:</b> Check whether your JAX-RPC provider returns thread-safe
300      * port stubs. If not, use the dynamic call mechanism instead, which will
301      * always be thread-safe. In particular, do not use JAX-RPC port stubs
302      * with Apache Axis, whose port stubs are known to be non-thread-safe.
303      * @see javax.xml.rpc.Service#getPort
304      * @see java.rmi.Remote
305      * @see #setServiceInterface
306      */

307     public void setPortInterface(Class JavaDoc portInterface) {
308         if (portInterface != null &&
309                 (!portInterface.isInterface() || !Remote JavaDoc.class.isAssignableFrom(portInterface))) {
310             throw new IllegalArgumentException JavaDoc(
311                     "portInterface must be an interface derived from [java.rmi.Remote]");
312         }
313         this.portInterface = portInterface;
314     }
315
316     /**
317      * Return the JAX-RPC port interface to use.
318      */

319     public Class JavaDoc getPortInterface() {
320         return this.portInterface;
321     }
322
323     /**
324      * Set whether to look up the JAX-RPC service on startup.
325      * <p>Default is "true". Turn this flag off to allow for late start
326      * of the target server. In this case, the JAX-RPC service will be
327      * lazily fetched on first access.
328      */

329     public void setLookupServiceOnStartup(boolean lookupServiceOnStartup) {
330         this.lookupServiceOnStartup = lookupServiceOnStartup;
331     }
332
333     /**
334      * Set whether to refresh the JAX-RPC service on connect failure,
335      * that is, whenever a JAX-RPC invocation throws a RemoteException.
336      * <p>Default is "false", keeping a reference to the JAX-RPC service
337      * in any case, retrying the next invocation on the same service
338      * even in case of failure. Turn this flag on to reinitialize the
339      * entire service in case of connect failures.
340      */

341     public void setRefreshServiceAfterConnectFailure(boolean refreshServiceAfterConnectFailure) {
342         this.refreshServiceAfterConnectFailure = refreshServiceAfterConnectFailure;
343     }
344
345
346     /**
347      * Prepares the JAX-RPC service and port if the "lookupServiceOnStartup"
348      * is turned on (which it is by default).
349      */

350     public void afterPropertiesSet() throws ServiceException JavaDoc {
351         if (this.lookupServiceOnStartup) {
352             prepare();
353         }
354     }
355
356     /**
357      * Create and initialize the JAX-RPC service for the specified port.
358      * <p>Prepares a JAX-RPC stub if possible (if an RMI interface is available);
359      * falls back to JAX-RPC dynamic calls else. Using dynamic calls can be
360      * enforced through overriding <code>alwaysUseJaxRpcCall</code> to return true.
361      * <p><code>postProcessJaxRpcService</code> and <code>postProcessPortStub</code>
362      * hooks are available for customization in subclasses. When using dynamic calls,
363      * each can be post-processed via <code>postProcessJaxRpcCall</code>.
364      * <p>Note: As of Spring 2.1, this method will always throw
365      * RemoteLookupFailureException and not declare ServiceException anymore.
366      * @throws ServiceException in case of service initialization failure
367      * @throws RemoteLookupFailureException if port stub creation failed
368      * @see #alwaysUseJaxRpcCall
369      * @see #postProcessJaxRpcService
370      * @see #postProcessPortStub
371      * @see #postProcessJaxRpcCall
372      */

373     public void prepare() throws ServiceException JavaDoc, RemoteLookupFailureException {
374         if (getPortName() == null) {
375             throw new IllegalArgumentException JavaDoc("Property 'portName' is required");
376         }
377
378         synchronized (this.preparationMonitor) {
379             this.serviceToUse = null;
380
381             // Cache the QName for the port.
382
this.portQName = getQName(getPortName());
383
384             Service JavaDoc service = getJaxRpcService();
385             if (service == null) {
386                 service = createJaxRpcService();
387             }
388             else {
389                 postProcessJaxRpcService(service);
390             }
391
392             Class JavaDoc portInterface = getPortInterface();
393             if (portInterface != null && !alwaysUseJaxRpcCall()) {
394                 // JAX-RPC-compliant port interface -> using JAX-RPC stub for port.
395

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 JavaDoc remoteObj = service.getPort(this.portQName, portInterface);
401
402                 if (logger.isDebugEnabled()) {
403                     Class JavaDoc 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 JavaDoc)) {
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 JavaDoc stub = (Stub JavaDoc) remoteObj;
416
417                 // Apply properties to JAX-RPC stub.
418
preparePortStub(stub);
419
420                 // Allow for custom post-processing in subclasses.
421
postProcessPortStub(stub);
422
423                 this.portStub = remoteObj;
424             }
425
426             else {
427                 // No JAX-RPC-compliant port interface -> using JAX-RPC dynamic calls.
428
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     /**
438      * Return whether to always use JAX-RPC dynamic calls.
439      * Called by <code>afterPropertiesSet</code>.
440      * <p>Default is "false"; if an RMI interface is specified as "portInterface"
441      * or "serviceInterface", it will be used to create a JAX-RPC port stub.
442      * <p>Can be overridden to enforce the use of the JAX-RPC Call API,
443      * for example if there is a need to customize at the Call level.
444      * This just necessary if you you want to use an RMI interface as
445      * "serviceInterface", though; in case of only a non-RMI interface being
446      * available, this interceptor will fall back to the Call API anyway.
447      * @see #postProcessJaxRpcCall
448      */

449     protected boolean alwaysUseJaxRpcCall() {
450         return false;
451     }
452
453     /**
454      * Reset the prepared service of this interceptor,
455      * allowing for reinitialization on next access.
456      */

457     protected void reset() {
458         synchronized (this.preparationMonitor) {
459             this.serviceToUse = null;
460         }
461     }
462
463     /**
464      * Return whether this client interceptor has already been prepared,
465      * i.e. has already looked up the JAX-RPC service and port.
466      */

467     protected boolean isPrepared() {
468         synchronized (this.preparationMonitor) {
469             return (this.serviceToUse != null);
470         }
471     }
472
473     /**
474      * Return the prepared QName for the port.
475      * @see #setPortName
476      * @see #getQName
477      */

478     protected QName JavaDoc getPortQName() {
479         return this.portQName;
480     }
481
482
483     /**
484      * Prepare the given JAX-RPC port stub, applying properties to it.
485      * Called by <code>afterPropertiesSet</code>.
486      * <p>Just applied when actually creating a JAX-RPC port stub,
487      * in case of a specified JAX-RPC-compliant port interface.
488      * Else, JAX-RPC dynamic calls will be used.
489      * @param stub the current JAX-RPC port stub
490      * @see #afterPropertiesSet
491      * @see #setUsername
492      * @see #setPassword
493      * @see #setEndpointAddress
494      * @see #setMaintainSession
495      * @see #setCustomProperties
496      * @see #setPortInterface
497      * @see #prepareJaxRpcCall
498      */

499     protected void preparePortStub(Stub JavaDoc stub) {
500         String JavaDoc username = getUsername();
501         if (username != null) {
502             stub._setProperty(Stub.USERNAME_PROPERTY, username);
503         }
504         String JavaDoc password = getPassword();
505         if (password != null) {
506             stub._setProperty(Stub.PASSWORD_PROPERTY, password);
507         }
508         String JavaDoc 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 JavaDoc it = this.customPropertyMap.keySet().iterator(); it.hasNext();) {
517                 String JavaDoc key = (String JavaDoc) it.next();
518                 stub._setProperty(key, this.customPropertyMap.get(key));
519             }
520         }
521     }
522
523     /**
524      * Post-process the given JAX-RPC port stub.
525      * Default implementation is empty. Called by <code>prepare</code>.
526      * <p>Just applied when actually creating a JAX-RPC port stub,
527      * in case of a specified JAX-RPC-compliant port interface.
528      * Else, JAX-RPC dynamic calls will be used.
529      * @param stub the current JAX-RPC port stub
530      * (can be cast to an implementation-specific class if necessary)
531      * @see #prepare
532      * @see #setPortInterface
533      * @see #postProcessJaxRpcCall
534      */

535     protected void postProcessPortStub(Stub JavaDoc stub) {
536     }
537
538     /**
539      * Return the underlying JAX-RPC port stub that this interceptor delegates to
540      * for each method invocation on the proxy.
541      */

542     protected Remote JavaDoc getPortStub() {
543         return this.portStub;
544     }
545
546
547     /**
548      * Translates the method invocation into a JAX-RPC service invocation.
549      * <p>Prepares the service on the fly, if necessary, in case of lazy
550      * lookup or a connect failure having happened.
551      * @see #prepare()
552      * @see #doInvoke
553      */

554     public Object JavaDoc invoke(MethodInvocation invocation) throws Throwable JavaDoc {
555         if (AopUtils.isToStringMethod(invocation.getMethod())) {
556             return "JAX-RPC proxy for port [" + getPortName() + "] of service [" + getServiceName() + "]";
557         }
558
559         // Lazily prepare service and stub if appropriate.
560
if (!this.lookupServiceOnStartup || this.refreshServiceAfterConnectFailure) {
561             synchronized (this.preparationMonitor) {
562                 if (!isPrepared()) {
563                     try {
564                         prepare();
565                     }
566                     catch (ServiceException JavaDoc 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 JavaDoc("JaxRpcClientInterceptor is not properly initialized - " +
575                         "invoke 'prepare' before attempting any operations");
576             }
577         }
578
579         return doInvoke(invocation);
580     }
581
582     /**
583      * Perform a JAX-RPC service invocation based on the given method invocation.
584      * <p>Uses traditional RMI stub invocation if a JAX-RPC port stub is available;
585      * falls back to JAX-RPC dynamic calls else.
586      * @param invocation the AOP method invocation
587      * @return the invocation result, if any
588      * @throws Throwable in case of invocation failure
589      * @see #getPortStub()
590      * @see #doInvoke(org.aopalliance.intercept.MethodInvocation, java.rmi.Remote)
591      * @see #performJaxRpcCall(org.aopalliance.intercept.MethodInvocation, javax.xml.rpc.Service)
592      */

593     protected Object JavaDoc doInvoke(MethodInvocation invocation) throws Throwable JavaDoc {
594         Remote JavaDoc stub = getPortStub();
595         if (stub != null) {
596             // JAX-RPC port stub available -> traditional RMI stub invocation.
597
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             // No JAX-RPC stub -> using JAX-RPC dynamic calls.
604
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     /**
612      * Perform a JAX-RPC service invocation based on the given port stub.
613      * @param invocation the AOP method invocation
614      * @param portStub the RMI port stub to invoke
615      * @return the invocation result, if any
616      * @throws Throwable in case of invocation failure
617      * @see #getPortStub()
618      * @see #doInvoke(org.aopalliance.intercept.MethodInvocation, java.rmi.Remote)
619      * @see #performJaxRpcCall
620      */

621     protected Object JavaDoc doInvoke(MethodInvocation invocation, Remote JavaDoc portStub) throws Throwable JavaDoc {
622         try {
623             return RmiClientInterceptorUtils.doInvoke(invocation, portStub);
624         }
625         catch (InvocationTargetException JavaDoc ex) {
626             Throwable JavaDoc targetEx = ex.getTargetException();
627             if (targetEx instanceof RemoteException JavaDoc) {
628                 RemoteException JavaDoc rex = (RemoteException JavaDoc) 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 JavaDoc) {
637                 throw new RemoteProxyFailureException("Invalid call on JAX-RPC port stub", targetEx);
638             }
639             else {
640                 throw targetEx;
641             }
642         }
643     }
644
645     /**
646      * @deprecated as of Spring 2.0.3, in favor of the <code>performJaxRpcCall</code>
647      * variant with an explicit Service argument
648      * @see #performJaxRpcCall(org.aopalliance.intercept.MethodInvocation, javax.xml.rpc.Service)
649      */

650     protected Object JavaDoc performJaxRpcCall(MethodInvocation invocation) throws Throwable JavaDoc {
651         return performJaxRpcCall(invocation, this.serviceToUse);
652     }
653
654     /**
655      * Perform a JAX-RPC dynamic call for the given AOP method invocation.
656      * Delegates to <code>prepareJaxRpcCall</code> and
657      * <code>postProcessJaxRpcCall</code> for setting up the call object.
658      * <p>Default implementation uses method name as JAX-RPC operation name
659      * and method arguments as arguments for the JAX-RPC call. Can be
660      * overridden in subclasses for custom operation names and/or arguments.
661      * @param invocation the current AOP MethodInvocation that should
662      * be converted to a JAX-RPC call
663      * @return the return value of the invocation, if any
664      * @throws Throwable the exception thrown by the invocation, if any
665      * @see #getPortQName
666      * @see #prepareJaxRpcCall
667      * @see #postProcessJaxRpcCall
668      */

669     protected Object JavaDoc performJaxRpcCall(MethodInvocation invocation, Service JavaDoc service) throws Throwable JavaDoc {
670         QName JavaDoc portQName = getPortQName();
671
672         // Create JAX-RPC call object, using the method name as operation name.
673
// Synchronized because of non-thread-safe Axis implementation!
674
Call JavaDoc call = null;
675         synchronized (service) {
676             call = service.createCall(portQName, invocation.getMethod().getName());
677         }
678
679         // Apply properties to JAX-RPC stub.
680
prepareJaxRpcCall(call);
681
682         // Allow for custom post-processing in subclasses.
683
postProcessJaxRpcCall(call, invocation);
684
685         // Perform actual invocation.
686
try {
687             return call.invoke(invocation.getArguments());
688         }
689         catch (RemoteException JavaDoc 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 JavaDoc ex) {
698             throw new RemoteProxyFailureException("Invalid JAX-RPC call configuration", ex);
699         }
700     }
701
702     /**
703      * Prepare the given JAX-RPC call, applying properties to it.
704      * Called by <code>invoke</code>.
705      * <p>Just applied when actually using JAX-RPC dynamic calls,
706      * i.e. if no JAX-RPC-compliant port interface was specified.
707      * Else, a JAX-RPC port stub will be used.
708      * @param call the current JAX-RPC call object
709      * @see #invoke
710      * @see #setUsername
711      * @see #setPassword
712      * @see #setEndpointAddress
713      * @see #setMaintainSession
714      * @see #setCustomProperties
715      * @see #setPortInterface
716      * @see #preparePortStub
717      */

718     protected void prepareJaxRpcCall(Call JavaDoc call) {
719         String JavaDoc username = getUsername();
720         if (username != null) {
721             call.setProperty(Call.USERNAME_PROPERTY, username);
722         }
723         String JavaDoc password = getPassword();
724         if (password != null) {
725             call.setProperty(Call.PASSWORD_PROPERTY, password);
726         }
727         String JavaDoc 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 JavaDoc it = this.customPropertyMap.keySet().iterator(); it.hasNext();) {
736                 String JavaDoc key = (String JavaDoc) it.next();
737                 call.setProperty(key, this.customPropertyMap.get(key));
738             }
739         }
740     }
741
742     /**
743      * Post-process the given JAX-RPC call.
744      * Default implementation is empty. Called by <code>invoke</code>.
745      * <p>Just applied when actually using JAX-RPC dynamic calls,
746      * that is, if no JAX-RPC-compliant port interface was specified.
747      * Else, a JAX-RPC port stub will be used.
748      * @param call the current JAX-RPC call object
749      * (can be cast to an implementation-specific class if necessary)
750      * @param invocation the current AOP MethodInvocation that the call was
751      * created for (can be used to check method name, method parameters
752      * and/or passed-in arguments)
753      * @see #invoke
754      * @see #setPortInterface
755      * @see #postProcessPortStub
756      */

757     protected void postProcessJaxRpcCall(Call JavaDoc call, MethodInvocation invocation) {
758     }
759
760     /**
761      * Determine whether the given RMI exception indicates a connect failure.
762      * <p>The default implementation always returns <code>true</code>,
763      * assuming that the JAX-RPC provider only throws RemoteException
764      * in case of connect failures.
765      * @param ex the RMI exception to check
766      * @return whether the exception should be treated as connect failure
767      * @see org.springframework.remoting.rmi.RmiClientInterceptorUtils#isConnectFailure
768      */

769     protected boolean isConnectFailure(RemoteException JavaDoc ex) {
770         return true;
771     }
772
773 }
774
Popular Tags