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 }