001    package org.andromda.cartridges.support.webservice.client;
002    
003    import org.aopalliance.intercept.MethodInterceptor;
004    import org.aopalliance.intercept.MethodInvocation;
005    import org.apache.commons.codec.binary.Base64;
006    import org.apache.commons.lang.StringUtils;
007    import org.apache.commons.logging.Log;
008    import org.apache.commons.logging.LogFactory;
009    import org.springframework.aop.support.AopUtils;
010    import org.springframework.beans.factory.InitializingBean;
011    import org.springframework.beans.factory.support.RootBeanDefinition;
012    import org.springframework.remoting.rmi.RmiClientInterceptorUtils;
013    
014    
015    /**
016     * Interceptor for accessing a specific port of a web service.
017     * Change from RootBeanDefinition to GenericBeanDefinition when using Spring 2.5
018     */
019    public class Axis2PortClientInterceptor
020        extends org.springframework.beans.factory.support.RootBeanDefinition
021        implements MethodInterceptor,
022            InitializingBean
023    {
024        private static final long serialVersionUID = 34L;
025        /**
026         * LogFactory.getLog(Axis2PortClientInterceptor.class)
027         */
028        protected final Log logger = LogFactory.getLog(Axis2PortClientInterceptor.class);
029        private final Object preparationMonitor = new Object();
030        private String username;
031    
032        /**
033         * Set the username to connect to the service.
034         * @param username
035         */
036        public void setUsername(String username)
037        {
038            this.username = username;
039        }
040    
041        /**
042         * Return the username to connect to the service.
043         * @return username
044         */
045        public String getUsername()
046        {
047            return username;
048        }
049    
050        private String password;
051    
052        /**
053         * Set the password to connect to the service.
054         * @param password
055         */
056        public void setPassword(String password)
057        {
058            this.password = password;
059        }
060    
061        /**
062         * Return the password to connect to the service.
063         * @return password
064         */
065        public String getPassword()
066        {
067            String password = this.password;
068            if (password != null && this.getBase64Password())
069            {
070                password = new String(Base64.decodeBase64(password.getBytes()));
071            }
072            return password;
073        }
074    
075        private boolean base64Password;
076    
077        /**
078         * Sets a flag indicating whether or not the password given is in Base64.
079         *
080         * @param base64Password true/false
081         */
082        public void setBase64Password(boolean base64Password)
083        {
084            this.base64Password = base64Password;
085        }
086    
087        /**
088         * Gets the flag indicating whether or not the password given is in Base64.
089         *
090         * @return true/false
091         */
092        public boolean getBase64Password()
093        {
094            return this.base64Password;
095        }
096    
097        private long timeout;
098    
099        /**
100         * Sets the timeout of the client in seconds.
101         *
102         * @param timeout
103         */
104        public void setTimeout(final long timeout)
105        {
106            this.timeout = timeout;
107        }
108    
109        /**
110         * Gets the timeout of the client in seconds.
111         *
112         * @return the timeout.
113         */
114        public long getTimeout()
115        {
116            return this.timeout;
117        }
118    
119        private Class serviceInterface;
120    
121        /**
122         * Set the interface of the service that this factory should create a proxy for.
123         * @param serviceInterface
124         */
125        public void setServiceInterface(Class serviceInterface)
126        {
127            if (serviceInterface != null && !serviceInterface.isInterface())
128            {
129                throw new IllegalArgumentException("serviceInterface must be an interface");
130            }
131            this.serviceInterface = serviceInterface;
132        }
133    
134        /**
135         * Return the interface of the service that this factory should create a proxy for.
136         * @return serviceInterface
137         */
138        public Class getServiceInterface()
139        {
140            return serviceInterface;
141        }
142    
143        private String wsdlUrl;
144    
145        /**
146         * Returns the URL to the WSDL for the service.
147         *
148         * @return the wsdlUrl
149         */
150        public String getWsdlUrl()
151        {
152            return wsdlUrl;
153        }
154    
155        /**
156         * Sets the WSDL URL for the service.
157         *
158         * @param wsdlUrl the wsdlUrl to set
159         */
160        public void setWsdlUrl(String wsdlUrl)
161        {
162            this.wsdlUrl = wsdlUrl;
163        }
164    
165        private String portAddress;
166    
167        /**
168         * Returns the port address (if not using a port address in the WSDL).
169         *
170         * @return the portAddress
171         */
172        public String getPortAddress()
173        {
174            return portAddress;
175        }
176    
177        /**
178         * Sets the port address (if to use one other than the one in the WSDL).
179         *
180         * @param portAddress the portAddress to set
181         */
182        public void setPortAddress(String portAddress)
183        {
184            this.portAddress = portAddress;
185        }
186    
187        private TypeMapper typeMapper = new DefaultTypeMapper();
188    
189        /**
190         * Sets the {@link TypeMapper} to use.  It only makes sense to set this
191         * if you want to change the default type mapping behavoir.
192         *
193         * @param typeMapper the typeMapper to set
194         * @throws IllegalAccessException
195         * @throws InstantiationException
196         */
197        public void setTypeMapper(Class typeMapper)
198            throws InstantiationException, IllegalAccessException
199        {
200            if (typeMapper == null)
201            {
202                throw new IllegalArgumentException("'typeMapper' can not be null");
203            }
204            if (!TypeMapper.class.isAssignableFrom(typeMapper))
205            {
206                throw new IllegalArgumentException("'typeMapper' must be an instance of: " + TypeMapper.class.getName());
207            }
208            this.typeMapper = (TypeMapper)typeMapper.newInstance();
209        }
210    
211        /**
212         * Prepares the JAX-RPC service and port if the "lazyInit"
213         * isn't false.
214         */
215        public void afterPropertiesSet()
216        {
217            this.prepare();
218        }
219    
220        private WebServiceClient client;
221    
222        /**
223         * Create and initialize the service for the specified WSDL.
224         */
225        public void prepare()
226        {
227            synchronized (this.preparationMonitor)
228            {
229                if (this.getServiceInterface() == null)
230                {
231                    throw new IllegalArgumentException("'serviceInterface' must be specified!");
232                }
233                if (StringUtils.isBlank(this.getPortAddress()))
234                {
235                    throw new IllegalArgumentException("'portAddress' must be specified!");
236                }
237                if (StringUtils.isBlank(this.getWsdlUrl()))
238                {
239                    throw new IllegalArgumentException("'wsdlUrl' must be specified!");
240                }
241                if (this.client == null)
242                {
243                    this.client =
244                        new WebServiceClient(
245                            this.getWsdlUrl(),
246                            this.getPortAddress(),
247                            this.getServiceInterface(),
248                            this.getUsername(),
249                            this.getPassword());
250                    this.client.setTimeout(this.getTimeout());
251                    this.client.setTypeMapper(this.typeMapper);
252                }
253            }
254        }
255    
256        /**
257         * Translates the method invocation into a JAX-RPC service invocation.
258         * Uses traditional RMI stub invocation if a JAX-RPC port stub is available;
259         * falls back to JAX-RPC dynamic calls else.
260         * @param invocation
261         * @return invoked operation return
262         * @throws Throwable
263         * @see WebServiceClient#invokeBlocking(String, Object[])
264         * @see org.springframework.remoting.rmi.RmiClientInterceptorUtils
265         */
266        public Object invoke(MethodInvocation invocation)
267            throws Throwable
268        {
269            if (AopUtils.isToStringMethod(invocation.getMethod()))
270            {
271                return "Axis2 proxy for port [" + this.getPortAddress() + "] of service [" +
272                    this.getServiceInterface().getName() + ']';
273            }
274            if (logger.isDebugEnabled())
275            {
276                logger.debug(
277                    "Invoking '" + invocation.getMethod().getName() + "' on port: '" +
278                    this.getPortAddress() + "' through interface: '" + this.getServiceInterface().getName() + '\'');
279            }
280            try
281            {
282                try
283                {
284                    return this.client.invokeBlocking(
285                        invocation.getMethod().getName(),
286                        invocation.getArguments());
287                }
288                finally
289                {
290                    this.client.cleanup();
291                }
292            }
293            catch (WebServiceClientException exception)
294            {
295                throw RmiClientInterceptorUtils.convertRmiAccessException(
296                    invocation.getMethod(),
297                    exception,
298                    this.getServiceInterface().getName());
299            }
300        }
301    
302        /**
303         * @see org.springframework.beans.factory.support.RootBeanDefinition#cloneBeanDefinition()
304         */
305        public RootBeanDefinition cloneBeanDefinition() {
306            return new RootBeanDefinition(this);
307        }
308    }