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    }