Package org.springframework.ws.server.endpoint.mapping

Source Code of org.springframework.ws.server.endpoint.mapping.AbstractMethodEndpointMapping

/*
* Copyright 2005-2011 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.springframework.ws.server.endpoint.mapping;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContextException;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MethodEndpoint;

/**
* Abstract base class for {@link MethodEndpoint} mappings.
*
* <p>Subclasses typically implement {@link org.springframework.beans.factory.config.BeanPostProcessor} to look for beans
* that qualify as endpoint. The methods of this bean are then registered under a specific key with {@link
* #registerEndpoint(Object, MethodEndpoint)}.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public abstract class AbstractMethodEndpointMapping<T> extends AbstractEndpointMapping {

    private final Map<T, MethodEndpoint> endpointMap = new HashMap<T, MethodEndpoint>();

    /**
     * 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}
     * @see #getLookupKeyForMessage(MessageContext)
     */
    @Override
    protected Object getEndpointInternal(MessageContext messageContext) throws Exception {
        T key = getLookupKeyForMessage(messageContext);
        if (key == null) {
            return null;
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up endpoint for [" + key + "]");
        }
        return lookupEndpoint(key);
    }

    /**
     * Returns the the endpoint keys for the given message context.
     *
     * @return the registration keys
     */
    protected abstract T getLookupKeyForMessage(MessageContext messageContext) throws Exception;

    /**
     * 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} if not found
     */
    protected MethodEndpoint lookupEndpoint(T key) {
        return endpointMap.get(key);
    }

    /**
     * Register the given endpoint instance under the key.
     *
     * @param key      the lookup key
     * @param endpoint the method endpoint instance
     * @throws BeansException if the endpoint could not be registered
     */
    protected void registerEndpoint(T key, MethodEndpoint 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 (endpoint == null) {
            throw new ApplicationContextException("Could not find endpoint for key [" + key + "]");
        }
        endpointMap.put(key, endpoint);
        if (logger.isDebugEnabled()) {
            logger.debug("Mapped [" + key + "] onto endpoint [" + endpoint + "]");
        }
    }

    /**
     * Helper method that registers the methods of the given bean. This method iterates over the methods of the bean,
     * and calls {@link #getLookupKeyForMethod(Method)} for each. If this returns a string, the method is registered
     * using {@link #registerEndpoint(Object, MethodEndpoint)}.
     *
     * @see #getLookupKeyForMethod(Method)
     */
    protected void registerMethods(final Object endpoint) {
        Assert.notNull(endpoint, "'endpoint' must not be null");
        Class<?> endpointClass = getEndpointClass(endpoint);
        ReflectionUtils.doWithMethods(endpointClass, new ReflectionUtils.MethodCallback() {

            public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
              List<T> keys = getLookupKeysForMethod(method);
              for (T key : keys) {
                registerEndpoint(key, new MethodEndpoint(endpoint, method));
              }
            }
        });
    }

    /**
     * Helper method that registers the methods of the given class. This method iterates over the methods of the class,
     * and calls {@link #getLookupKeyForMethod(Method)} for each. If this returns a string, the method is registered
     * using {@link #registerEndpoint(Object, MethodEndpoint)}.
     *
     * @see #getLookupKeyForMethod(Method)
     * @see #getLookupKeysForMethod(Method)
     */
    protected void registerMethods(String beanName) {
        Assert.hasText(beanName, "'beanName' must not be empty");
        Class<?> endpointType = getApplicationContext().getType(beanName);
        endpointType = ClassUtils.getUserClass(endpointType);
       
        Set<Method> methods = findEndpointMethods(endpointType, new ReflectionUtils.MethodFilter() {
            public boolean matches(Method method) {
              return !getLookupKeysForMethod(method).isEmpty();
            }
        });

        for (Method method : methods) {
          List<T> keys = getLookupKeysForMethod(method);
          for (T key : keys) {
            registerEndpoint(key, new MethodEndpoint(beanName, getApplicationContext(), method));
          }
        }

    }

    private Set<Method> findEndpointMethods(Class<?> endpointType,
                                            final ReflectionUtils.MethodFilter endpointMethodFilter) {
        final Set<Method> endpointMethods = new LinkedHashSet<Method>();
        Set<Class<?>> endpointTypes = new LinkedHashSet<Class<?>>();
        Class<?> specificEndpointType = null;
        if (!Proxy.isProxyClass(endpointType)) {
            endpointTypes.add(endpointType);
            specificEndpointType = endpointType;
        }
        endpointTypes.addAll(Arrays.asList(endpointType.getInterfaces()));
        for (Class<?> currentEndpointType : endpointTypes) {
            final Class<?> targetClass = (specificEndpointType != null ? specificEndpointType : currentEndpointType);
            ReflectionUtils.doWithMethods(currentEndpointType, new ReflectionUtils.MethodCallback() {
                public void doWith(Method method) {
                    Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
                    Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
                    if (endpointMethodFilter.matches(specificMethod) &&
                            (bridgedMethod == specificMethod || !endpointMethodFilter.matches(bridgedMethod))) {
                        endpointMethods.add(specificMethod);
                    }
                }
            }, ReflectionUtils.USER_DECLARED_METHODS);
        }
        return endpointMethods;
    }

    /**
     * Returns the the endpoint key for the given method. Returns {@code null} if the method is not to be
     * registered, which is the default.
     *
     * @param method the method
     * @return a registration key, or {@code null} if the method is not to be registered
     * @see #getLookupKeysForMethod(Method)
     */
    protected T getLookupKeyForMethod(Method method) {
        return null;
    }

    /**
     * Returns the the endpoint keys for the given method. Should return an empty array if the method is not to be
     * registered. The default delegates to {@link #getLookupKeysForMethod(Method)}.
     *
     * @param method the method
     * @return a list of registration keys
     * @since 2.2
     */
    protected List<T> getLookupKeysForMethod(Method method) {
      T key = getLookupKeyForMethod(method);
      return key != null ? Collections.singletonList(key) : Collections.<T>emptyList();
    }

    /**
     * Return the class or interface to use for method reflection.
     *
     * <p>Default implementation delegates to {@link AopUtils#getTargetClass(Object)}.
     *
     * @param endpoint the bean instance (might be an AOP proxy)
     * @return the bean class to expose
     */
    protected Class<?> getEndpointClass(Object endpoint) {
        if (AopUtils.isJdkDynamicProxy(endpoint)) {
            throw new IllegalArgumentException(ClassUtils.getShortName(getClass()) +
                    " does not work with JDK Dynamic Proxies. " +
                    "Please use CGLIB proxies, by setting proxy-target-class=\"true\" on the aop:aspectj-autoproxy " +
                    "or aop:config element.");
        }
        return AopUtils.getTargetClass(endpoint);
    }
}
TOP

Related Classes of org.springframework.ws.server.endpoint.mapping.AbstractMethodEndpointMapping

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.