/** 
 * 
 * Copyright 2004 Protique Ltd
 * 
 * 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.activemq.bean;

import org.activemq.util.MessageListenerSupport;
import org.w3c.dom.Node;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;
import java.io.StringWriter;

/**
 * Performs a transformation on an XML message and then sends the result to the given destination
 * using any TrAX based {@link Transformer} instance
 *
 * @version $Revision: 1.1.1.1 $
 */
public class TransformerBean extends MessageListenerSupport {

    private Session session;
    private MessageProducer producer;
    private Transformer transformer;

    public TransformerBean() {
    }

    // Properties
    //-------------------------------------------------------------------------
    public Transformer getTransformer() {
        return transformer;
    }

    public void setTransformer(Transformer transformer) {
        this.transformer = transformer;
    }

    public MessageProducer getProducer() {
        return producer;
    }

    public void setProducer(MessageProducer producer) {
        this.producer = producer;
    }

    public Session getSession() {
        return session;
    }

    public void setSession(Session session) {
        this.session = session;
    }

    // Implementation methods
    //-------------------------------------------------------------------------
    protected void processMessage(Message inputMessage) throws Exception {
        Source source = createSource(inputMessage);
        StringWriter writer = new StringWriter();
        Result result = new StreamResult(writer);
        transformer.transform(source, result);
        String output = writer.toString();
        Message outputMessage = createMessage(output);
        configureMessage(inputMessage, outputMessage);
        send(outputMessage);
    }

    protected void send(Message message) throws JMSException {
        producer.send(message);
    }


    /**
     * Append any custom header properties
     */
    protected void configureMessage(Message inputMessage, Message outputMessage) throws JMSException {
        outputMessage.setJMSCorrelationID(inputMessage.getJMSCorrelationID());
    }

    protected Message createMessage(String output) throws JMSException {
        return getSession().createTextMessage(output);
    }

    protected Source createSource(Message message) throws JMSException {
        if (message instanceof TextMessage) {
            TextMessage textMessage = (TextMessage) message;
            String text = textMessage.getText();
            return createSource(text);
        }
        if (message instanceof ObjectMessage) {
            ObjectMessage objectMessage = (ObjectMessage) message;
            Object value = objectMessage.getObject();
            if (value instanceof String) {
                createSource((String) value);
            }
            else if (value instanceof Node) {
                return new DOMSource((Node) value);
            }
            else if (value != null) {
                createSource((String) value);
            }
        }
        throw new JMSException("Cannot convert message body to a String or a DOM Node");
    }

    protected StreamSource createSource(String text) {
        return new StreamSource(new StringReader(text));
    }
}
