All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.camel.support.DefaultMessage Maven / Gradle / Ivy

There is a newer version: 4.6.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.camel.support;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;

import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.spi.HeadersMapFactory;
import org.apache.camel.util.ObjectHelper;

/**
 * The default implementation of {@link org.apache.camel.Message}
 * 

* This implementation uses a {@link org.apache.camel.util.CaseInsensitiveMap} storing the headers. * This allows us to be able to lookup headers using case insensitive keys, making it easier for end users * as they do not have to be worried about using exact keys. * See more details at {@link org.apache.camel.util.CaseInsensitiveMap}. * The implementation of the map can be configured by the {@link HeadersMapFactory} which can be set * on the {@link CamelContext}. The default implementation uses the {@link org.apache.camel.util.CaseInsensitiveMap CaseInsensitiveMap}. */ public class DefaultMessage extends MessageSupport { private Map headers; public DefaultMessage(Exchange exchange) { setExchange(exchange); setCamelContext(exchange != null ? exchange.getContext() : null); } public DefaultMessage(CamelContext camelContext) { setCamelContext(camelContext); } @Override public Object getHeader(String name) { if (hasHeaders()) { return getHeaders().get(name); } else { return null; } } @Override public Object getHeader(String name, Object defaultValue) { Object answer = getHeaders().get(name); return answer != null ? answer : defaultValue; } @Override public Object getHeader(String name, Supplier defaultValueSupplier) { ObjectHelper.notNull(name, "name"); ObjectHelper.notNull(defaultValueSupplier, "defaultValueSupplier"); Object answer = getHeaders().get(name); return answer != null ? answer : defaultValueSupplier.get(); } @Override @SuppressWarnings("unchecked") public T getHeader(String name, Class type) { Object value = getHeader(name); if (value == null) { // lets avoid NullPointerException when converting to boolean for null values if (boolean.class == type) { return (T) Boolean.FALSE; } return null; } // eager same instance type test to avoid the overhead of invoking the type converter // if already same type if (type.isInstance(value)) { return type.cast(value); } Exchange e = getExchange(); if (e != null) { return e.getContext().getTypeConverter().convertTo(type, e, value); } else { return type.cast(value); } } @Override @SuppressWarnings("unchecked") public T getHeader(String name, Object defaultValue, Class type) { Object value = getHeader(name, defaultValue); if (value == null) { // lets avoid NullPointerException when converting to boolean for null values if (boolean.class == type) { return (T) Boolean.FALSE; } return null; } // eager same instance type test to avoid the overhead of invoking the type converter // if already same type if (type.isInstance(value)) { return type.cast(value); } Exchange e = getExchange(); if (e != null) { return e.getContext().getTypeConverter().convertTo(type, e, value); } else { return type.cast(value); } } @Override @SuppressWarnings("unchecked") public T getHeader(String name, Supplier defaultValueSupplier, Class type) { ObjectHelper.notNull(name, "name"); ObjectHelper.notNull(type, "type"); ObjectHelper.notNull(defaultValueSupplier, "defaultValueSupplier"); Object value = getHeader(name, defaultValueSupplier); if (value == null) { // lets avoid NullPointerException when converting to boolean for null values if (boolean.class == type) { return (T) Boolean.FALSE; } return null; } // eager same instance type test to avoid the overhead of invoking the type converter // if already same type if (type.isInstance(value)) { return type.cast(value); } Exchange e = getExchange(); if (e != null) { return e.getContext().getTypeConverter().convertTo(type, e, value); } else { return type.cast(value); } } @Override public void setHeader(String name, Object value) { if (headers == null) { headers = createHeaders(); } headers.put(name, value); } @Override public Object removeHeader(String name) { if (!hasHeaders()) { return null; } return headers.remove(name); } @Override public boolean removeHeaders(String pattern) { return removeHeaders(pattern, (String[]) null); } @Override public boolean removeHeaders(String pattern, String... excludePatterns) { if (!hasHeaders()) { return false; } boolean matches = false; // must use a set to store the keys to remove as we cannot walk using entrySet and remove at the same time // due concurrent modification error Set toRemove = new HashSet<>(); for (Map.Entry entry : headers.entrySet()) { String key = entry.getKey(); if (PatternHelper.matchPattern(key, pattern)) { if (excludePatterns != null && PatternHelper.isExcludePatternMatch(key, excludePatterns)) { continue; } matches = true; toRemove.add(entry.getKey()); } } for (String key : toRemove) { headers.remove(key); } return matches; } @Override public Map getHeaders() { if (headers == null) { headers = createHeaders(); } return headers; } @Override public void setHeaders(Map headers) { ObjectHelper.notNull(getCamelContext(), "CamelContext", this); if (getCamelContext().getHeadersMapFactory().isInstanceOf(headers)) { this.headers = headers; } else { // create a new map this.headers = getCamelContext().getHeadersMapFactory().newMap(headers); } } @Override public boolean hasHeaders() { if (!hasPopulatedHeaders()) { // force creating headers getHeaders(); } return headers != null && !headers.isEmpty(); } @Override public DefaultMessage newInstance() { ObjectHelper.notNull(getCamelContext(), "CamelContext", this); return new DefaultMessage(getCamelContext()); } /** * A factory method to lazily create the headers to make it easy to create * efficient Message implementations which only construct and populate the * Map on demand * * @return return a newly constructed Map possibly containing headers from * the underlying inbound transport */ protected Map createHeaders() { ObjectHelper.notNull(getCamelContext(), "CamelContext", this); Map map = getCamelContext().getHeadersMapFactory().newMap(); populateInitialHeaders(map); return map; } /** * A strategy method populate the initial set of headers on an inbound * message from an underlying binding * * @param map is the empty header map to populate */ protected void populateInitialHeaders(Map map) { // do nothing by default } /** * A strategy for component specific messages to determine whether the * message is redelivered or not. *

* Important: It is not always possible to determine if the transacted is a redelivery * or not, and therefore null is returned. Such an example would be a JDBC message. * However JMS brokers provides details if a transacted message is redelivered. * * @return true if redelivered, false if not, null if not able to determine */ protected Boolean isTransactedRedelivered() { // return null by default return null; } /** * Returns true if the headers have been mutated in some way */ protected boolean hasPopulatedHeaders() { return headers != null; } }