View Javadoc

1   /*
2    * Copyright 2005 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.HashMap;
20  import java.util.Iterator;
21  import java.util.Map;
22  import java.util.Properties;
23  
24  import org.springframework.beans.BeansException;
25  import org.springframework.context.ApplicationContextException;
26  import org.springframework.util.StringUtils;
27  import org.springframework.ws.context.MessageContext;
28  
29  /**
30   * Abstract base class for endpoint mapping that are based on a <code>Map</code>. Provides mappings of application
31   * context beans as well as a settable map.
32   * <p/>
33   * Subclasses determine the exact nature of the key in the enpoint map; this can be a qualified name, a SOAP Header, the
34   * result of a XPath validation. The values are always endpoint objects, or bean names of endpoint objects.
35   *
36   * @author Arjen Poutsma
37   * @since 1.0.0
38   */
39  public abstract class AbstractMapBasedEndpointMapping extends AbstractEndpointMapping {
40  
41      private boolean lazyInitEndpoints = false;
42  
43      private boolean registerBeanNames = false;
44  
45      private final Map endpointMap = new HashMap();
46  
47      // holds mappings set via setEndpointMap and setMappings
48      private Map temporaryEndpointMap = new HashMap();
49  
50      /**
51       * Set whether to lazily initialize endpoints. Only applicable to singleton endpoints, as prototypes are always
52       * lazily initialized. Default is <code>false</code>, as eager initialization allows for more efficiency through
53       * referencing the controller objects directly.
54       * <p/>
55       * If you want to allow your endpoints to be lazily initialized, make them "lazy-init" and set this flag to
56       * <code>true</code>. Just making them "lazy-init" will not work, as they are initialized through the references
57       * from the endpoint mapping in this case.
58       */
59      public void setLazyInitEndpoints(boolean lazyInitEndpoints) {
60          this.lazyInitEndpoints = lazyInitEndpoints;
61      }
62  
63      /**
64       * Set whether to register bean names found in the application context. Setting this to <code>true</code> will
65       * register all beans found in the application context under their name. Default is <code>false</code>.
66       */
67      public final void setRegisterBeanNames(boolean registerBeanNames) {
68          this.registerBeanNames = registerBeanNames;
69      }
70  
71      /**
72       * Sets a Map with keys and endpoint beans as values. The nature of the keys in the given map depends on the exact
73       * subclass used. They can be qualified names, for instance, or mime headers.
74       *
75       * @throws IllegalArgumentException if the endpoint is invalid
76       */
77      public final void setEndpointMap(Map endpointMap) {
78          temporaryEndpointMap.putAll(endpointMap);
79      }
80  
81      /**
82       * Maps keys to endpoint bean names. The nature of the property names depends on the exact subclass used. They can
83       * be qualified names, for instance, or mime headers.
84       */
85      public void setMappings(Properties mappings) {
86          temporaryEndpointMap.putAll(mappings);
87      }
88  
89      /** Validates the given endpoint key. Should return <code>true</code> is the given string is valid. */
90      protected abstract boolean validateLookupKey(String key);
91  
92      /**
93       * Returns the the endpoint key for the given message context. Returns <code>null</code> if a key cannot be found.
94       *
95       * @return the registration key; or <code>null</code>
96       */
97      protected abstract String getLookupKeyForMessage(MessageContext messageContext) throws Exception;
98  
99      /**
100      * Lookup an endpoint for the given message. The extraction of the endpoint key is delegated to the concrete
101      * subclass.
102      *
103      * @return the looked up endpoint, or <code>null</code>
104      */
105     protected final Object getEndpointInternal(MessageContext messageContext) throws Exception {
106         String key = getLookupKeyForMessage(messageContext);
107         if (!StringUtils.hasLength(key)) {
108             return null;
109         }
110         if (logger.isDebugEnabled()) {
111             logger.debug("Looking up endpoint for [" + key + "]");
112         }
113         return lookupEndpoint(key);
114     }
115 
116     /**
117      * Looks up an endpoint instance for the given keys. All keys are tried in order.
118      *
119      * @param key key the beans are mapped to
120      * @return the associated endpoint instance, or <code>null</code> if not found
121      */
122     protected Object lookupEndpoint(String key) {
123         return endpointMap.get(key);
124     }
125 
126     /**
127      * Register the given endpoint instance under the registration key.
128      *
129      * @param key      the string representation of the registration key
130      * @param endpoint the endpoint instance
131      * @throws org.springframework.beans.BeansException
132      *          if the endpoint could not be registered
133      */
134     protected void registerEndpoint(String key, Object endpoint) throws BeansException {
135         Object mappedEndpoint = endpointMap.get(key);
136         if (mappedEndpoint != null) {
137             throw new ApplicationContextException("Cannot map endpoint [" + endpoint + "] on registration key [" + key +
138                     "]: there's already endpoint [" + mappedEndpoint + "] mapped");
139         }
140         if (!lazyInitEndpoints && endpoint instanceof String) {
141             String endpointName = (String) endpoint;
142             endpoint = resolveStringEndpoint(endpointName);
143         }
144         if (endpoint == null) {
145             throw new ApplicationContextException("Could not find endpoint for key [" + key + "]");
146         }
147         endpointMap.put(key, endpoint);
148         if (logger.isDebugEnabled()) {
149             logger.debug("Mapped key [" + key + "] onto endpoint [" + endpoint + "]");
150         }
151     }
152 
153     /**
154      * Registers annd checks the set endpoints. Checks the beans set through <code>setEndpointMap</code> and
155      * <code>setMappings</code>, and registers the bean names found in the application context, if
156      * <code>registerBeanNames</code> is set to <code>true</code>.
157      *
158      * @throws ApplicationContextException if either of the endpoints defined via <code>setEndpointMap</code> or
159      *                                     <code>setMappings</code> is invalid
160      * @see #setEndpointMap(java.util.Map)
161      * @see #setMappings(java.util.Properties)
162      * @see #setRegisterBeanNames(boolean)
163      */
164     protected final void initApplicationContext() throws BeansException {
165         for (Iterator iter = temporaryEndpointMap.keySet().iterator(); iter.hasNext();) {
166             String key = (String) iter.next();
167             Object endpoint = temporaryEndpointMap.get(key);
168             if (!validateLookupKey(key)) {
169                 throw new ApplicationContextException("Invalid key [" + key + "] for endpoint [" + endpoint + "]");
170             }
171             registerEndpoint(key, endpoint);
172         }
173         temporaryEndpointMap = null;
174         if (registerBeanNames) {
175             if (logger.isDebugEnabled()) {
176                 logger.debug("Looking for endpoint mappings in application context: [" + getApplicationContext() + "]");
177             }
178             String[] beanNames = getApplicationContext().getBeanDefinitionNames();
179             for (int i = 0; i < beanNames.length; i++) {
180                 if (validateLookupKey(beanNames[i])) {
181                     registerEndpoint(beanNames[i], beanNames[i]);
182                 }
183                 String[] aliases = getApplicationContext().getAliases(beanNames[i]);
184                 for (int j = 0; j < aliases.length; j++) {
185                     if (validateLookupKey(aliases[j])) {
186                         registerEndpoint(aliases[j], beanNames[i]);
187                     }
188                 }
189             }
190         }
191     }
192 
193 }