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 }