Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2002-2013 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.messaging.handler.invocation;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 
Abstract base class for HandlerMethod-based message handling. Provides most of the logic required to discover handler methods at startup, find a matching handler method at runtime for a given message and invoke it.

Also supports discovering and invoking exception handling methods to process exceptions raised during message handling.

Parameters:
<T> the type of the Object that contains information mapping a org.springframework.messaging.handler.HandlerMethod to incoming messages
Author(s):
Rossen Stoyanchev
Since:
4.0
 
 public abstract class AbstractMethodMessageHandler<T>
 
 	protected final Log logger = LogFactory.getLog(getClass());
 
 
 
 
 
 
 
 	private final Map<T, HandlerMethodhandlerMethods = new LinkedHashMap<T, HandlerMethod>();
 
 	private final MultiValueMap<String, T> destinationLookup = new LinkedMultiValueMap<String, T>();
 
Configure one or more prefixes to match to the destinations of handled messages. Messages whose destination does not start with one of the configured prefixes are ignored. When a destination matches one of the configured prefixes, the matching part is removed from destination before performing a lookup for a matching message handling method. Prefixes without a trailing slash will have one appended automatically.

By default the list of prefixes is empty in which case all destinations match.

 
	public void setDestinationPrefixes(Collection<Stringprefixes) {
		if (prefixes != null) {
			for (String prefix : prefixes) {
				prefix = prefix.trim();
				if (!prefix.endsWith("/")) {
					prefix += "/";
				}
			}
		}
	}
		return this.;
	}

Sets the list of custom HandlerMethodArgumentResolvers that will be used after resolvers for supported argument type.

Parameters:
customArgumentResolvers the list of resolvers; never null.
	public void setCustomArgumentResolvers(List<HandlerMethodArgumentResolvercustomArgumentResolvers) {
		Assert.notNull(customArgumentResolvers"The 'customArgumentResolvers' cannot be null.");
		this. = customArgumentResolvers;
	}
	}

Set the list of custom HandlerMethodReturnValueHandlers that will be used after return value handlers for known types.

Parameters:
customReturnValueHandlers the list of custom return value handlers, never null.
	public void setCustomReturnValueHandlers(List<HandlerMethodReturnValueHandlercustomReturnValueHandlers) {
		Assert.notNull(customReturnValueHandlers"The 'customReturnValueHandlers' cannot be null.");
		this. = customReturnValueHandlers;
	}
	}

Configure the complete list of supported argument types effectively overriding the ones configured by default. This is an advanced option. For most use cases it should be sufficient to use setCustomArgumentResolvers(java.util.List).
	public void setArgumentResolvers(List<HandlerMethodArgumentResolverargumentResolvers) {
		if (argumentResolvers == null) {
			return;
		}
		this..addResolvers(argumentResolvers);
	}
	}

Configure the complete list of supported return value types effectively overriding the ones configured by default. This is an advanced option. For most use cases it should be sufficient to use setCustomReturnValueHandlers(java.util.List)
	public void setReturnValueHandlers(List<HandlerMethodReturnValueHandlerreturnValueHandlers) {
		if (returnValueHandlers == null) {
			return;
		}
		this..addHandlers(returnValueHandlers);
	}
	}

Return a map with all handler methods and their mappings.
		return Collections.unmodifiableMap(this.);
	}
	public void setApplicationContext(ApplicationContext applicationContextthrows BeansException {
		this. = applicationContext;
	}
		return this.;
	}
	public void afterPropertiesSet() {
		}
		}
		for (String beanName : this..getBeanNamesForType(Object.class)) {
			if (isHandler(this..getType(beanName))){
			}
		}
	}

Return the list of argument resolvers to use. Invoked only if the resolvers have not already been set via setArgumentResolvers(java.util.List).

Sub-classes should also take into account custom argument types configured via setCustomArgumentResolvers(java.util.List).

	protected abstract List<? extends HandlerMethodArgumentResolverinitArgumentResolvers();

Return the list of return value handlers to use. Invoked only if the return value handlers have not already been set via setReturnValueHandlers(java.util.List).

Sub-classes should also take into account custom return value types configured via setCustomReturnValueHandlers(java.util.List).

	protected abstract List<? extends HandlerMethodReturnValueHandlerinitReturnValueHandlers();


