1
16
17 package org.springframework.ws.server.endpoint.adapter;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.List;
22
23 import org.springframework.beans.BeanUtils;
24 import org.springframework.beans.factory.BeanClassLoaderAware;
25 import org.springframework.beans.factory.InitializingBean;
26 import org.springframework.core.MethodParameter;
27 import org.springframework.util.ClassUtils;
28 import org.springframework.util.CollectionUtils;
29 import org.springframework.ws.context.MessageContext;
30 import org.springframework.ws.server.endpoint.MethodEndpoint;
31 import org.springframework.ws.server.endpoint.adapter.method.MessageContextMethodArgumentResolver;
32 import org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver;
33 import org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler;
34 import org.springframework.ws.server.endpoint.adapter.method.SourcePayloadMethodProcessor;
35 import org.springframework.ws.server.endpoint.adapter.method.StaxPayloadMethodArgumentResolver;
36 import org.springframework.ws.server.endpoint.adapter.method.XPathParamMethodArgumentResolver;
37 import org.springframework.ws.server.endpoint.adapter.method.dom.Dom4jPayloadMethodProcessor;
38 import org.springframework.ws.server.endpoint.adapter.method.dom.DomPayloadMethodProcessor;
39 import org.springframework.ws.server.endpoint.adapter.method.dom.JDomPayloadMethodProcessor;
40 import org.springframework.ws.server.endpoint.adapter.method.dom.XomPayloadMethodProcessor;
41 import org.springframework.ws.server.endpoint.adapter.method.jaxb.JaxbElementPayloadMethodProcessor;
42 import org.springframework.ws.server.endpoint.adapter.method.jaxb.XmlRootElementPayloadMethodProcessor;
43
44
51 public class DefaultMethodEndpointAdapter extends AbstractMethodEndpointAdapter
52 implements BeanClassLoaderAware, InitializingBean {
53
54 private static final String DOM4J_CLASS_NAME = "org.dom4j.Element";
55
56 private static final String JAXB2_CLASS_NAME = "javax.xml.bind.Binder";
57
58 private static final String JDOM_CLASS_NAME = "org.jdom2.Element";
59
60 private static final String STAX_CLASS_NAME = "javax.xml.stream.XMLInputFactory";
61
62 private static final String XOM_CLASS_NAME = "nu.xom.Element";
63
64 private static final String SOAP_METHOD_ARGUMENT_RESOLVER_CLASS_NAME =
65 "org.springframework.ws.soap.server.endpoint.adapter.method.SoapMethodArgumentResolver";
66
67 private static final String SOAP_HEADER_ELEMENT_ARGUMENT_RESOLVER_CLASS_NAME =
68 "org.springframework.ws.soap.server.endpoint.adapter.method.SoapHeaderElementMethodArgumentResolver";
69
70 private List<MethodArgumentResolver> methodArgumentResolvers;
71
72 private List<MethodArgumentResolver> customMethodArgumentResolvers;
73
74 private List<MethodReturnValueHandler> methodReturnValueHandlers;
75
76 private List<MethodReturnValueHandler> customMethodReturnValueHandlers;
77
78 private ClassLoader classLoader;
79
80
83 public List<MethodArgumentResolver> getMethodArgumentResolvers() {
84 return methodArgumentResolvers;
85 }
86
87
90 public void setMethodArgumentResolvers(List<MethodArgumentResolver> methodArgumentResolvers) {
91 this.methodArgumentResolvers = methodArgumentResolvers;
92 }
93
94
97 public List<MethodArgumentResolver> getCustomMethodArgumentResolvers() {
98 return customMethodArgumentResolvers;
99 }
100
101
106 public void setCustomMethodArgumentResolvers(
107 List<MethodArgumentResolver> customMethodArgumentResolvers) {
108 this.customMethodArgumentResolvers = customMethodArgumentResolvers;
109 }
110
111
114 public List<MethodReturnValueHandler> getMethodReturnValueHandlers() {
115 return methodReturnValueHandlers;
116 }
117
118
121 public void setMethodReturnValueHandlers(List<MethodReturnValueHandler> methodReturnValueHandlers) {
122 this.methodReturnValueHandlers = methodReturnValueHandlers;
123 }
124
125
128 public List<MethodReturnValueHandler> getCustomMethodReturnValueHandlers() {
129 return customMethodReturnValueHandlers;
130 }
131
132
137 public void setCustomMethodReturnValueHandlers(
138 List<MethodReturnValueHandler> customMethodReturnValueHandlers) {
139 this.customMethodReturnValueHandlers = customMethodReturnValueHandlers;
140 }
141
142 private ClassLoader getClassLoader() {
143 return this.classLoader != null ? this.classLoader : DefaultMethodEndpointAdapter.class.getClassLoader();
144 }
145
146 @Override
147 public void setBeanClassLoader(ClassLoader classLoader) {
148 this.classLoader = classLoader;
149 }
150
151 @Override
152 public void afterPropertiesSet() throws Exception {
153 initDefaultStrategies();
154 }
155
156
157 protected void initDefaultStrategies() {
158 initMethodArgumentResolvers();
159 initMethodReturnValueHandlers();
160 }
161
162 private void initMethodArgumentResolvers() {
163 if (CollectionUtils.isEmpty(methodArgumentResolvers)) {
164 List<MethodArgumentResolver> methodArgumentResolvers = new ArrayList<MethodArgumentResolver>();
165 methodArgumentResolvers.add(new DomPayloadMethodProcessor());
166 methodArgumentResolvers.add(new MessageContextMethodArgumentResolver());
167 methodArgumentResolvers.add(new SourcePayloadMethodProcessor());
168 methodArgumentResolvers.add(new XPathParamMethodArgumentResolver());
169 addMethodArgumentResolver(SOAP_METHOD_ARGUMENT_RESOLVER_CLASS_NAME, methodArgumentResolvers);
170 addMethodArgumentResolver(SOAP_HEADER_ELEMENT_ARGUMENT_RESOLVER_CLASS_NAME, methodArgumentResolvers);
171 if (isPresent(DOM4J_CLASS_NAME)) {
172 methodArgumentResolvers.add(new Dom4jPayloadMethodProcessor());
173 }
174 if (isPresent(JAXB2_CLASS_NAME)) {
175 methodArgumentResolvers.add(new XmlRootElementPayloadMethodProcessor());
176 methodArgumentResolvers.add(new JaxbElementPayloadMethodProcessor());
177 }
178 if (isPresent(JDOM_CLASS_NAME)) {
179 methodArgumentResolvers.add(new JDomPayloadMethodProcessor());
180 }
181 if (isPresent(STAX_CLASS_NAME)) {
182 methodArgumentResolvers.add(new StaxPayloadMethodArgumentResolver());
183 }
184 if (isPresent(XOM_CLASS_NAME)) {
185 methodArgumentResolvers.add(new XomPayloadMethodProcessor());
186 }
187 if (logger.isDebugEnabled()) {
188 logger.debug("No MethodArgumentResolvers set, using defaults: " + methodArgumentResolvers);
189 }
190 if (getCustomMethodArgumentResolvers() != null) {
191 methodArgumentResolvers.addAll(getCustomMethodArgumentResolvers());
192 }
193 setMethodArgumentResolvers(methodArgumentResolvers);
194 }
195 }
196
197
201 @SuppressWarnings("unchecked")
202 private void addMethodArgumentResolver(String className, List<MethodArgumentResolver> methodArgumentResolvers) {
203 try {
204 Class<MethodArgumentResolver> methodArgumentResolverClass =
205 (Class<MethodArgumentResolver>) ClassUtils.forName(className, getClassLoader());
206 methodArgumentResolvers.add(BeanUtils.instantiateClass(methodArgumentResolverClass));
207 }
208 catch (ClassNotFoundException e) {
209 logger.warn("Could not find \"" + className + "\" on the classpath");
210 }
211 }
212
213 private void initMethodReturnValueHandlers() {
214 if (CollectionUtils.isEmpty(methodReturnValueHandlers)) {
215 List<MethodReturnValueHandler> methodReturnValueHandlers = new ArrayList<MethodReturnValueHandler>();
216 methodReturnValueHandlers.add(new DomPayloadMethodProcessor());
217 methodReturnValueHandlers.add(new SourcePayloadMethodProcessor());
218 if (isPresent(DOM4J_CLASS_NAME)) {
219 methodReturnValueHandlers.add(new Dom4jPayloadMethodProcessor());
220 }
221 if (isPresent(JAXB2_CLASS_NAME)) {
222 methodReturnValueHandlers.add(new XmlRootElementPayloadMethodProcessor());
223 methodReturnValueHandlers.add(new JaxbElementPayloadMethodProcessor());
224 }
225 if (isPresent(JDOM_CLASS_NAME)) {
226 methodReturnValueHandlers.add(new JDomPayloadMethodProcessor());
227 }
228 if (isPresent(XOM_CLASS_NAME)) {
229 methodReturnValueHandlers.add(new XomPayloadMethodProcessor());
230 }
231 if (logger.isDebugEnabled()) {
232 logger.debug("No MethodReturnValueHandlers set, using defaults: " + methodReturnValueHandlers);
233 }
234 if (getCustomMethodReturnValueHandlers() != null) {
235 methodReturnValueHandlers.addAll(getCustomMethodReturnValueHandlers());
236 }
237 setMethodReturnValueHandlers(methodReturnValueHandlers);
238 }
239 }
240
241 private boolean isPresent(String className) {
242 return ClassUtils.isPresent(className, getClassLoader());
243 }
244
245 @Override
246 protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
247 return supportsParameters(methodEndpoint.getMethodParameters()) &&
248 supportsReturnType(methodEndpoint.getReturnType());
249 }
250
251 private boolean supportsParameters(MethodParameter[] methodParameters) {
252 for (MethodParameter methodParameter : methodParameters) {
253 boolean supported = false;
254 for (MethodArgumentResolver methodArgumentResolver : methodArgumentResolvers) {
255 if (logger.isTraceEnabled()) {
256 logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
257 methodParameter.getGenericParameterType() + "]");
258 }
259 if (methodArgumentResolver.supportsParameter(methodParameter)) {
260 supported = true;
261 break;
262 }
263 }
264 if (!supported) {
265 return false;
266 }
267 }
268 return true;
269 }
270
271 private boolean supportsReturnType(MethodParameter methodReturnType) {
272 if (Void.TYPE.equals(methodReturnType.getParameterType())) {
273 return true;
274 }
275 for (MethodReturnValueHandler methodReturnValueHandler : methodReturnValueHandlers) {
276 if (methodReturnValueHandler.supportsReturnType(methodReturnType)) {
277 return true;
278 }
279 }
280 return false;
281 }
282
283 @Override
284 protected final void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception {
285 Object[] args = getMethodArguments(messageContext, methodEndpoint);
286
287 if (logger.isTraceEnabled()) {
288 logger.trace("Invoking [" + methodEndpoint + "] with arguments " + Arrays.asList(args));
289 }
290
291 Object returnValue = methodEndpoint.invoke(args);
292
293 if (logger.isTraceEnabled()) {
294 logger.trace("Method [" + methodEndpoint + "] returned [" + returnValue + "]");
295 }
296
297 Class<?> returnType = methodEndpoint.getMethod().getReturnType();
298 if (!Void.TYPE.equals(returnType)) {
299 handleMethodReturnValue(messageContext, returnValue, methodEndpoint);
300 }
301 }
302
303
314 protected Object[] getMethodArguments(MessageContext messageContext, MethodEndpoint methodEndpoint)
315 throws Exception {
316 MethodParameter[] parameters = methodEndpoint.getMethodParameters();
317 Object[] args = new Object[parameters.length];
318 for (int i = 0; i < parameters.length; i++) {
319 for (MethodArgumentResolver methodArgumentResolver : methodArgumentResolvers) {
320 if (methodArgumentResolver.supportsParameter(parameters[i])) {
321 args[i] = methodArgumentResolver.resolveArgument(messageContext, parameters[i]);
322 break;
323 }
324 }
325 }
326 return args;
327 }
328
329
340 protected void handleMethodReturnValue(MessageContext messageContext,
341 Object returnValue,
342 MethodEndpoint methodEndpoint) throws Exception {
343 MethodParameter returnType = methodEndpoint.getReturnType();
344 for (MethodReturnValueHandler methodReturnValueHandler : methodReturnValueHandlers) {
345 if (methodReturnValueHandler.supportsReturnType(returnType)) {
346 methodReturnValueHandler.handleReturnValue(messageContext, returnType, returnValue);
347 return;
348 }
349 }
350 throw new IllegalStateException(
351 "Return value [" + returnValue + "] not resolved by any MethodReturnValueHandler");
352 }
353 }
354