001: /*
002: * Copyright 2005 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.ws.server.endpoint.mapping;
018:
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.Map;
022: import java.util.Properties;
023:
024: import org.springframework.beans.BeansException;
025: import org.springframework.context.ApplicationContextException;
026: import org.springframework.util.StringUtils;
027: import org.springframework.ws.context.MessageContext;
028:
029: /**
030: * Abstract base class for endpoint mapping that are based on a <code>Map</code>. Provides mappings of application
031: * context beans as well as a settable map.
032: * <p/>
033: * Subclasses determine the exact nature of the key in the enpoint map; this can be a qualified name, a SOAP Header, the
034: * result of a XPath validation. The values are always endpoint objects, or bean names of endpoint objects.
035: *
036: * @author Arjen Poutsma
037: * @since 1.0.0
038: */
039: public abstract class AbstractMapBasedEndpointMapping extends
040: AbstractEndpointMapping {
041:
042: private boolean lazyInitEndpoints = false;
043:
044: private boolean registerBeanNames = false;
045:
046: private final Map endpointMap = new HashMap();
047:
048: // holds mappings set via setEndpointMap and setMappings
049: private Map temporaryEndpointMap = new HashMap();
050:
051: /**
052: * Set whether to lazily initialize endpoints. Only applicable to singleton endpoints, as prototypes are always
053: * lazily initialized. Default is <code>false</code>, as eager initialization allows for more efficiency through
054: * referencing the controller objects directly.
055: * <p/>
056: * If you want to allow your endpoints to be lazily initialized, make them "lazy-init" and set this flag to
057: * <code>true</code>. Just making them "lazy-init" will not work, as they are initialized through the references
058: * from the endpoint mapping in this case.
059: */
060: public void setLazyInitEndpoints(boolean lazyInitEndpoints) {
061: this .lazyInitEndpoints = lazyInitEndpoints;
062: }
063:
064: /**
065: * Set whether to register bean names found in the application context. Setting this to <code>true</code> will
066: * register all beans found in the application context under their name. Default is <code>false</code>.
067: */
068: public final void setRegisterBeanNames(boolean registerBeanNames) {
069: this .registerBeanNames = registerBeanNames;
070: }
071:
072: /**
073: * Sets a Map with keys and endpoint beans as values. The nature of the keys in the given map depends on the exact
074: * subclass used. They can be qualified names, for instance, or mime headers.
075: *
076: * @throws IllegalArgumentException if the endpoint is invalid
077: */
078: public final void setEndpointMap(Map endpointMap) {
079: temporaryEndpointMap.putAll(endpointMap);
080: }
081:
082: /**
083: * Maps keys to endpoint bean names. The nature of the property names depends on the exact subclass used. They can
084: * be qualified names, for instance, or mime headers.
085: */
086: public void setMappings(Properties mappings) {
087: temporaryEndpointMap.putAll(mappings);
088: }
089:
090: /** Validates the given endpoint key. Should return <code>true</code> is the given string is valid. */
091: protected abstract boolean validateLookupKey(String key);
092:
093: /**
094: * Returns the the endpoint keys for the given message context.
095: *
096: * @return the registration keys
097: */
098: protected abstract String getLookupKeyForMessage(
099: MessageContext messageContext) throws Exception;
100:
101: /**
102: * Lookup an endpoint for the given message. The extraction of the endpoint key is delegated to the concrete
103: * subclass.
104: *
105: * @return the looked up endpoint, or <code>null</code>
106: */
107: protected final Object getEndpointInternal(
108: MessageContext messageContext) throws Exception {
109: String key = getLookupKeyForMessage(messageContext);
110: if (!StringUtils.hasLength(key)) {
111: return null;
112: }
113: if (logger.isDebugEnabled()) {
114: logger.debug("Looking up endpoint for [" + key + "]");
115: }
116: return lookupEndpoint(key);
117: }
118:
119: /**
120: * Looks up an endpoint instance for the given keys. All keys are tried in order.
121: *
122: * @param key key the beans are mapped to
123: * @return the associated endpoint instance, or <code>null</code> if not found
124: */
125: protected Object lookupEndpoint(String key) {
126: return endpointMap.get(key);
127: }
128:
129: /**
130: * Register the given endpoint instance under the registration key.
131: *
132: * @param key the string representation of the registration key
133: * @param endpoint the endpoint instance
134: * @throws org.springframework.beans.BeansException
135: * if the endpoint could not be registered
136: */
137: protected void registerEndpoint(String key, Object endpoint)
138: throws BeansException {
139: Object mappedEndpoint = endpointMap.get(key);
140: if (mappedEndpoint != null) {
141: throw new ApplicationContextException(
142: "Cannot map endpoint [" + endpoint
143: + "] on registration key [" + key
144: + "]: there's already endpoint ["
145: + mappedEndpoint + "] mapped");
146: }
147: if (!lazyInitEndpoints && endpoint instanceof String) {
148: String endpointName = (String) endpoint;
149: endpoint = resolveStringEndpoint(endpointName);
150: }
151: if (endpoint == null) {
152: throw new ApplicationContextException(
153: "Could not find endpoint for key [" + key + "]");
154: }
155: endpointMap.put(key, endpoint);
156: if (logger.isDebugEnabled()) {
157: logger.debug("Mapped key [" + key + "] onto endpoint ["
158: + endpoint + "]");
159: }
160: }
161:
162: /**
163: * Registers annd checks the set endpoints. Checks the beans set through <code>setEndpointMap</code> and
164: * <code>setMappings</code>, and registers the bean names found in the application context, if
165: * <code>registerBeanNames</code> is set to <code>true</code>.
166: *
167: * @throws ApplicationContextException if either of the endpoints defined via <code>setEndpointMap</code> or
168: * <code>setMappings</code> is invalid
169: * @see #setEndpointMap(java.util.Map)
170: * @see #setMappings(java.util.Properties)
171: * @see #setRegisterBeanNames(boolean)
172: */
173: protected final void initApplicationContext() throws BeansException {
174: for (Iterator iter = temporaryEndpointMap.keySet().iterator(); iter
175: .hasNext();) {
176: String key = (String) iter.next();
177: Object endpoint = temporaryEndpointMap.get(key);
178: if (!validateLookupKey(key)) {
179: throw new ApplicationContextException("Invalid key ["
180: + key + "] for endpoint [" + endpoint + "]");
181: }
182: registerEndpoint(key, endpoint);
183: }
184: temporaryEndpointMap = null;
185: if (registerBeanNames) {
186: if (logger.isDebugEnabled()) {
187: logger
188: .debug("Looking for endpoint mappings in application context: ["
189: + getApplicationContext() + "]");
190: }
191: String[] beanNames = getApplicationContext()
192: .getBeanDefinitionNames();
193: for (int i = 0; i < beanNames.length; i++) {
194: if (validateLookupKey(beanNames[i])) {
195: registerEndpoint(beanNames[i], beanNames[i]);
196: }
197: String[] aliases = getApplicationContext().getAliases(
198: beanNames[i]);
199: for (int j = 0; j < aliases.length; j++) {
200: if (validateLookupKey(aliases[j])) {
201: registerEndpoint(aliases[j], beanNames[i]);
202: }
203: }
204: }
205: }
206: }
207:
208: }
|