Whether the given bean type should be introspected for messaging handling methods.
	protected abstract boolean isHandler(Class<?> beanType);

Detect if the given handler has any methods that can handle messages and if so register it with the extracted mapping information.

Parameters:
handler the handler to check, either an instance of a Spring bean name
	protected final void detectHandlerMethods(Object handler) {
		Class<?> handlerType = (handler instanceof String) ?
				this..getType((Stringhandler) : handler.getClass();
		final Class<?> userType = ClassUtils.getUserClass(handlerType);
		Set<Methodmethods = HandlerMethodSelector.selectMethods(userTypenew ReflectionUtils.MethodFilter() {
			public boolean matches(Method method) {
				return getMappingForMethod(methoduserType) != null;
			}
		});
		for (Method method : methods) {
mapping = getMappingForMethod(methoduserType);
			registerHandlerMethod(handlermethodmapping);
		}
	}

Provide the mapping for a handler method.

Parameters:
method the method to provide a mapping for
handlerType the handler type, possibly a sub-type of the method's declaring class
Returns:
the mapping, or null if the method is not mapped
	protected abstract T getMappingForMethod(Method methodClass<?> handlerType);


Register a handler method and its unique mapping.

Parameters:
handler the bean name of the handler or the handler instance
method the method to register
mapping the mapping conditions associated with the handler method
Throws:
java.lang.IllegalStateException if another method was already registered under the same mapping
	protected void registerHandlerMethod(Object handlerMethod method, T mapping) {
		HandlerMethod newHandlerMethod = createHandlerMethod(handlermethod);
		HandlerMethod oldHandlerMethod = .get(mapping);
		if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {
			throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean()
"' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '"
oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped.");
		}
		this..put(mappingnewHandlerMethod);
			.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod);
		}
		for (String pattern : getDirectLookupDestinations(mapping)) {
			this..add(patternmapping);
		}
	}

Create a HandlerMethod instance from an Object handler that is either a handler instance or a String-based bean name.
	protected HandlerMethod createHandlerMethod(Object handlerMethod method) {
		HandlerMethod handlerMethod;
		if (handler instanceof String) {
			String beanName = (Stringhandler;
			handlerMethod = new HandlerMethod(beanNamethis.method);
		}
		else {
			handlerMethod = new HandlerMethod(handlermethod);
		}
		return handlerMethod;
	}

Return destinations contained in the mapping that are not patterns and are therefore suitable for direct lookups.
	protected abstract Set<StringgetDirectLookupDestinations(T mapping);
	public void handleMessage(Message<?> messagethrows MessagingException {
		String destination = getDestination(message);
		if (destination == null) {
			.trace("Ignoring message, no destination");
			return;
		}
		String lookupDestination = getLookupDestination(destination);
		if (lookupDestination == null) {
				.trace("Ignoring message to destination=" + destination);
			}
			return;
		}
			.debug("Handling message, lookupDestination=" + lookupDestination);
		}
		message = MessageBuilder.fromMessage(message).setHeader(
		handleMessageInternal(messagelookupDestination);
	}
	protected abstract String getDestination(Message<?> message);

Find if the given destination matches any of the configured allowed destination prefixes and if a match is found return the destination with the prefix removed.

If no destination prefixes are configured, the destination is returned as is.

Returns:
the destination to use to find matching message handling methods or null if the destination does not match
	protected String getLookupDestination(String destination) {
		if (destination == null) {
			return null;
		}
		if (CollectionUtils.isEmpty(this.)) {
			return destination;
		}
		for (String prefix : this.) {
			if (destination.startsWith(prefix)) {
				return destination.substring(prefix.length() - 1);
			}
		}
		return null;
	}
	protected void handleMessageInternal(Message<?> messageString lookupDestination) {
		List<Matchmatches = new ArrayList<Match>();
		List<T> mappingsByUrl = this..get(lookupDestination);
		if (mappingsByUrl != null) {
			addMatchesToCollection(mappingsByUrlmessagematches);
		}
		if (matches.isEmpty()) {
			// No direct hits, go through all mappings
			Set<T> allMappings = this..keySet();
			addMatchesToCollection(allMappingsmessagematches);
		}
		if (matches.isEmpty()) {
			handleNoMatch(.keySet(), lookupDestinationmessage);
			return;
		}
		Comparator<Matchcomparator = new MatchComparator(getMappingComparator(message));
		Collections.sort(matchescomparator);
			.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupDestination + "] : " + matches);
		}
		Match bestMatch = matches.get(0);
		if (matches.size() > 1) {
			Match secondBestMatch = matches.get(1);
			if (comparator.compare(bestMatchsecondBestMatch) == 0) {
				Method m1 = bestMatch.handlerMethod.getMethod();
				Method m2 = secondBestMatch.handlerMethod.getMethod();
				throw new IllegalStateException("Ambiguous handler methods mapped for destination '" +
						lookupDestination + "': {" + m1 + ", " + m2 + "}");
			}
		}
		handleMatch(bestMatch.mappingbestMatch.handlerMethodlookupDestinationmessage);
	}
	private void addMatchesToCollection(Collection<T> mappingsToCheckMessage<?> messageList<Matchmatches) {
		for (T mapping : mappingsToCheck) {
match = getMatchingMapping(mappingmessage);
			if (match != null) {
				matches.add(new Match(match.get(mapping)));
			}
		}
	}

