org.codehaus.groovy.grails.plugins.spring.ws.ReloadablePayloadRootQNameEndpointMapping.java Source code

Java tutorial

Introduction

Here is the source code for org.codehaus.groovy.grails.plugins.spring.ws.ReloadablePayloadRootQNameEndpointMapping.java

Source

/*
 * Copyright 2008-2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.codehaus.groovy.grails.plugins.spring.ws;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContextException;
import org.springframework.util.StringUtils;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.mapping.AbstractEndpointMapping;
import org.springframework.ws.server.endpoint.support.PayloadRootUtils;
import org.springframework.xml.namespace.QNameUtils;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * PayloadRootQNameEndpointMapping with reloadable endpoint mappings
 *
 * @author Arjen Poutsma
 * @author Ivo Houbrechts (ivo@houbrechts-it.be)
 *
 */
public class ReloadablePayloadRootQNameEndpointMapping extends AbstractEndpointMapping {

    private static TransformerFactory transformerFactory;

    static {
        transformerFactory = TransformerFactory.newInstance();
    }

    private boolean lazyInitEndpoints = false;

    private boolean registerBeanNames = false;

    private final Map<String, Object> endpointMap = new HashMap<String, Object>();

    // holds mappings set via setEndpointMap and setMappings
    private Map<String, Object> temporaryEndpointMap = new HashMap<String, Object>();

    /**
     * Set whether to lazily initialize endpoints. Only applicable to singleton endpoints, as prototypes are always
     * lazily initialized. Default is <code>false</code>, as eager initialization allows for more efficiency through
     * referencing the controller objects directly.
     * <p/>
     * If you want to allow your endpoints to be lazily initialized, make them "lazy-init" and set this flag to
     * <code>true</code>. Just making them "lazy-init" will not work, as they are initialized through the references
     * from the endpoint mapping in this case.
     */
    public void setLazyInitEndpoints(boolean lazyInitEndpoints) {
        this.lazyInitEndpoints = lazyInitEndpoints;
    }

    /**
     * Set whether to register bean names found in the application context. Setting this to <code>true</code> will
     * register all beans found in the application context under their name. Default is <code>false</code>.
     */
    public final void setRegisterBeanNames(boolean registerBeanNames) {
        this.registerBeanNames = registerBeanNames;
    }

    /**
     * Sets a Map with keys and endpoint beans as values. The nature of the keys in the given map depends on the exact
     * subclass used. They can be qualified names, for instance, or mime headers.
     *
     * @throws IllegalArgumentException if the endpoint is invalid
     */
    public final void setEndpointMap(Map<String, Object> endpointMap) {
        temporaryEndpointMap.putAll(endpointMap);
    }

    /**
     * Maps keys to endpoint bean names. The nature of the property names depends on the exact subclass used. They can
     * be qualified names, for instance, or mime headers.
     */
    public void setMappings(Properties mappings) {
        for (Map.Entry<Object, Object> entry : mappings.entrySet()) {
            temporaryEndpointMap.put(String.class.cast(entry.getKey()), entry.getValue());
        }
    }

    protected final String getLookupKeyForMessage(MessageContext messageContext) throws Exception {
        QName qName = resolveQName(messageContext);
        return qName != null ? qName.toString() : null;
    }

    protected QName resolveQName(MessageContext messageContext) throws TransformerException, XMLStreamException {
        return PayloadRootUtils.getPayloadRootQName(messageContext.getRequest().getPayloadSource(),
                transformerFactory);
    }

    protected boolean validateLookupKey(String key) {
        return QNameUtils.validateQName(key);
    }

    /**
     * Lookup an endpoint for the given message. The extraction of the endpoint key is delegated to the concrete
     * subclass.
     *
     * @return the looked up endpoint, or <code>null</code>
     */
    protected final Object getEndpointInternal(MessageContext messageContext) throws Exception {
        String key = getLookupKeyForMessage(messageContext);
        if (!StringUtils.hasLength(key)) {
            return null;
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up endpoint for [" + key + "]");
        }
        return lookupEndpoint(key);
    }

    /**
     * Looks up an endpoint instance for the given keys. All keys are tried in order.
     *
     * @param key key the beans are mapped to
     * @return the associated endpoint instance, or <code>null</code> if not found
     */
    protected Object lookupEndpoint(String key) {
        return endpointMap.get(key);
    }

    /**
     * Register the given endpoint instance under the registration key.
     *
     * @param key      the string representation of the registration key
     * @param endpoint the endpoint instance
     * @throws org.springframework.beans.BeansException
     *          if the endpoint could not be registered
     */
    protected void registerEndpoint(String key, Object endpoint) throws BeansException {
        Object mappedEndpoint = endpointMap.get(key);
        if (mappedEndpoint != null) {
            throw new ApplicationContextException("Cannot map endpoint [" + endpoint + "] on registration key ["
                    + key + "]: there's already endpoint [" + mappedEndpoint + "] mapped");
        }
        if (!lazyInitEndpoints && endpoint instanceof String) {
            String endpointName = (String) endpoint;
            endpoint = resolveStringEndpoint(endpointName);
        }
        if (endpoint == null) {
            throw new ApplicationContextException("Could not find endpoint for key [" + key + "]");
        }
        endpointMap.put(key, endpoint);
        if (logger.isDebugEnabled()) {
            logger.debug("Mapped key [" + key + "] onto endpoint [" + endpoint + "]");
        }
    }

    /**
     * Registers annd checks the set endpoints. Checks the beans set through <code>setEndpointMap</code> and
     * <code>setMappings</code>, and registers the bean names found in the application context, if
     * <code>registerBeanNames</code> is set to <code>true</code>.
     *
     * @throws ApplicationContextException if either of the endpoints defined via <code>setEndpointMap</code> or
     *                                     <code>setMappings</code> is invalid
     * @see #setEndpointMap(java.util.Map)
     * @see #setMappings(java.util.Properties)
     * @see #setRegisterBeanNames(boolean)
     */
    protected final void initApplicationContext() throws BeansException {
        for (Map.Entry<String, Object> entry : temporaryEndpointMap.entrySet()) {
            String key = entry.getKey();
            Object endpoint = entry.getValue();
            if (!validateLookupKey(key)) {
                throw new ApplicationContextException("Invalid key [" + key + "] for endpoint [" + endpoint + "]");
            }
            registerEndpoint(key, endpoint);
        }
        temporaryEndpointMap = null;
        if (registerBeanNames) {
            if (logger.isDebugEnabled()) {
                logger.debug(
                        "Looking for endpoint mappings in application context: [" + getApplicationContext() + "]");
            }
            String[] beanNames = getApplicationContext().getBeanDefinitionNames();
            for (int i = 0; i < beanNames.length; i++) {
                if (validateLookupKey(beanNames[i])) {
                    registerEndpoint(beanNames[i], beanNames[i]);
                }
                String[] aliases = getApplicationContext().getAliases(beanNames[i]);
                for (int j = 0; j < aliases.length; j++) {
                    if (validateLookupKey(aliases[j])) {
                        registerEndpoint(aliases[j], beanNames[i]);
                    }
                }
            }
        }
    }

    public void registerEndpoints(Map<String, Object> endpointsMap) throws BeansException {
        endpointMap.clear();
        for (Map.Entry<String, Object> entry : endpointsMap.entrySet()) {
            String key = entry.getKey();
            Object endpoint = entry.getValue();
            if (!validateLookupKey(key)) {
                throw new ApplicationContextException("Invalid key [" + key + "] for endpoint [" + endpoint + "]");
            }
            registerEndpoint(key, endpoint);
        }
    }

}