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.component.jms.requestor;
018    
019    import java.util.concurrent.FutureTask;
020    
021    import javax.jms.JMSException;
022    import javax.jms.Message;
023    
024    import org.apache.camel.component.jms.JmsConfiguration.MessageSentCallback;
025    import org.apache.camel.component.jms.JmsProducer;
026    import org.apache.camel.util.TimeoutMap;
027    import org.apache.camel.util.UuidGenerator;
028    import org.apache.commons.logging.Log;
029    import org.apache.commons.logging.LogFactory;
030    
031    public class DeferredRequestReplyMap  {
032        private static final transient Log LOG = LogFactory.getLog(DeferredRequestReplyMap.class);
033        private Requestor requestor;
034        private JmsProducer producer;
035        private TimeoutMap<String, Object> deferredRequestMap;
036        private TimeoutMap<String, Object> deferredReplyMap;
037    
038        public static class DeferredMessageSentCallback implements MessageSentCallback {
039            private DeferredRequestReplyMap map;
040            private String transitionalID;
041            private Message message;
042            private Object monitor;
043    
044            public DeferredMessageSentCallback(DeferredRequestReplyMap map, UuidGenerator uuidGenerator, Object monitor) {
045                transitionalID = uuidGenerator.generateUuid();
046                this.map = map;
047                this.monitor = monitor;
048            }
049    
050            public DeferredRequestReplyMap getDeferredRequestReplyMap() {
051                return map;
052            }
053    
054            public String getID() {
055                return transitionalID;
056            }
057    
058            public Message getMessage() {
059                return message;
060            }
061            
062            public void sent(Message message) {
063                this.message = message;
064                map.processDeferredReplies(monitor, getID(), message);
065            }
066        }
067    
068        public DeferredRequestReplyMap(Requestor requestor,
069                                       JmsProducer producer,
070                                       TimeoutMap<String, Object> deferredRequestMap,
071                                       TimeoutMap<String, Object> deferredReplyMap) {
072            this.requestor = requestor;
073            this.producer = producer;
074            this.deferredRequestMap = deferredRequestMap;
075            this.deferredReplyMap = deferredReplyMap;
076        }
077    
078        public long getRequestTimeout() {
079            return producer.getRequestTimeout();
080        }
081    
082        public DeferredMessageSentCallback createDeferredMessageSentCallback() {
083            return new DeferredMessageSentCallback(this, getUuidGenerator(), requestor);
084        }
085    
086        public void put(DeferredMessageSentCallback callback, FutureTask futureTask) {
087            deferredRequestMap.put(callback.getID(), futureTask, getRequestTimeout());
088        }
089    
090        public void processDeferredRequests(String correlationID, Message inMessage) {
091            processDeferredRequests(requestor, deferredRequestMap, deferredReplyMap,
092                                    correlationID, requestor.getMaxRequestTimeout(), inMessage);
093        }
094    
095        public static void processDeferredRequests(Object monitor,
096                                                   TimeoutMap<String, Object> requestMap,
097                                                   TimeoutMap<String, Object> replyMap,
098                                                   String correlationID,
099                                                   long timeout,
100                                                   Message inMessage) {
101            synchronized (monitor) {
102                try {
103                    Object handler = requestMap.get(correlationID);
104                    if (handler == null) {
105                        if (requestMap.size() > replyMap.size()) {
106                            replyMap.put(correlationID, inMessage, timeout);
107                        } else {
108                            LOG.warn("Response received for unknown correlationID: " + correlationID + "; response: " + inMessage);
109                        }
110                    }
111                    if (handler != null && handler instanceof ReplyHandler) {
112                        ReplyHandler replyHandler = (ReplyHandler) handler;
113                        boolean complete = replyHandler.handle(inMessage);
114                        if (complete) {
115                            requestMap.remove(correlationID);
116                        }
117                    }
118                } catch (JMSException e) {
119                    throw new FailedToProcessResponse(inMessage, e);
120                }
121            }
122        }
123    
124        public void processDeferredReplies(Object monitor, String transitionalID, Message outMessage) {
125            synchronized (monitor) {
126                try {
127                    Object handler = deferredRequestMap.get(transitionalID);
128                    if (handler == null) {
129                        return;
130                    }
131                    deferredRequestMap.remove(transitionalID);
132                    String correlationID = outMessage.getJMSMessageID();
133                    Object in = deferredReplyMap.get(correlationID);
134    
135                    if (in != null && in instanceof Message) {
136                        Message inMessage = (Message)in;
137                        if (handler instanceof ReplyHandler) {
138                            ReplyHandler replyHandler = (ReplyHandler)handler;
139                            try {
140                                boolean complete = replyHandler.handle(inMessage);
141                                if (complete) {
142                                    deferredReplyMap.remove(correlationID);
143                                }
144                            } catch (JMSException e) {
145                                throw new FailedToProcessResponse(inMessage, e);
146                            }
147                        }
148                    } else {
149                        deferredRequestMap.put(correlationID, handler, getRequestTimeout());
150                    }
151                } catch (JMSException e) {
152                    throw new FailedToProcessResponse(outMessage, e);
153                }
154            }
155        }
156    
157        protected UuidGenerator getUuidGenerator() {
158            return producer.getUuidGenerator();
159        }
160    }