Check if a mapping matches the current message and return a possibly new mapping with conditions relevant to the current request.

Parameters:
mapping the mapping to get a match for
message the message being handled
Returns:
the match or null if there is no match
	protected abstract T getMatchingMapping(T mappingMessage<?> message);

Return a comparator for sorting matching mappings. The returned comparator should sort 'better' matches higher.

Parameters:
message the current Message
Returns:
the comparator, never null
	protected abstract Comparator<T> getMappingComparator(Message<?> message);
	protected void handleMatch(T mappingHandlerMethod handlerMethodString lookupDestinationMessage<?> message) {
			.debug("Message matched to " + handlerMethod);
		}
		handlerMethod = handlerMethod.createWithResolvedBean();
		InvocableHandlerMethod invocable = new InvocableHandlerMethod(handlerMethod);
		try {
			Object returnValue = invocable.invoke(message);
			MethodParameter returnType = handlerMethod.getReturnType();
			if (void.class.equals(returnType.getParameterType())) {
				return;
			}
			this..handleReturnValue(returnValuereturnTypemessage);
		}
		catch (Exception ex) {
			processHandlerMethodException(handlerMethodexmessage);
		}
		catch (Throwable ex) {
			.error("Error while processing message " + messageex);
		}
	}
	protected void processHandlerMethodException(HandlerMethod handlerMethodException exMessage<?> message) {
		Class<?> beanType = handlerMethod.getBeanType();
		if (resolver == null) {
			this..put(beanTyperesolver);
		}
		Method method = resolver.resolveMethod(ex);
		if (method == null) {
			.error("Unhandled exception"ex);
			return;
		}
		InvocableHandlerMethod invocable = new InvocableHandlerMethod(handlerMethod.getBean(), method);
		try {
			Object returnValue = invocable.invoke(messageex);
			MethodParameter returnType = invocable.getReturnType();
			if (void.class.equals(returnType.getParameterType())) {
				return;
			}
			this..handleReturnValue(returnValuereturnTypemessage);
		}
		catch (Throwable t) {
			.error("Error while handling exception"t);
			return;
		}
	}
	protected void handleNoMatch(Set<T> tsString lookupDestinationMessage<?> message) {
			.debug("No matching method found");
		}
	}


A thin wrapper around a matched HandlerMethod and its matched mapping for the purpose of comparing the best match with a comparator in the context of a message.
	private class Match {
		private final T mapping;
		private final HandlerMethod handlerMethod;
		private Match(T mappingHandlerMethod handlerMethod) {
			this. = mapping;
			this. = handlerMethod;
		}
		public String toString() {
			return this..toString();
		}
	}
	private class MatchComparator implements Comparator<Match> {
		private final Comparator<T> comparator;
		public MatchComparator(Comparator<T> comparator) {
			this. = comparator;
		}
		public int compare(Match match1Match match2) {
			return this..compare(match1.mappingmatch2.mapping);
		}
	}
New to GrepCode? Check out our FAQ X