e.g. Calendar Search Help
You must enter a value before pressing Search
spring

Class: org.springframework.remoting.jaxrpc.JaxRpcPortClientInterceptor   ©

 OK to copy?
001 /*
002  * Copyright 2002-2004 the original author or authors.
003  * 
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of the License at
007  * 
008  *      http://www.apache.org/licenses/LICENSE-2.0
009  * 
010  * Unless required by applicable law or agreed to in writing, software
011  * distributed under the License is distributed on an "AS IS" BASIS,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  * limitations under the License.
015  */ 
016 
017 package org.springframework.remoting.jaxrpc;
018 
019 import java.rmi.Remote;
020 import java.rmi.RemoteException;
021 import java.util.Enumeration;
022 import java.util.Properties;
023 
024 import javax.xml.namespace.QName;
025 import javax.xml.rpc.Call;
026 import javax.xml.rpc.Service;
027 import javax.xml.rpc.ServiceException;
028 import javax.xml.rpc.Stub;
029 
030 import org.aopalliance.intercept.MethodInterceptor;
031 import org.aopalliance.intercept.MethodInvocation;
032 
033 import org.springframework.aop.support.AopUtils;
034 import org.springframework.beans.factory.InitializingBean;
035 import org.springframework.remoting.rmi.RmiClientInterceptorUtils;
036 
037 /**
038  * Interceptor for accessing a specific port of a JAX-RPC service.
039  * Uses either LocalJaxRpcServiceFactory's facilities underneath,
040  * or takes an explicit reference to an existing JAX-RPC Service instance
041  * (for example looked up via JndiObjectFactoryBean).
042  *
043  * <p>Allows to set JAX-RPC's standard stub properties directly, via the
044  * "username", "password", "endpointAddress" and "maintainSession" properties.
045  * For typical usage, it is not necessary to specify those, though.
046  *
047  * <p>This invoker is typically used with an RMI service interface. Alternatively,
048  * this invoker can also proxy a JAX-RPC service with a matching non-RMI business
049  * interface, i.e. an interface that mirrors the RMI service methods but does not
050  * declare RemoteExceptions. In the latter case, RemoteExceptions thrown by the
051  * JAX-RPC stub will automatically get converted to Spring's unchecked
052  * RemoteAccessException.
053  *
054  * <p>If exposing the JAX-RPC port interface (i.e. an RMI interface) directly,
055  * setting "serviceInterface" is sufficient. If exposing a non-RMI business
056  * interface, the business interface needs to be set as "serviceInterface",
057  * and the JAX-RPC port interface as "portInterface".
058  *
059  * @author Juergen Hoeller
060  * @since 15.12.2003
061  * @see #setPortName
062  * @see #setServiceInterface
063  * @see #setPortInterface
064  * @see javax.xml.rpc.Service#getPort
065  * @see javax.xml.rpc.Stub
066  * @see org.springframework.remoting.RemoteAccessException
067  * @see org.springframework.jndi.JndiObjectFactoryBean
068  */
069 public class JaxRpcPortClientInterceptor extends LocalJaxRpcServiceFactory
070         implements MethodInterceptor, InitializingBean {
071 
072     private Service jaxRpcService;
073 
074     private String portName;
075 
076     private String username;
077 
078     private String password;
079 
080     private String endpointAddress;
081 
082     private boolean maintainSession;
083 
084     private Properties customProperties;
085 
086     private Class serviceInterface;
087 
088     private Class portInterface;
089 
090     private QName portQName;
091 
092     private Remote portStub;
093 
094 
095     /**
096      * Set a reference to an existing JAX-RPC Service instance,
097      * for example looked up via JndiObjectFactoryBean.
098      * If not set, LocalJaxRpcServiceFactory's properties have to be specified.
099      * @see #setServiceFactoryClass
100      * @see #setWsdlDocumentUrl
101      * @see #setNamespaceUri
102      * @see #setServiceName
103      * @see org.springframework.jndi.JndiObjectFactoryBean
104      */
105     public void setJaxRpcService(Service jaxRpcService) {
106         this.jaxRpcService = jaxRpcService;
107     }
108 
109     /**
110      * Return a reference to an existing JAX-RPC Service instance, if any.
111      */
112     public Service getJaxRpcService() {
113         return jaxRpcService;
114     }
115 
116     /**
117      * Set the name of the port.
118      * Corresponds to the "wsdl:port" name.
119      */
120     public void setPortName(String portName) {
121         this.portName = portName;
122     }
123 
124     /**
125      * Return the name of the port.
126      */
127     public String getPortName() {
128         return portName;
129     }
130 
131     /**
132      * Set the username to specify on the stub or call.
133      * @see javax.xml.rpc.Stub#USERNAME_PROPERTY
134      * @see javax.xml.rpc.Call#USERNAME_PROPERTY
135      */
136     public void setUsername(String username) {
137         this.username = username;
138     }
139 
140     /**
141      * Return the username to specify on the stub or call.
142      */
143     public String getUsername() {
144         return username;
145     }
146 
147     /**
148      * Set the password to specify on the stub or call.
149      * @see javax.xml.rpc.Stub#PASSWORD_PROPERTY
150      * @see javax.xml.rpc.Call#PASSWORD_PROPERTY
151      */
152     public void setPassword(String password) {
153         this.password = password;
154     }
155 
156     /**
157      * Return the password to specify on the stub or call.
158      */
159     public String getPassword() {
160         return password;
161     }
162 
163     /**
164      * Set the endpoint address to specify on the stub or call.
165      * @see javax.xml.rpc.Stub#ENDPOINT_ADDRESS_PROPERTY
166      * @see javax.xml.rpc.Call#setTargetEndpointAddress
167      */
168     public void setEndpointAddress(String endpointAddress) {
169         this.endpointAddress = endpointAddress;
170     }
171 
172     /**
173      * Return the endpoint address to specify on the stub or call.
174      */
175     public String getEndpointAddress() {
176         return endpointAddress;
177     }
178 
179     /**
180      * Set the maintain session flag to specify on the stub or call.
181      * @see javax.xml.rpc.Stub#SESSION_MAINTAIN_PROPERTY
182      * @see javax.xml.rpc.Call#SESSION_MAINTAIN_PROPERTY
183      */
184     public void setMaintainSession(boolean maintainSession) {
185         this.maintainSession = maintainSession;
186     }
187 
188     /**
189      * Return the maintain session flag to specify on the stub or call.
190      */
191     public boolean isMaintainSession() {
192         return maintainSession;
193     }
194 
195     /**
196      * Set custom properties to be set on the stub or call.
197      * @see javax.xml.rpc.Stub#_setProperty
198      * @see javax.xml.rpc.Call#setProperty
199      */
200     public void setCustomProperties(Properties customProperties) {
201         this.customProperties = customProperties;
202     }
203 
204     /**
205      * Return custom properties to be set on the stub or call.
206      */
207     public Properties getCustomProperties() {
208         return customProperties;
209     }
210 
211     /**
212      * Set the interface of the service that this factory should create a proxy for.
213      * This will typically be a non-RMI business interface, although you can also
214      * use an RMI port interface as recommended by JAX-RPC here.
215      * <p>If the specified service interface is a non-RMI business interface,
216      * invocations will either be translated to the underlying RMI port interface
217      * (in case of a "portInterface" being specified) or to JAX-RPC dynamic calls.
218      * <p>The dynamic call mechanism has the advantage that you don't need to
219      * maintain an RMI port interface in addition to an existing non-RMI business
220      * interface. In terms of configuration, specifying the business interface
221      * as "serviceInterface" will be enough; this interceptor will automatically
222      * switch to dynamic calls in such a scenario.
223      * @see #setPortInterface
224      */
225     public void setServiceInterface(Class serviceInterface) {
226         if (serviceInterface != null && !serviceInterface.isInterface()) {
227             throw new IllegalArgumentException("serviceInterface must be an interface");
228         }
229         this.serviceInterface = serviceInterface;
230     }
231 
232     /**
233      * Return the interface of the service that this factory should create a proxy for.
234      */
235     public Class getServiceInterface() {
236         return serviceInterface;
237     }
238 
239     /**
240      * Set the JAX-RPC port interface to use. Only needs to be set if the exposed
241      * service interface is different from the port interface, i.e. when using
242      * a non-RMI business interface as service interface for exposed proxies,
243      * and if the JAX-RPC dynamic call mechanism is not desirable. See the
244      * javadoc of the "serviceInterface" property for more details.
245      * <p>The interface must be suitable for a JAX-RPC port, i.e. it must be an
246      * RMI service interface (that extends <code>java.rmi.Remote</code>).
247      * @see #setServiceInterface
248      * @see java.rmi.Remote
249      */
250     public void setPortInterface(Class portInterface) {
251         if (portInterface != null &&
252                 (!portInterface.isInterface() || !Remote.class.isAssignableFrom(portInterface))) {
253             throw new IllegalArgumentException(
254                     "portInterface must be an interface derived from [java.rmi.Remote]");
255         }
256         this.portInterface = portInterface;
257     }
258 
259     /**
260      * Return the JAX-RPC port interface to use.
261      */
262     public Class getPortInterface() {
263         return portInterface;
264     }
265 
266 
267     public void afterPropertiesSet() throws ServiceException {
268         prepare();
269     }
270 
271     /**
272      * Create and initialize the JAX-RPC service for the specified port.
273      * <p>Prepares a JAX-RPC stub if possible (if an RMI interface is available);
274      * falls back to JAX-RPC dynamic calls else. Using dynamic calls can be
275      * enforced through overriding <code>alwaysUseJaxRpcCall</code> to return true.
276      * <p><code>postProcessJaxRpcService</code> and <code>postProcessPortStub</code>
277      * hooks are available for customization in subclasses. When using dynamic calls,
278      * each can be post-processed via <code>postProcessJaxRpcCall</code>.
279      * @see #alwaysUseJaxRpcCall
280      * @see #postProcessJaxRpcService
281      * @see #postProcessPortStub
282      * @see #postProcessJaxRpcCall
283      */
284     public void prepare() throws ServiceException {
285         if (this.portName == null) {
286             throw new IllegalArgumentException("portName is required");
287         }
288 
289         if (this.jaxRpcService == null) {
290             this.jaxRpcService = createJaxRpcService();
291         }
292 
293         // Cache the QName for the port.
294         this.portQName = getQName(this.portName);
295 
296         // Determine interface to use at the JAX-RPC port level:
297         // Use portInterface if specified, else fall back to serviceInterface.
298         Class actualInterface = (this.portInterface != null ? this.portInterface : this.serviceInterface);
299 
300         if (actualInterface != null && Remote.class.isAssignableFrom(actualInterface) &&
301                 !alwaysUseJaxRpcCall()) {
302             // JAX-RPC-compliant port interface -> using JAX-RPC stub for port.
303 
304             if (logger.isInfoEnabled()) {
305                 logger.info("Creating JAX-RPC proxy for JAX-RPC port [" + this.portQName +
306                         "], using port interface [" + actualInterface.getName() + "]");
307             }
308             Remote remoteObj = this.jaxRpcService.getPort(this.portQName, actualInterface);
309 
310             if (logger.isInfoEnabled()) {
311                 if (this.serviceInterface != null) {
312                     boolean isImpl = this.serviceInterface.isInstance(remoteObj);
313                     logger.info("Using service interface [" + this.serviceInterface.getName() + "] for JAX-RPC port [" +
314                             this.portQName + "] - " + (!isImpl ? "not" : "") + " directly implemented");
315                 }
316             }
317 
318             if (!(remoteObj instanceof Stub)) {
319                 throw new ServiceException("Port stub of class [" + remoteObj.getClass().getName() +
320                         "] is not a valid JAX-RPC stub: it does not implement interface [javax.xml.rpc.Stub]");
321             }
322             Stub stub = (Stub) remoteObj;
323 
324             // Apply properties to JAX-RPC stub.
325             preparePortStub(stub);
326 
327             // Allow for custom post-processing in subclasses.
328             postProcessPortStub(stub);
329 
330             this.portStub = remoteObj;
331         }
332 
333         else {
334             // No JAX-RPC-compliant port interface -> using JAX-RPC dynamic calls.
335             if (logger.isInfoEnabled()) {
336                 logger.info("Using JAX-RPC dynamic calls for JAX-RPC port [" + this.portQName + "]");
337             }
338         }
339     }
340 
341     /**
342      * Return the prepared QName for the port.
343      * @see #setPortName
344      * @see #getQName
345      */
346     protected QName getPortQName() {
347         return portQName;
348     }
349 
350     /**
351      * Return whether to always use JAX-RPC dynamic calls.
352      * Called by <code>afterPropertiesSet</code>.
353      * <p>Default is false; if an RMI interface is specified as "portInterface"
354      * or "serviceInterface", it will be used to create a JAX-RPC port stub.
355      * <p>Can be overridden to enforce the use of the JAX-RPC Call API,
356      * for example if there is a need to customize at the Call level.
357      * This just necessary if you you want to use an RMI interface as
358      * "serviceInterface", though; in case of only a non-RMI interface being
359      * available, this interceptor will fall back to the Call API anyway.
360      * @see #postProcessJaxRpcCall
361      */
362     protected boolean alwaysUseJaxRpcCall() {
363         return false;
364     }
365 
366 
367     /**
368      * Prepare the given JAX-RPC port stub, applying properties to it.
369      * Called by <code>afterPropertiesSet</code>.
370      * <p>Just applied when actually creating a JAX-RPC port stub,
371      * in case of a specified JAX-RPC-compliant port interface.
372      * Else, JAX-RPC dynamic calls will be used.
373      * @param stub the current JAX-RPC port stub
374      * @see #afterPropertiesSet
375      * @see #setUsername
376      * @see #setPassword
377      * @see #setEndpointAddress
378      * @see #setMaintainSession
379      * @see #setCustomProperties
380      * @see #setPortInterface
381      * @see #prepareJaxRpcCall
382      */
383     protected void preparePortStub(Stub stub) {
384         if (this.username != null) {
385             stub._setProperty(Stub.USERNAME_PROPERTY, this.username);
386         }
387         if (this.password != null) {
388             stub._setProperty(Stub.PASSWORD_PROPERTY, this.password);
389         }
390         if (this.endpointAddress != null) {
391             stub._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, this.endpointAddress);
392         }
393         if (this.maintainSession) {
394             stub._setProperty(Stub.SESSION_MAINTAIN_PROPERTY, new Boolean(this.maintainSession));
395         }
396         if (this.customProperties != null) {
397             Enumeration en = this.customProperties.propertyNames();
398             while (en.hasMoreElements()) {
399                 String key = (String) en.nextElement();
400                 stub._setProperty(key, this.customProperties.getProperty(key));
401             }
402         }
403     }
404 
405     /**
406      * Post-process the given JAX-RPC port stub.
407      * Default implementation is empty. Called by <code>prepare</code>.
408      * <p>Just applied when actually creating a JAX-RPC port stub,
409      * in case of a specified JAX-RPC-compliant port interface.
410      * Else, JAX-RPC dynamic calls will be used.
411      * @param stub the current JAX-RPC port stub
412      * (can be cast to an implementation-specific class if necessary)
413      * @see #prepare
414      * @see #setPortInterface
415      * @see #postProcessJaxRpcCall
416      */
417     protected void postProcessPortStub(Stub stub) {
418     }
419 
420     /**
421      * Return the underlying JAX-RPC port stub that this interceptor delegates to
422      * for each method invocation on the proxy.
423      */
424     protected Remote getPortStub() {
425         return portStub;
426     }
427 
428 
429     public Object invoke(MethodInvocation invocation) throws Throwable {
430         if (AopUtils.isToStringMethod(invocation.getMethod())) {
431             return "JAX-RPC proxy for port [" + getPortName() + "] of service [" +
432                     getJaxRpcService().getServiceName() + "]";
433         }
434 
435         Remote stub = getPortStub();
436         if (stub != null) {
437             // JAX-RPC stub available -> traditional RMI stub invocation.
438             if (logger.isDebugEnabled()) {
439                 logger.debug("Invoking operation '" + invocation.getMethod().getName() +
440                         "' on JAX-RPC port stub");
441             }
442             return RmiClientInterceptorUtils.invoke(invocation, stub, getPortQName().toString());
443         }
444 
445         else {
446             // No JAX-RPC stub -> using JAX-RPC dynamic calls.
447             if (logger.isDebugEnabled()) {
448                 logger.debug("Invoking operation '" + invocation.getMethod().getName() +
449                         "' as JAX-RPC dynamic call");
450             }
451             return performJaxRpcCall(invocation);
452         }
453     }
454 
455 
456     /**
457      * Perform a JAX-RPC dynamic call for the given AOP method invocation.
458      * Delegates to <code>prepareJaxRpcCall</code> and
459      * <code>postProcessJaxRpcCall</code> for setting up the call object.
460      * <p>Default implementation uses method name as JAX-RPC operation name
461      * and method arguments as arguments for the JAX-RPC call. Can be
462      * overridden in subclasses for custom operation names and/or arguments.
463      * @param invocation the current AOP MethodInvocation that should
464      * be converted to a JAX-RPC call
465      * @return the return value of the invocation, if any
466      * @throws Throwable the exception thrown by the invocation, if any
467      * @see #getJaxRpcService
468      * @see #getPortQName
469      * @see #prepareJaxRpcCall
470      * @see #postProcessJaxRpcCall
471      */
472     protected Object performJaxRpcCall(MethodInvocation invocation) throws Throwable {
473         Service service = getJaxRpcService();
474         if (service == null) {
475             throw new IllegalStateException("JaxRpcClientInterceptor is not properly initialized - " +
476                     "invoke 'prepare' before attempting any operations");
477         }
478 
479         QName portQName = getPortQName();
480 
481         // Create JAX-RPC call object, using the method name as operation name.
482         Call call = service.createCall(portQName, invocation.getMethod().getName());
483 
484         // Apply properties to JAX-RPC stub.
485         prepareJaxRpcCall(call);
486 
487         // Allow for custom post-processing in subclasses.
488         postProcessJaxRpcCall(call, invocation);
489 
490         // Perform actual invocation.
491         try {
Rate492             return call.invoke(invocation.getArguments());
493         }
494         catch (RemoteException ex) {
495             throw RmiClientInterceptorUtils.convertRmiAccessException(
496                     invocation.getMethod(), ex, portQName.toString());
497         }
498     }
499 
500     /**
501      * Prepare the given JAX-RPC call, applying properties to it.
502      * Called by <code>invoke</code>.
503      * <p>Just applied when actually using JAX-RPC dynamic calls,
504      * i.e. if no JAX-RPC-compliant port interface was specified.
505      * Else, a JAX-RPC port stub will be used.
506      * @param call the current JAX-RPC call object
507      * @see #invoke
508      * @see #setUsername
509      * @see #setPassword
510      * @see #setEndpointAddress
511      * @see #setMaintainSession
512      * @see #setCustomProperties
513      * @see #setPortInterface
514      * @see #preparePortStub
515      */
516     protected void prepareJaxRpcCall(Call call) {
517         if (this.username != null) {
518             call.setProperty(Call.USERNAME_PROPERTY, this.username);
519         }
520         if (this.password != null) {
521             call.setProperty(Call.PASSWORD_PROPERTY, this.password);
522         }
523         if (this.endpointAddress != null) {
524             call.setTargetEndpointAddress(this.endpointAddress);
525         }
526         if (this.maintainSession) {
527             call.setProperty(Call.SESSION_MAINTAIN_PROPERTY, new Boolean(this.maintainSession));
528         }
529         if (this.customProperties != null) {
530             Enumeration en = this.customProperties.propertyNames();
531             while (en.hasMoreElements()) {
532                 String key = (String) en.nextElement();
533                 call.setProperty(key, this.customProperties.getProperty(key));
534             }
535         }
536     }
537 
538     /**
539      * Post-process the given JAX-RPC call.
540      * Default implementation is empty. Called by <code>invoke</code>.
541      * <p>Just applied when actually using JAX-RPC dynamic calls,
542      * i.e. if no JAX-RPC-compliant port interface was specified.
543      * Else, a JAX-RPC port stub will be used.
544      * @param call the current JAX-RPC call object
545      * (can be cast to an implementation-specific class if necessary)
546      * @param invocation the current AOP MethodInvocation that the call was
547      * created for (can be used to check method name, method parameters
548      * and/or passed-in arguments)
549      * @see #invoke
550      * @see #setPortInterface
551      * @see #postProcessPortStub
552      */
553     protected void postProcessJaxRpcCall(Call call, MethodInvocation invocation) {
554     }
555 
556 }

            
All Examples in File:
Example
Line
Rating (found
useful by...)
492 0% of 0