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 */ 022package org.granite.gravity; 023 024import java.io.IOException; 025import java.io.Serializable; 026import java.lang.reflect.Constructor; 027 028import org.granite.context.GraniteContext; 029import org.granite.gravity.selector.GravityMessageSelector; 030import org.granite.gravity.selector.MessageSelector; 031import org.granite.logging.Logger; 032import org.granite.util.TypeUtil; 033 034import flex.messaging.messages.AsyncMessage; 035import flex.messaging.messages.CommandMessage; 036import flex.messaging.messages.Message; 037 038/** 039 * @author William DRAI 040 */ 041public 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}