001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.impl;
018
019 import java.util.HashMap;
020 import java.util.Map;
021 import java.util.Set;
022 import javax.activation.DataHandler;
023
024 import org.apache.camel.Exchange;
025 import org.apache.camel.Message;
026 import org.apache.camel.util.CaseInsensitiveMap;
027 import org.apache.camel.util.MessageHelper;
028
029 /**
030 * The default implementation of {@link org.apache.camel.Message}
031 * <p/>
032 * This implementation uses a {@link org.apache.camel.util.CaseInsensitiveMap} storing the headers.
033 * This allows us to be able to lookup headers using case insensitive keys, making it easier for end users
034 * as they do not have to be worried about using exact keys.
035 * See more details at {@link org.apache.camel.util.CaseInsensitiveMap}.
036 *
037 * @version $Revision: 893110 $
038 */
039 public class DefaultMessage extends MessageSupport {
040 private boolean fault;
041 private Map<String, Object> headers;
042 private Map<String, DataHandler> attachments;
043
044 @Override
045 public String toString() {
046 return MessageHelper.extractBodyForLogging(this);
047 }
048
049 @Override
050 public void copyFrom(Message that) {
051 super.copyFrom(that);
052 fault = that.isFault();
053 }
054
055 public boolean isFault() {
056 return fault;
057 }
058
059 public void setFault(boolean fault) {
060 this.fault = fault;
061 }
062
063 public Object getHeader(String name) {
064 return getHeaders().get(name);
065 }
066
067 public Object getHeader(String name, Object defaultValue) {
068 Object answer = getHeaders().get(name);
069 return answer != null ? answer : defaultValue;
070 }
071
072 public <T> T getHeader(String name, Class<T> type) {
073 Object value = getHeader(name);
074 if (value == null) {
075 return null;
076 }
077
078 // eager same instance type test to avoid the overhead of invoking the type converter
079 // if already same type
080 if (type.isInstance(value)) {
081 return type.cast(value);
082 }
083
084 Exchange e = getExchange();
085 if (e != null) {
086 return e.getContext().getTypeConverter().convertTo(type, e, value);
087 } else {
088 return type.cast(value);
089 }
090 }
091
092 public <T> T getHeader(String name, Object defaultValue, Class<T> type) {
093 Object value = getHeader(name, defaultValue);
094
095 // eager same instance type test to avoid the overhead of invoking the type converter
096 // if already same type
097 if (type.isInstance(value)) {
098 return type.cast(value);
099 }
100
101 Exchange e = getExchange();
102 if (e != null) {
103 return e.getContext().getTypeConverter().convertTo(type, e, value);
104 } else {
105 return type.cast(value);
106 }
107 }
108
109 public void setHeader(String name, Object value) {
110 if (headers == null) {
111 headers = createHeaders();
112 }
113 headers.put(name, value);
114 }
115
116 public Object removeHeader(String name) {
117 if (!hasHeaders()) {
118 return null;
119 }
120 return headers.remove(name);
121 }
122
123 public Map<String, Object> getHeaders() {
124 if (headers == null) {
125 headers = createHeaders();
126 }
127 return headers;
128 }
129
130 public void setHeaders(Map<String, Object> headers) {
131 if (headers instanceof CaseInsensitiveMap) {
132 this.headers = headers;
133 } else {
134 // wrap it in a case insensitive map
135 this.headers = new CaseInsensitiveMap(headers);
136 }
137 }
138
139 public boolean hasHeaders() {
140 if (!hasPopulatedHeaders()) {
141 // force creating headers
142 getHeaders();
143 }
144 return headers != null && !headers.isEmpty();
145 }
146
147 public DefaultMessage newInstance() {
148 return new DefaultMessage();
149 }
150
151 /**
152 * A factory method to lazily create the headers to make it easy to create
153 * efficient Message implementations which only construct and populate the
154 * Map on demand
155 *
156 * @return return a newly constructed Map possibly containing headers from
157 * the underlying inbound transport
158 */
159 protected Map<String, Object> createHeaders() {
160 Map<String, Object> map = new CaseInsensitiveMap();
161 populateInitialHeaders(map);
162 return map;
163 }
164
165 /**
166 * A factory method to lazily create the attachments to make it easy to
167 * create efficient Message implementations which only construct and
168 * populate the Map on demand
169 *
170 * @return return a newly constructed Map
171 */
172 protected Map<String, DataHandler> createAttachments() {
173 Map<String, DataHandler> map = new HashMap<String, DataHandler>();
174 populateInitialAttachments(map);
175 return map;
176 }
177
178 /**
179 * A strategy method populate the initial set of headers on an inbound
180 * message from an underlying binding
181 *
182 * @param map is the empty header map to populate
183 */
184 protected void populateInitialHeaders(Map<String, Object> map) {
185 // do nothing by default
186 }
187
188 /**
189 * A strategy method populate the initial set of attachments on an inbound
190 * message from an underlying binding
191 *
192 * @param map is the empty attachment map to populate
193 */
194 protected void populateInitialAttachments(Map<String, DataHandler> map) {
195 // do nothing by default
196 }
197
198 public void addAttachment(String id, DataHandler content) {
199 if (attachments == null) {
200 attachments = createAttachments();
201 }
202 attachments.put(id, content);
203 }
204
205 public DataHandler getAttachment(String id) {
206 return getAttachments().get(id);
207 }
208
209 public Set<String> getAttachmentNames() {
210 if (attachments == null) {
211 attachments = createAttachments();
212 }
213 return attachments.keySet();
214 }
215
216 public void removeAttachment(String id) {
217 if (attachments != null && attachments.containsKey(id)) {
218 attachments.remove(id);
219 }
220 }
221
222 public Map<String, DataHandler> getAttachments() {
223 if (attachments == null) {
224 attachments = createAttachments();
225 }
226 return attachments;
227 }
228
229 public void setAttachments(Map<String, DataHandler> attachments) {
230 this.attachments = attachments;
231 }
232
233 public boolean hasAttachments() {
234 if (attachments == null) {
235 attachments = createAttachments();
236 }
237 return this.attachments != null && this.attachments.size() > 0;
238 }
239
240 /**
241 * Returns true if the headers have been mutated in some way
242 */
243 protected boolean hasPopulatedHeaders() {
244 return headers != null;
245 }
246
247 public String createExchangeId() {
248 return null;
249 }
250 }