001    /** 
002     * 
003     * Copyright 2004 Protique Ltd
004     * 
005     * Licensed under the Apache License, Version 2.0 (the "License"); 
006     * you may not use this file except in compliance with the License. 
007     * 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     **/
018    package org.codehaus.activesoap.transport.jms;
019    
020    import org.apache.commons.logging.Log;
021    import org.apache.commons.logging.LogFactory;
022    import org.codehaus.activesoap.SoapService;
023    
024    import javax.jms.Destination;
025    import javax.jms.JMSException;
026    import javax.jms.Message;
027    import javax.jms.MessageListener;
028    import javax.jms.MessageProducer;
029    import javax.jms.Session;
030    import javax.jms.TextMessage;
031    import java.io.PrintWriter;
032    import java.io.StringReader;
033    import java.io.StringWriter;
034    
035    /**
036     * A SOAP endpoint which listens to JMS messages, processes them with the SOAP stack
037     * and then sends the response to a new destination or replies to the inbound JMSReployTo destination.
038     *
039     * @version $Revision: 1.2 $
040     */
041    public class SoapEndpointMessageListener implements MessageListener {
042        private static final Log log = LogFactory.getLog(SoapEndpointMessageListener.class);
043    
044        private SoapService soapService;
045        private Session session;
046        private MessageProducer producer;
047        private Destination deadLetterQueue;
048        private Destination replyToDestination;
049    
050        public SoapEndpointMessageListener(SoapService soapService, Session session, MessageProducer producer, Destination deadLetterQueue) {
051            this.soapService = soapService;
052            this.session = session;
053            this.producer = producer;
054            this.deadLetterQueue = deadLetterQueue;
055        }
056    
057        public void onMessage(Message message) {
058            if (message instanceof TextMessage) {
059                try {
060                    onTextMessage((TextMessage) message);
061                }
062                catch (Exception e) {
063                    onException(e, message);
064                }
065            }
066            else {
067                sendToDeadLetterQueue("Expected TextMessage", message);
068            }
069        }
070    
071        // Properties
072        //-------------------------------------------------------------------------
073        public SoapService getSoapService() {
074            return soapService;
075        }
076    
077        public void setSoapService(SoapService soapService) {
078            this.soapService = soapService;
079        }
080    
081        public Destination getDeadLetterQueue() {
082            return deadLetterQueue;
083        }
084    
085        public void setDeadLetterQueue(Destination deadLetterQueue) {
086            this.deadLetterQueue = deadLetterQueue;
087        }
088    
089        public MessageProducer getProducer() {
090            return producer;
091        }
092    
093        public void setProducer(MessageProducer producer) {
094            this.producer = producer;
095        }
096    
097        public Destination getReplyToDestination() {
098            return replyToDestination;
099        }
100    
101        public void setReplyToDestination(Destination replyToDestination) {
102            this.replyToDestination = replyToDestination;
103        }
104    
105        public Session getSession() {
106            return session;
107        }
108    
109        public void setSession(Session session) {
110            this.session = session;
111        }
112    
113    
114        // Implementation methods
115        //-------------------------------------------------------------------------
116        protected void onTextMessage(TextMessage message) throws Exception {
117            StringWriter writer = new StringWriter();
118            soapService.invoke(new StringReader(message.getText()), writer);
119            TextMessage response = session.createTextMessage(writer.toString());
120            Destination destination = findReplyToDestination(message);
121            producer.send(destination, response);
122        }
123    
124        protected Destination findReplyToDestination(TextMessage message) throws JMSException {
125            Destination answer = message.getJMSReplyTo();
126            if (answer == null) {
127                answer = getReplyToDestination();
128                if (answer == null) {
129                    throw new JMSException("No JMSReployTo destination on the message or reployToDestination property available");
130                }
131            }
132            return answer;
133        }
134    
135        protected void onException(Exception reason, Message message) {
136            checkValidDeadLetterQueue(reason.toString(), message);
137            try {
138                Message response = createDuplicateMessage(message);
139                response.setStringProperty("reason", reason.getMessage());
140                StringWriter buffer = new StringWriter();
141                reason.printStackTrace(new PrintWriter(buffer));
142                response.setStringProperty("stackTrace", buffer.toString());
143                producer.send(deadLetterQueue, response);
144            }
145            catch (JMSException e) {
146                log.error("Error sending to deadLetterQueue. Reason: " + reason + ". Exception: " + e + " message: " + message, e);
147            }
148        }
149    
150        protected void sendToDeadLetterQueue(String reason, Message message) {
151            checkValidDeadLetterQueue(reason, message);
152            try {
153                Message response = createDuplicateMessage(message);
154                response.setStringProperty("reason", reason);
155                producer.send(deadLetterQueue, response);
156            }
157            catch (JMSException e) {
158                log.error("Error sending to deadLetterQueue. Reason: " + reason + ". Exception: " + e + " message: " + message, e);
159            }
160        }
161    
162        protected Message createDuplicateMessage(Message message) throws JMSException {
163            return JMSUtils.createDuplicateMessage(session, message);
164        }
165    
166        protected void checkValidDeadLetterQueue(String reason, Message message) {
167            if (deadLetterQueue == null) {
168                log.error("Cannot send message to deadLetterQueue as no destination configured. Reason for failure: " + reason + " message: " + message);
169                throw new RuntimeException("No dead letter queue available");
170            }
171        }
172    }