1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
45
46
47
48
49
50
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<MethodReturnValueHandler> methodReturnValueHandlers;
73
74 private ClassLoader classLoader;
75
76
77 public List<MethodArgumentResolver> getMethodArgumentResolvers() {
78 return methodArgumentResolvers;
79 }
80
81
82 public void setMethodArgumentResolvers(List<MethodArgumentResolver> methodArgumentResolvers) {
83 this.methodArgumentResolvers = methodArgumentResolvers;
84 }
85
86
87 public List<MethodReturnValueHandler> getMethodReturnValueHandlers() {
88 return methodReturnValueHandlers;
89 }
90
91
92 public void setMethodReturnValueHandlers(List<MethodReturnValueHandler> methodReturnValueHandlers) {
93 this.methodReturnValueHandlers = methodReturnValueHandlers;
94 }
95
96 private ClassLoader getClassLoader() {
97 return this.classLoader != null ? this.classLoader : DefaultMethodEndpointAdapter.class.getClassLoader();
98 }
99
100 public void setBeanClassLoader(ClassLoader classLoader) {
101 this.classLoader = classLoader;
102 }
103
104 public void afterPropertiesSet() throws Exception {
105 initDefaultStrategies();
106 }
107
108
109 protected void initDefaultStrategies() {
110 initMethodArgumentResolvers();
111 initMethodReturnValueHandlers();
112 }
113
114 private void initMethodArgumentResolvers() {
115 if (CollectionUtils.isEmpty(methodArgumentResolvers)) {
116 List<MethodArgumentResolver> methodArgumentResolvers = new ArrayList<MethodArgumentResolver>();
117 methodArgumentResolvers.add(new DomPayloadMethodProcessor());
118 methodArgumentResolvers.add(new MessageContextMethodArgumentResolver());
119 methodArgumentResolvers.add(new SourcePayloadMethodProcessor());
120 methodArgumentResolvers.add(new XPathParamMethodArgumentResolver());
121 addMethodArgumentResolver(SOAP_METHOD_ARGUMENT_RESOLVER_CLASS_NAME, methodArgumentResolvers);
122 addMethodArgumentResolver(SOAP_HEADER_ELEMENT_ARGUMENT_RESOLVER_CLASS_NAME, methodArgumentResolvers);
123 if (isPresent(DOM4J_CLASS_NAME)) {
124 methodArgumentResolvers.add(new Dom4jPayloadMethodProcessor());
125 }
126 if (isPresent(JAXB2_CLASS_NAME)) {
127 methodArgumentResolvers.add(new XmlRootElementPayloadMethodProcessor());
128 methodArgumentResolvers.add(new JaxbElementPayloadMethodProcessor());
129 }
130 if (isPresent(JDOM_CLASS_NAME)) {
131 methodArgumentResolvers.add(new JDomPayloadMethodProcessor());
132 }
133 if (isPresent(STAX_CLASS_NAME)) {
134 methodArgumentResolvers.add(new StaxPayloadMethodArgumentResolver());
135 }
136 if (isPresent(XOM_CLASS_NAME)) {
137 methodArgumentResolvers.add(new XomPayloadMethodProcessor());
138 }
139 if (logger.isDebugEnabled()) {
140 logger.debug("No MethodArgumentResolvers set, using defaults: " + methodArgumentResolvers);
141 }
142 setMethodArgumentResolvers(methodArgumentResolvers);
143 }
144 }
145
146
147
148
149
150 @SuppressWarnings("unchecked")
151 private void addMethodArgumentResolver(String className, List<MethodArgumentResolver> methodArgumentResolvers) {
152 try {
153 Class<MethodArgumentResolver> methodArgumentResolverClass =
154 (Class<MethodArgumentResolver>) ClassUtils.forName(className, getClassLoader());
155 methodArgumentResolvers.add(BeanUtils.instantiate(methodArgumentResolverClass));
156 }
157 catch (ClassNotFoundException e) {
158 logger.warn("Could not find \"" + className + "\" on the classpath");
159 }
160 }
161
162 private void initMethodReturnValueHandlers() {
163 if (CollectionUtils.isEmpty(methodReturnValueHandlers)) {
164 List<MethodReturnValueHandler> methodReturnValueHandlers = new ArrayList<MethodReturnValueHandler>();
165 methodReturnValueHandlers.add(new DomPayloadMethodProcessor());
166 methodReturnValueHandlers.add(new SourcePayloadMethodProcessor());
167 if (isPresent(DOM4J_CLASS_NAME)) {
168 methodReturnValueHandlers.add(new Dom4jPayloadMethodProcessor());
169 }
170 if (isPresent(JAXB2_CLASS_NAME)) {
171 methodReturnValueHandlers.add(new XmlRootElementPayloadMethodProcessor());
172 methodReturnValueHandlers.add(new JaxbElementPayloadMethodProcessor());
173 }
174 if (isPresent(JDOM_CLASS_NAME)) {
175 methodReturnValueHandlers.add(new JDomPayloadMethodProcessor());
176 }
177 if (isPresent(XOM_CLASS_NAME)) {
178 methodReturnValueHandlers.add(new XomPayloadMethodProcessor());
179 }
180 if (logger.isDebugEnabled()) {
181 logger.debug("No MethodReturnValueHandlers set, using defaults: " + methodReturnValueHandlers);
182 }
183 setMethodReturnValueHandlers(methodReturnValueHandlers);
184 }
185 }
186
187 private boolean isPresent(String className) {
188 return ClassUtils.isPresent(className, getClassLoader());
189 }
190
191 @Override
192 protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
193 return supportsParameters(methodEndpoint.getMethodParameters()) &&
194 supportsReturnType(methodEndpoint.getReturnType());
195 }
196
197 private boolean supportsParameters(MethodParameter[] methodParameters) {
198 for (MethodParameter methodParameter : methodParameters) {
199 boolean supported = false;
200 for (MethodArgumentResolver methodArgumentResolver : methodArgumentResolvers) {
201 if (logger.isTraceEnabled()) {
202 logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
203 methodParameter.getGenericParameterType() + "]");
204 }
205 if (methodArgumentResolver.supportsParameter(methodParameter)) {
206 supported = true;
207 break;
208 }
209 }
210 if (!supported) {
211 return false;
212 }
213 }
214 return true;
215 }
216
217 private boolean supportsReturnType(MethodParameter methodReturnType) {
218 if (Void.TYPE.equals(methodReturnType.getParameterType())) {
219 return true;
220 }
221 for (MethodReturnValueHandler methodReturnValueHandler : methodReturnValueHandlers) {
222 if (methodReturnValueHandler.supportsReturnType(methodReturnType)) {
223 return true;
224 }
225 }
226 return false;
227 }
228
229 @Override
230 protected final void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception {
231 Object[] args = getMethodArguments(messageContext, methodEndpoint);
232
233 if (logger.isTraceEnabled()) {
234 StringBuilder builder = new StringBuilder("Invoking [");
235 builder.append(methodEndpoint).append("] with arguments ");
236 builder.append(Arrays.asList(args));
237 logger.trace(builder.toString());
238 }
239
240 Object returnValue = methodEndpoint.invoke(args);
241
242 if (logger.isTraceEnabled()) {
243 logger.trace("Method [" + methodEndpoint + "] returned [" + returnValue + "]");
244 }
245
246 Class<?> returnType = methodEndpoint.getMethod().getReturnType();
247 if (!Void.TYPE.equals(returnType)) {
248 handleMethodReturnValue(messageContext, returnValue, methodEndpoint);
249 }
250 }
251
252
253
254
255
256
257
258
259
260
261
262
263 protected Object[] getMethodArguments(MessageContext messageContext, MethodEndpoint methodEndpoint)
264 throws Exception {
265 MethodParameter[] parameters = methodEndpoint.getMethodParameters();
266 Object[] args = new Object[parameters.length];
267 for (int i = 0; i < parameters.length; i++) {
268 for (MethodArgumentResolver methodArgumentResolver : methodArgumentResolvers) {
269 if (methodArgumentResolver.supportsParameter(parameters[i])) {
270 args[i] = methodArgumentResolver.resolveArgument(messageContext, parameters[i]);
271 break;
272 }
273 }
274 }
275 return args;
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289 protected void handleMethodReturnValue(MessageContext messageContext,
290 Object returnValue,
291 MethodEndpoint methodEndpoint) throws Exception {
292 MethodParameter returnType = methodEndpoint.getReturnType();
293 for (MethodReturnValueHandler methodReturnValueHandler : methodReturnValueHandlers) {
294 if (methodReturnValueHandler.supportsReturnType(returnType)) {
295 methodReturnValueHandler.handleReturnValue(messageContext, returnType, returnValue);
296 return;
297 }
298 }
299 throw new IllegalStateException(
300 "Return value [" + returnValue + "] not resolved by any MethodReturnValueHandler");
301 }
302 }