View Javadoc

1   /*
2    * Copyright 2005-2010 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.server.endpoint.mapping;
18  
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.springframework.beans.BeansException;
25  import org.springframework.beans.factory.BeanFactoryUtils;
26  import org.springframework.context.support.ApplicationObjectSupport;
27  import org.springframework.core.Ordered;
28  import org.springframework.ws.context.MessageContext;
29  import org.springframework.ws.server.EndpointInterceptor;
30  import org.springframework.ws.server.EndpointInvocationChain;
31  import org.springframework.ws.server.EndpointMapping;
32  import org.springframework.ws.server.SmartEndpointInterceptor;
33  
34  /**
35   * Abstract base class for EndpointMapping implementations. Supports a default endpoint, and endpoint interceptors.
36   *
37   * @author Arjen Poutsma
38   * @see #getEndpointInternal(org.springframework.ws.context.MessageContext)
39   * @see org.springframework.ws.server.EndpointInterceptor
40   * @since 1.0.0
41   */
42  public abstract class AbstractEndpointMapping extends ApplicationObjectSupport implements EndpointMapping, Ordered {
43  
44      private int order = Integer.MAX_VALUE;  // default: same as non-Ordered
45  
46      private Object defaultEndpoint;
47  
48      private EndpointInterceptor[] interceptors;
49  
50      private SmartEndpointInterceptor[] smartInterceptors;
51  
52      /**
53       * Returns the the endpoint interceptors to apply to all endpoints mapped by this endpoint mapping.
54       *
55       * @return array of endpoint interceptors, or <code>null</code> if none
56       */
57      public EndpointInterceptor[] getInterceptors() {
58          return interceptors;
59      }
60  
61      /**
62       * Sets the endpoint interceptors to apply to all endpoints mapped by this endpoint mapping.
63       *
64       * @param interceptors array of endpoint interceptors, or <code>null</code> if none
65       */
66      public final void setInterceptors(EndpointInterceptor[] interceptors) {
67          this.interceptors = interceptors;
68      }
69  
70      public final int getOrder() {
71          return order;
72      }
73  
74      /**
75       * Specify the order value for this mapping.
76       * <p/>
77       * Default value is {@link Integer#MAX_VALUE}, meaning that it's non-ordered.
78       *
79       * @see org.springframework.core.Ordered#getOrder()
80       */
81      public final void setOrder(int order) {
82          this.order = order;
83      }
84  
85      /**
86       * Initializes the interceptors.
87       *
88       * @see #initInterceptors()
89       */
90      @Override
91      protected void initApplicationContext() throws BeansException {
92          initInterceptors();
93      }
94  
95      /**
96       * Initialize the specified interceptors, adapting them where necessary.
97       *
98       * @see #setInterceptors
99       */
100     protected void initInterceptors() {
101         Map<String, SmartEndpointInterceptor> smartInterceptors = BeanFactoryUtils
102                 .beansOfTypeIncludingAncestors(getApplicationContext(), SmartEndpointInterceptor.class, true, false);
103         if (!smartInterceptors.isEmpty()) {
104             this.smartInterceptors =
105                     smartInterceptors.values().toArray(new SmartEndpointInterceptor[smartInterceptors.size()]);
106         }
107     }
108 
109     /**
110      * Look up an endpoint for the given message context, falling back to the default endpoint if no specific one is
111      * found.
112      *
113      * @return the looked up endpoint instance, or the default endpoint
114      * @see #getEndpointInternal(org.springframework.ws.context.MessageContext)
115      */
116     public final EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception {
117         Object endpoint = getEndpointInternal(messageContext);
118         if (endpoint == null) {
119             endpoint = defaultEndpoint;
120         }
121         if (endpoint == null) {
122             return null;
123         }
124         if (endpoint instanceof String) {
125             String endpointName = (String) endpoint;
126             endpoint = resolveStringEndpoint(endpointName);
127             if (endpoint == null) {
128                 return null;
129             }
130         }
131 
132         List<EndpointInterceptor> interceptors = new ArrayList<EndpointInterceptor>();
133         if (this.interceptors != null) {
134             interceptors.addAll(Arrays.asList(this.interceptors));
135         }
136 
137         if (this.smartInterceptors != null) {
138             for (SmartEndpointInterceptor smartInterceptor : smartInterceptors) {
139                 if (smartInterceptor.shouldIntercept(messageContext, endpoint)) {
140                     interceptors.add(smartInterceptor);
141                 }
142             }
143         }
144 
145         return createEndpointInvocationChain(messageContext, endpoint,
146                 interceptors.toArray(new EndpointInterceptor[interceptors.size()]));
147     }
148 
149     /**
150      * Creates a new <code>EndpointInvocationChain</code> based on the given message context, endpoint, and
151      * interceptors. Default implementation creates a simple <code>EndpointInvocationChain</code> based on the set
152      * interceptors.
153      *
154      * @param endpoint     the endpoint
155      * @param interceptors the endpoint interceptors
156      * @return the created invocation chain
157      * @see #setInterceptors(org.springframework.ws.server.EndpointInterceptor[])
158      */
159     protected EndpointInvocationChain createEndpointInvocationChain(MessageContext messageContext,
160                                                                     Object endpoint,
161                                                                     EndpointInterceptor[] interceptors) {
162         return new EndpointInvocationChain(endpoint, interceptors);
163     }
164 
165     /**
166      * Returns the default endpoint for this endpoint mapping.
167      *
168      * @return the default endpoint mapping, or null if none
169      */
170     protected final Object getDefaultEndpoint() {
171         return defaultEndpoint;
172     }
173 
174     /**
175      * Sets the default endpoint for this endpoint mapping. This endpoint will be returned if no specific mapping was
176      * found.
177      * <p/>
178      * Default is <code>null</code>, indicating no default endpoint.
179      *
180      * @param defaultEndpoint the default endpoint, or null if none
181      */
182     public final void setDefaultEndpoint(Object defaultEndpoint) {
183         this.defaultEndpoint = defaultEndpoint;
184     }
185 
186     /**
187      * Resolves an endpoint string. If the given string can is a bean name, it is resolved using the application
188      * context.
189      *
190      * @param endpointName the endpoint name
191      * @return the resolved endpoint, or <code>null</code> if the name could not be resolved
192      */
193     protected Object resolveStringEndpoint(String endpointName) {
194         if (getApplicationContext().containsBean(endpointName)) {
195             return getApplicationContext().getBean(endpointName);
196         }
197         else {
198             return null;
199         }
200     }
201 
202     /**
203      * Lookup an endpoint for the given request, returning <code>null</code> if no specific one is found. This template
204      * method is called by getEndpoint, a <code>null</code> return value will lead to the default handler, if one is
205      * set.
206      * <p/>
207      * The returned endpoint can be a string, in which case it is resolved as a bean name. Also, it can take the form
208      * <code>beanName#method</code>, in which case the method is resolved.
209      *
210      * @return the looked up endpoint instance, or null
211      * @throws Exception if there is an error
212      */
213     protected abstract Object getEndpointInternal(MessageContext messageContext) throws Exception;
214 }