Java tutorial
/* * 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.integration.mapping; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.integration.MessageHeaders; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.PatternMatchUtils; import org.springframework.util.StringUtils; /** * Abstract base class for HeaderMapper implementations. * * @author Mark Fisher * @author Oleg Zhurakousky * @since 2.1 */ public abstract class AbstractHeaderMapper<T> implements RequestReplyHeaderMapper<T> { public static final String STANDARD_REQUEST_HEADER_NAME_PATTERN = "STANDARD_REQUEST_HEADERS"; public static final String STANDARD_REPLY_HEADER_NAME_PATTERN = "STANDARD_REPLY_HEADERS"; private static final String[] TRANSIENT_HEADER_NAMES = new String[] { MessageHeaders.ID, MessageHeaders.ERROR_CHANNEL, MessageHeaders.REPLY_CHANNEL, MessageHeaders.TIMESTAMP }; protected final Log logger = LogFactory.getLog(this.getClass()); private final String standardHeaderPrefix; private volatile String userDefinedHeaderPrefix = ""; private volatile List<String> requestHeaderNames = new ArrayList<String>(); private volatile List<String> replyHeaderNames = new ArrayList<String>(); protected AbstractHeaderMapper() { this.standardHeaderPrefix = this.getStandardHeaderPrefix(); this.requestHeaderNames.addAll(this.getStandardRequestHeaderNames()); this.replyHeaderNames.addAll(this.getStandardReplyHeaderNames()); } /** * Provide the header names that should be mapped from a request (for inbound/outbound adapters) * TO a Spring Integration Message's headers. * The values can also contain simple wildcard patterns (e.g. "foo*" or "*foo") to be matched. * <p> * This will match the header name directly or, for non-standard headers, it will match * the header name prefixed with the value, if specified, by {@link #setUserDefinedHeaderPrefix(String)}. */ public void setRequestHeaderNames(String[] requestHeaderNames) { Assert.notNull(requestHeaderNames, "'requestHeaderNames' must not be null"); this.requestHeaderNames = Arrays.asList(requestHeaderNames); } /** * Provide the header names that should be mapped to a response (for inbound/outbound adapters) * FROM a Spring Integration Message's headers. * The values can also contain simple wildcard patterns (e.g. "foo*" or "*foo") to be matched. * <p> * Any non-standard headers will be prefixed with the value specified by {@link #setUserDefinedHeaderPrefix(String)}. */ public void setReplyHeaderNames(String[] replyHeaderNames) { Assert.notNull(replyHeaderNames, "'replyHeaderNames' must not be null"); this.replyHeaderNames = Arrays.asList(replyHeaderNames); } /** * Specify a prefix to be prepended to the header name for any integration * message header that is being mapped to or from a user-defined value. * <p> * This does not affect the standard properties for the particular protocol, such as * contentType for AMQP, etc. The header names used for mapping such properties are * defined in a corresponding Headers class as constants (e.g. AmqpHeaders). */ public void setUserDefinedHeaderPrefix(String userDefinedHeaderPrefix) { this.userDefinedHeaderPrefix = (userDefinedHeaderPrefix != null) ? userDefinedHeaderPrefix : ""; } /** * Maps headers from a Spring Integration MessageHeaders instance to the target instance * matching on the set of REQUEST headers (if different). */ public void fromHeadersToRequest(MessageHeaders headers, T target) { this.fromHeaders(headers, target, this.requestHeaderNames); } /** * Maps headers from a Spring Integration MessageHeaders instance to the target instance * matching on the set of REPLY headers (if different). */ public void fromHeadersToReply(MessageHeaders headers, T target) { this.fromHeaders(headers, target, this.replyHeaderNames); } /** * Maps headers/properties of the target object to Map of MessageHeaders * matching on the set of REQUEST headers */ public Map<String, Object> toHeadersFromRequest(T source) { return this.toHeaders(source, this.requestHeaderNames); } /** * Maps headers/properties of the target object to Map of MessageHeaders * matching on the set of REPLY headers */ public Map<String, Object> toHeadersFromReply(T source) { return this.toHeaders(source, this.replyHeaderNames); } private void fromHeaders(MessageHeaders headers, T target, List<String> headerPatterns) { try { Map<String, Object> subset = new HashMap<String, Object>(); for (String headerName : headers.keySet()) { if (this.shouldMapHeader(headerName, headerPatterns)) { subset.put(headerName, headers.get(headerName)); } } this.populateStandardHeaders(subset, target); this.populateUserDefinedHeaders(subset, target); } catch (Exception e) { if (logger.isWarnEnabled()) { logger.warn("error occurred while mapping from MessageHeaders", e); } } } private void populateUserDefinedHeaders(Map<String, Object> headers, T target) { for (String headerName : headers.keySet()) { Object value = headers.get(headerName); if (value != null) { try { if (!headerName.startsWith(this.standardHeaderPrefix)) { String key = this.addPrefixIfNecessary(this.userDefinedHeaderPrefix, headerName); this.populateUserDefinedHeader(key, value, target); } } catch (Exception e) { if (logger.isWarnEnabled()) { logger.warn("failed to map from Message header '" + headerName + "' to target", e); } } } } } /** * Maps headers from a source instance to the MessageHeaders of a * Spring Integration Message. */ private Map<String, Object> toHeaders(T source, List<String> headerPatterns) { Map<String, Object> headers = new HashMap<String, Object>(); Map<String, Object> standardHeaders = this.extractStandardHeaders(source); this.copyHeaders(this.standardHeaderPrefix, standardHeaders, headers, headerPatterns); Map<String, Object> userDefinedHeaders = this.extractUserDefinedHeaders(source); this.copyHeaders(this.userDefinedHeaderPrefix, userDefinedHeaders, headers, headerPatterns); return headers; } private <V> void copyHeaders(String prefix, Map<String, Object> source, Map<String, Object> target, List<String> headerPatterns) { if (!CollectionUtils.isEmpty(source)) { for (Map.Entry<String, Object> entry : source.entrySet()) { try { String headerName = this.addPrefixIfNecessary(prefix, entry.getKey()); if (this.shouldMapHeader(headerName, headerPatterns)) { target.put(headerName, entry.getValue()); } } catch (Exception e) { if (logger.isWarnEnabled()) { logger.warn( "error occurred while mapping header '" + entry.getKey() + "' to Message header", e); } } } } } private boolean shouldMapHeader(String headerName, List<String> patterns) { if (!StringUtils.hasText(headerName) || ObjectUtils.containsElement(TRANSIENT_HEADER_NAMES, headerName)) { return false; } if (patterns != null && patterns.size() > 0) { for (String pattern : patterns) { if (PatternMatchUtils.simpleMatch(pattern.toLowerCase(), headerName.toLowerCase())) { if (logger.isDebugEnabled()) { logger.debug(MessageFormat.format("headerName=[{0}] WILL be mapped, matched pattern={1}", headerName, pattern)); } return true; } else if (STANDARD_REQUEST_HEADER_NAME_PATTERN.equals(pattern) && this.containsElementIgnoreCase(this.getStandardRequestHeaderNames(), headerName)) { if (logger.isDebugEnabled()) { logger.debug(MessageFormat.format("headerName=[{0}] WILL be mapped, matched pattern={1}", headerName, pattern)); } return true; } else if (STANDARD_REPLY_HEADER_NAME_PATTERN.equals(pattern) && this.containsElementIgnoreCase(this.getStandardReplyHeaderNames(), headerName)) { if (logger.isDebugEnabled()) { logger.debug(MessageFormat.format("headerName=[{0}] WILL be mapped, matched pattern={1}", headerName, pattern)); } return true; } } } if (logger.isDebugEnabled()) { logger.debug(MessageFormat.format("headerName=[{0}] WILL NOT be mapped", headerName)); } return false; } @SuppressWarnings("unchecked") protected <V> V getHeaderIfAvailable(Map<String, Object> headers, String name, Class<V> type) { Object value = headers.get(name); if (value == null) { return null; } if (!type.isAssignableFrom(value.getClass())) { if (logger.isWarnEnabled()) { logger.warn("skipping header '" + name + "' since it is not of expected type [" + type + "], it is [" + value.getClass() + "]"); } return null; } else { return (V) value; } } private boolean containsElementIgnoreCase(List<String> headerNames, String name) { for (String headerName : headerNames) { if (headerName.equalsIgnoreCase(name)) { return true; } } return false; } /** * Adds the prefix to the header name */ private String addPrefixIfNecessary(String prefix, String propertyName) { String headerName = propertyName; if (StringUtils.hasText(prefix) && !headerName.startsWith(prefix) && !headerName.equals(MessageHeaders.CONTENT_TYPE)) { headerName = prefix + propertyName; } return headerName; } /** * Returns the list of standard REQUEST headers. Implementation provided by a subclass */ protected List<String> getStandardReplyHeaderNames() { return Collections.emptyList(); } /** * Returns the PREFIX used by standard headers (if any) */ protected List<String> getStandardRequestHeaderNames() { return Collections.emptyList(); } /** * Returns the list of standard REPLY headers. Implementation provided by a subclass */ protected abstract String getStandardHeaderPrefix(); protected abstract Map<String, Object> extractStandardHeaders(T source); protected abstract Map<String, Object> extractUserDefinedHeaders(T source); protected abstract void populateStandardHeaders(Map<String, Object> headers, T target); protected abstract void populateUserDefinedHeader(String headerName, Object headerValue, T target); }