001 /**
002 * GRANITE DATA SERVICES
003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 * This file is part of Granite Data Services.
006 *
007 * Granite Data Services is free software; you can redistribute it and/or modify
008 * it under the terms of the GNU Library General Public License as published by
009 * the Free Software Foundation; either version 2 of the License, or (at your
010 * option) any later version.
011 *
012 * Granite Data Services is distributed in the hope that it will be useful, but
013 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015 * for more details.
016 *
017 * You should have received a copy of the GNU Library General Public License
018 * along with this library; if not, see <http://www.gnu.org/licenses/>.
019 */
020 package org.granite.client.messaging;
021
022 import java.util.concurrent.ConcurrentHashMap;
023
024 import org.granite.client.messaging.channel.MessagingChannel;
025 import org.granite.client.messaging.channel.ResponseMessageFuture;
026 import org.granite.client.messaging.events.IssueEvent;
027 import org.granite.client.messaging.events.ResultEvent;
028 import org.granite.client.messaging.events.TopicMessageEvent;
029 import org.granite.client.messaging.messages.push.TopicMessage;
030 import org.granite.client.messaging.messages.requests.SubscribeMessage;
031 import org.granite.client.messaging.messages.requests.UnsubscribeMessage;
032 import org.granite.logging.Logger;
033
034 /**
035 * @author Franck WOLFF
036 */
037 public class Consumer extends AbstractTopicAgent {
038
039 private static final Logger log = Logger.getLogger(Consumer.class);
040
041 private final ConcurrentHashMap<TopicMessageListener, Boolean> listeners = new ConcurrentHashMap<TopicMessageListener, Boolean>();
042
043 private String subscriptionId = null;
044 private String selector = null;
045
046 public Consumer(MessagingChannel channel, String destination, String topic) {
047 super(channel, destination, topic);
048 }
049
050 public String getSelector() {
051 return selector;
052 }
053
054 public void setSelector(String selector) {
055 this.selector = selector;
056 }
057
058 public boolean isSubscribed() {
059 return subscriptionId != null;
060 }
061
062 public String getSubscriptionId() {
063 return subscriptionId;
064 }
065
066 public ResponseMessageFuture subscribe(ResponseListener...listeners) {
067 SubscribeMessage subscribeMessage = new SubscribeMessage(destination, topic, selector);
068 subscribeMessage.getHeaders().putAll(defaultHeaders);
069
070 final Consumer consumer = this;
071 ResponseListener listener = new ResultIssuesResponseListener() {
072
073 @Override
074 public void onResult(ResultEvent event) {
075 subscriptionId = (String)event.getResult();
076 channel.addConsumer(consumer);
077 }
078
079 @Override
080 public void onIssue(IssueEvent event) {
081 log.error("Subscription failed %s: %s", consumer, event);
082 }
083 };
084
085 if (listeners == null || listeners.length == 0)
086 listeners = new ResponseListener[]{listener};
087 else {
088 ResponseListener[] tmp = new ResponseListener[listeners.length + 1];
089 System.arraycopy(listeners, 0, tmp, 0, listeners.length);
090 tmp[listeners.length] = listener;
091 listeners = tmp;
092 }
093
094 return channel.send(subscribeMessage, listeners);
095 }
096
097 public ResponseMessageFuture unsubscribe(ResponseListener...listeners) {
098 UnsubscribeMessage unsubscribeMessage = new UnsubscribeMessage(destination, topic, subscriptionId);
099 unsubscribeMessage.getHeaders().putAll(defaultHeaders);
100
101 final Consumer consumer = this;
102 ResponseListener listener = new ResultIssuesResponseListener() {
103
104 @Override
105 public void onResult(ResultEvent event) {
106 channel.removeConsumer(consumer);
107 subscriptionId = null;
108 }
109
110 @Override
111 public void onIssue(IssueEvent event) {
112 log.error("Unsubscription failed %s: %s", consumer, event);
113 }
114 };
115
116 if (listeners == null || listeners.length == 0)
117 listeners = new ResponseListener[]{listener};
118 else {
119 ResponseListener[] tmp = new ResponseListener[listeners.length + 1];
120 System.arraycopy(listeners, 0, tmp, 0, listeners.length);
121 tmp[listeners.length] = listener;
122 listeners = tmp;
123 }
124
125 return channel.send(unsubscribeMessage, listeners);
126 }
127
128 public void addMessageListener(TopicMessageListener listener) {
129 listeners.putIfAbsent(listener, Boolean.TRUE);
130 }
131
132 public boolean removeMessageListener(TopicMessageListener listener) {
133 return listeners.remove(listener) != null;
134 }
135
136 public void onDisconnect() {
137 subscriptionId = null;
138 }
139
140 public void onMessage(TopicMessage message) {
141 for (TopicMessageListener listener : listeners.keySet()) {
142 try {
143 listener.onMessage(new TopicMessageEvent(this, message));
144 }
145 catch (Exception e) {
146 log.error(e, "Consumer listener threw an exception: ", listener);
147 }
148 }
149 }
150
151 @Override
152 public String toString() {
153 return getClass().getName() + " {subscriptionId=" + subscriptionId +
154 ", destination=" + destination +
155 ", topic=" + topic +
156 ", selector=" + selector +
157 "}";
158 }
159 }