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 */
017package org.apache.camel.processor;
018
019import org.apache.camel.AsyncCallback;
020import org.apache.camel.AsyncProcessor;
021import org.apache.camel.Exchange;
022import org.apache.camel.Message;
023import org.apache.camel.impl.DefaultMessage;
024import org.apache.camel.support.ServiceSupport;
025import org.apache.camel.util.AsyncProcessorHelper;
026import org.apache.camel.util.ExchangeHelper;
027import org.apache.camel.util.IOHelper;
028import org.apache.camel.util.ObjectHelper;
029
030/**
031 * A processor which converts the payload of the input message to be of the given type
032 * <p/>
033 * If the conversion fails an {@link org.apache.camel.InvalidPayloadException} is thrown.
034 *
035 * @version 
036 */
037public class ConvertBodyProcessor extends ServiceSupport implements AsyncProcessor {
038    private final Class<?> type;
039    private final String charset;
040
041    public ConvertBodyProcessor(Class<?> type) {
042        ObjectHelper.notNull(type, "type", this);
043        this.type = type;
044        this.charset = null;
045    }
046
047    public ConvertBodyProcessor(Class<?> type, String charset) {
048        ObjectHelper.notNull(type, "type", this);
049        this.type = type;
050        this.charset = IOHelper.normalizeCharset(charset);
051    }
052
053    @Override
054    public String toString() {
055        return "convertBodyTo[" + type.getCanonicalName() + "]";
056    }
057
058    public void process(Exchange exchange) throws Exception {
059        AsyncProcessorHelper.process(this, exchange);
060    }
061
062    @Override
063    public boolean process(Exchange exchange, AsyncCallback callback) {
064        boolean out = exchange.hasOut();
065        Message old = out ? exchange.getOut() : exchange.getIn();
066
067        if (old.getBody() == null) {
068            // only convert if the is a body
069            callback.done(true);
070            return true;
071        }
072
073        if (charset != null) {
074            // override existing charset with configured charset as that is what the user
075            // have explicit configured and expects to be used
076            exchange.setProperty(Exchange.CHARSET_NAME, charset);
077        }
078        // use mandatory conversion
079        Object value;
080        try {
081            value = old.getMandatoryBody(type);
082        } catch (Exception e) {
083            exchange.setException(e);
084            callback.done(true);
085            return true;
086        }
087
088        // create a new message container so we do not drag specialized message objects along
089        // but that is only needed if the old message is a specialized message
090        boolean copyNeeded = !(old.getClass().equals(DefaultMessage.class));
091
092        if (copyNeeded) {
093            Message msg = new DefaultMessage();
094            msg.copyFrom(old);
095            msg.setBody(value);
096
097            // replace message on exchange
098            ExchangeHelper.replaceMessage(exchange, msg, false);
099        } else {
100            // no copy needed so set replace value directly
101            old.setBody(value);
102        }
103
104        // remove charset when we are done as we should not propagate that,
105        // as that can lead to double converting later on
106        if (charset != null) {
107            exchange.removeProperty(Exchange.CHARSET_NAME);
108        }
109
110        callback.done(true);
111        return true;
112    }
113
114    public Class<?> getType() {
115        return type;
116    }
117
118    @Override
119    protected void doStart() throws Exception {
120        // noop
121    }
122
123    @Override
124    protected void doStop() throws Exception {
125        // noop
126    }
127}