View Javadoc

1   /*
2    * Copyright 2005-2012 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.ws.config;
18  
19  import org.springframework.beans.BeanMetadataElement;
20  import org.springframework.beans.factory.config.BeanDefinition;
21  import org.springframework.beans.factory.config.RuntimeBeanReference;
22  import org.springframework.beans.factory.parsing.BeanComponentDefinition;
23  import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
24  import org.springframework.beans.factory.support.ManagedList;
25  import org.springframework.beans.factory.support.RootBeanDefinition;
26  import org.springframework.beans.factory.xml.BeanDefinitionParser;
27  import org.springframework.beans.factory.xml.ParserContext;
28  import org.springframework.core.Ordered;
29  import org.springframework.util.ClassUtils;
30  import org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter;
31  import org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor;
32  import org.springframework.ws.server.endpoint.adapter.method.MessageContextMethodArgumentResolver;
33  import org.springframework.ws.server.endpoint.adapter.method.SourcePayloadMethodProcessor;
34  import org.springframework.ws.server.endpoint.adapter.method.StaxPayloadMethodArgumentResolver;
35  import org.springframework.ws.server.endpoint.adapter.method.XPathParamMethodArgumentResolver;
36  import org.springframework.ws.server.endpoint.adapter.method.dom.Dom4jPayloadMethodProcessor;
37  import org.springframework.ws.server.endpoint.adapter.method.dom.DomPayloadMethodProcessor;
38  import org.springframework.ws.server.endpoint.adapter.method.dom.JDomPayloadMethodProcessor;
39  import org.springframework.ws.server.endpoint.adapter.method.dom.XomPayloadMethodProcessor;
40  import org.springframework.ws.server.endpoint.adapter.method.jaxb.JaxbElementPayloadMethodProcessor;
41  import org.springframework.ws.server.endpoint.adapter.method.jaxb.XmlRootElementPayloadMethodProcessor;
42  import org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping;
43  import org.springframework.ws.soap.addressing.server.AnnotationActionEndpointMapping;
44  import org.springframework.ws.soap.server.endpoint.SimpleSoapExceptionResolver;
45  import org.springframework.ws.soap.server.endpoint.SoapFaultAnnotationExceptionResolver;
46  import org.springframework.ws.soap.server.endpoint.adapter.method.SoapHeaderElementMethodArgumentResolver;
47  import org.springframework.ws.soap.server.endpoint.adapter.method.SoapMethodArgumentResolver;
48  import org.springframework.ws.soap.server.endpoint.mapping.SoapActionAnnotationMethodEndpointMapping;
49  
50  import org.w3c.dom.Element;
51  
52  /**
53   * {@link BeanDefinitionParser} that parses the {@code annotation-driven} element to configure a Spring WS application.
54   *
55   * @author Arjen Poutsma
56   * @since 2.0
57   */
58  class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
59  
60      private static final boolean dom4jPresent =
61              ClassUtils.isPresent("org.dom4j.Element", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
62  
63      private static final boolean jaxb2Present =
64              ClassUtils.isPresent("javax.xml.bind.Binder", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
65  
66      private static final boolean jdomPresent =
67              ClassUtils.isPresent("org.jdom2.Element", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
68  
69      private static final boolean staxPresent = ClassUtils
70              .isPresent("javax.xml.stream.XMLInputFactory", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
71  
72      private static final boolean xomPresent =
73              ClassUtils.isPresent("nu.xom.Element", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
74  
75      public BeanDefinition parse(Element element, ParserContext parserContext) {
76          Object source = parserContext.extractSource(element);
77  
78          CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
79          parserContext.pushContainingComponent(compDefinition);
80  
81          registerEndpointMappings(source, parserContext);
82  
83          registerEndpointAdapters(element, source, parserContext);
84  
85          registerEndpointExceptionResolvers(source, parserContext);
86  
87          parserContext.popAndRegisterContainingComponent();
88  
89          return null;
90      }
91  
92      private void registerEndpointMappings(Object source, ParserContext parserContext) {
93          RootBeanDefinition payloadRootMappingDef =
94                  createBeanDefinition(PayloadRootAnnotationMethodEndpointMapping.class, source);
95          payloadRootMappingDef.getPropertyValues().add("order", 0);
96          parserContext.getReaderContext().registerWithGeneratedName(payloadRootMappingDef);
97  
98          RootBeanDefinition soapActionMappingDef =
99                  createBeanDefinition(SoapActionAnnotationMethodEndpointMapping.class, source);
100         soapActionMappingDef.getPropertyValues().add("order", 1);
101         parserContext.getReaderContext().registerWithGeneratedName(soapActionMappingDef);
102 
103         RootBeanDefinition annActionMappingDef =
104                 createBeanDefinition(AnnotationActionEndpointMapping.class, source);
105         annActionMappingDef.getPropertyValues().add("order", 2);
106         parserContext.getReaderContext().registerWithGeneratedName(annActionMappingDef);
107     }
108 
109     private void registerEndpointAdapters(Element element, Object source, ParserContext parserContext) {
110         RootBeanDefinition adapterDef = createBeanDefinition(DefaultMethodEndpointAdapter.class, source);
111 
112         ManagedList<BeanMetadataElement> argumentResolvers = new ManagedList<BeanMetadataElement>();
113         argumentResolvers.setSource(source);
114 
115         ManagedList<BeanMetadataElement> returnValueHandlers = new ManagedList<BeanMetadataElement>();
116         returnValueHandlers.setSource(source);
117 
118         argumentResolvers.add(createBeanDefinition(MessageContextMethodArgumentResolver.class, source));
119         argumentResolvers.add(createBeanDefinition(XPathParamMethodArgumentResolver.class, source));
120         argumentResolvers.add(createBeanDefinition(SoapMethodArgumentResolver.class, source));
121         argumentResolvers.add(createBeanDefinition(SoapHeaderElementMethodArgumentResolver.class, source));
122 
123         RuntimeBeanReference domProcessor = createBeanReference(DomPayloadMethodProcessor.class, source, parserContext);
124         argumentResolvers.add(domProcessor);
125         returnValueHandlers.add(domProcessor);
126 
127         RuntimeBeanReference sourceProcessor =
128                 createBeanReference(SourcePayloadMethodProcessor.class, source, parserContext);
129         argumentResolvers.add(sourceProcessor);
130         returnValueHandlers.add(sourceProcessor);
131 
132         if (dom4jPresent) {
133             RuntimeBeanReference dom4jProcessor =
134                     createBeanReference(Dom4jPayloadMethodProcessor.class, source, parserContext);
135             argumentResolvers.add(dom4jProcessor);
136             returnValueHandlers.add(dom4jProcessor);
137         }
138         if (jaxb2Present) {
139             RuntimeBeanReference xmlRootElementProcessor =
140                     createBeanReference(XmlRootElementPayloadMethodProcessor.class, source, parserContext);
141             argumentResolvers.add(xmlRootElementProcessor);
142             returnValueHandlers.add(xmlRootElementProcessor);
143 
144             RuntimeBeanReference jaxbElementProcessor =
145                     createBeanReference(JaxbElementPayloadMethodProcessor.class, source, parserContext);
146             argumentResolvers.add(jaxbElementProcessor);
147             returnValueHandlers.add(jaxbElementProcessor);
148         }
149         if (jdomPresent) {
150             RuntimeBeanReference jdomProcessor =
151                     createBeanReference(JDomPayloadMethodProcessor.class, source, parserContext);
152             argumentResolvers.add(jdomProcessor);
153             returnValueHandlers.add(jdomProcessor);
154         }
155         if (staxPresent) {
156             argumentResolvers.add(createBeanDefinition(StaxPayloadMethodArgumentResolver.class, source));
157         }
158         if (xomPresent) {
159             RuntimeBeanReference xomProcessor =
160                     createBeanReference(XomPayloadMethodProcessor.class, source, parserContext);
161             argumentResolvers.add(xomProcessor);
162             returnValueHandlers.add(xomProcessor);
163         }
164         if (element.hasAttribute("marshaller")) {
165             RuntimeBeanReference marshallerReference = new RuntimeBeanReference(element.getAttribute("marshaller"));
166             RuntimeBeanReference unmarshallerReference;
167             if (element.hasAttribute("unmarshaller")) {
168                 unmarshallerReference = new RuntimeBeanReference(element.getAttribute("unmarshaller"));
169             }
170             else {
171                 unmarshallerReference = marshallerReference;
172             }
173 
174             RootBeanDefinition marshallingProcessorDef =
175                     createBeanDefinition(MarshallingPayloadMethodProcessor.class, source);
176             marshallingProcessorDef.getPropertyValues().add("marshaller", marshallerReference);
177             marshallingProcessorDef.getPropertyValues().add("unmarshaller", unmarshallerReference);
178             argumentResolvers.add(marshallingProcessorDef);
179             returnValueHandlers.add(marshallingProcessorDef);
180         }
181 
182         adapterDef.getPropertyValues().add("methodArgumentResolvers", argumentResolvers);
183         adapterDef.getPropertyValues().add("methodReturnValueHandlers", returnValueHandlers);
184 
185         parserContext.getReaderContext().registerWithGeneratedName(adapterDef);
186     }
187 
188     private void registerEndpointExceptionResolvers(Object source, ParserContext parserContext) {
189         RootBeanDefinition annotationResolverDef =
190                 createBeanDefinition(SoapFaultAnnotationExceptionResolver.class, source);
191         annotationResolverDef.getPropertyValues().add("order", 0);
192         parserContext.getReaderContext().registerWithGeneratedName(annotationResolverDef);
193 
194         RootBeanDefinition simpleResolverDef =
195                 createBeanDefinition(SimpleSoapExceptionResolver.class, source);
196         simpleResolverDef.getPropertyValues().add("order", Ordered.LOWEST_PRECEDENCE);
197         parserContext.getReaderContext().registerWithGeneratedName(simpleResolverDef);
198     }
199 
200     private RuntimeBeanReference createBeanReference(Class<?> beanClass, Object source, ParserContext parserContext) {
201         RootBeanDefinition beanDefinition = createBeanDefinition(beanClass, source);
202         String beanName = parserContext.getReaderContext().registerWithGeneratedName(beanDefinition);
203         parserContext.registerComponent(new BeanComponentDefinition(beanDefinition, beanName));
204         return new RuntimeBeanReference(beanName);
205     }
206 
207     private RootBeanDefinition createBeanDefinition(Class<?> beanClass, Object source) {
208         RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
209         beanDefinition.setSource(source);
210         beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
211         return beanDefinition;
212     }
213 }