001 /**
002 * GRANITE DATA SERVICES
003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 * This file is part of the Granite Data Services Platform.
006 *
007 * Granite Data Services is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * Granite Data Services is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 * General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 * USA, or see <http://www.gnu.org/licenses/>.
021 */
022 package org.granite.gravity;
023
024 import java.io.IOException;
025 import java.io.Serializable;
026 import java.lang.reflect.Constructor;
027
028 import org.granite.context.GraniteContext;
029 import org.granite.gravity.selector.GravityMessageSelector;
030 import org.granite.gravity.selector.MessageSelector;
031 import org.granite.logging.Logger;
032 import org.granite.util.TypeUtil;
033
034 import flex.messaging.messages.AsyncMessage;
035 import flex.messaging.messages.CommandMessage;
036 import flex.messaging.messages.Message;
037
038 /**
039 * @author William DRAI
040 */
041 public class Subscription implements Serializable {
042
043 private static final long serialVersionUID = -8527072003319223252L;
044
045 private static final Logger log = Logger.getLogger(Subscription.class);
046
047 private final Channel channel;
048 private final String destination;
049 private final String subTopicId;
050 private final String subscriptionId;
051 private String selectorText;
052 private String selectorClassName;
053 private transient Constructor<?> messageSelectorConstructor;
054 private transient MessageSelector selector;
055 private final boolean noLocal;
056
057
058 public Subscription(Channel channel, String destination, String subTopicId, String subscriptionId, boolean noLocal) {
059 super();
060 this.channel = channel;
061 this.destination = destination;
062 this.subTopicId = subTopicId;
063 this.subscriptionId = subscriptionId;
064 this.noLocal = noLocal;
065 }
066
067 private void readObject(java.io.ObjectInputStream in) throws ClassNotFoundException, IOException {
068 in.defaultReadObject();
069 if (selectorClassName != null) {
070 try {
071 messageSelectorConstructor = TypeUtil.getConstructor(selectorClassName, new Class<?>[] { String.class });
072 }
073 catch (NoSuchMethodException e) {
074 throw new IOException("Could not get message selector: " + selectorClassName);
075 }
076 }
077 parseSelector();
078 }
079
080 public Channel getChannel() {
081 return channel;
082 }
083
084 public String getSubTopicId() {
085 return subTopicId;
086 }
087
088 public String getSubscriptionId() {
089 return subscriptionId;
090 }
091
092
093 public void setSelector(String selector) {
094 this.selectorText = selector;
095 parseSelector();
096 }
097
098 private void parseSelector() {
099 if (selectorText != null) {
100 try {
101 Constructor<?> messageSelectorConstructor = this.messageSelectorConstructor;
102 if (messageSelectorConstructor == null) {
103 GraniteContext context = GraniteContext.getCurrentInstance();
104 if (context == null)
105 throw new IllegalStateException("Cannot parse selector outside of GDS context");
106 messageSelectorConstructor = context.getGraniteConfig().getMessageSelectorConstructor();
107 }
108 if (messageSelectorConstructor == null)
109 this.selector = new GravityMessageSelector(selectorText);
110 else
111 this.selector = (MessageSelector)messageSelectorConstructor.newInstance(selectorText);
112 }
113 catch (Exception e) {
114 throw new RuntimeException("Could not create message selector", e);
115 }
116 }
117 }
118
119
120 public boolean deliver(Channel fromClient, AsyncMessage message) {
121 if (noLocal && fromClient.getId().equals(channel.getId()))
122 return false;
123
124 if (selector == null || selector.accept(message)) {
125 try {
126 message.setHeader(AsyncMessage.DESTINATION_CLIENT_ID_HEADER, subscriptionId);
127 getChannel().receive(message);
128 return true;
129 } catch (MessageReceivingException e) {
130 log.error(e, "Could not deliver message");
131 }
132 }
133
134 return false;
135 }
136
137 public Message getUnsubscribeMessage() {
138 CommandMessage unsubscribeMessage = new CommandMessage();
139 unsubscribeMessage.setOperation(CommandMessage.UNSUBSCRIBE_OPERATION);
140 unsubscribeMessage.setClientId(getChannel().getId());
141 unsubscribeMessage.setDestination(destination);
142 unsubscribeMessage.setHeader(AsyncMessage.SUBTOPIC_HEADER, getSubTopicId());
143 unsubscribeMessage.setHeader(AsyncMessage.DESTINATION_CLIENT_ID_HEADER, getSubscriptionId());
144 return unsubscribeMessage;
145 }
146
147
148 @Override
149 public boolean equals(Object o) {
150 if (!o.getClass().equals(Subscription.class))
151 return false;
152
153 Subscription s = (Subscription)o;
154 return getChannel().equals(s.getChannel()) && getSubscriptionId().equals(s.getSubscriptionId());
155 }
156
157 @Override
158 public String toString() {
159 return subscriptionId + ":" + subTopicId;
160 }
161 }