001/* 002 GRANITE DATA SERVICES 003 Copyright (C) 2011 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 021package org.granite.gravity; 022 023import java.io.IOException; 024import java.io.Serializable; 025import java.lang.reflect.Constructor; 026 027import org.granite.context.GraniteContext; 028import org.granite.gravity.selector.GravityMessageSelector; 029import org.granite.gravity.selector.MessageSelector; 030import org.granite.logging.Logger; 031import org.granite.util.TypeUtil; 032 033import flex.messaging.messages.AsyncMessage; 034import flex.messaging.messages.CommandMessage; 035import flex.messaging.messages.Message; 036 037/** 038 * @author William DRAI 039 */ 040public class Subscription implements Serializable { 041 042 private static final long serialVersionUID = -8527072003319223252L; 043 044 private static final Logger log = Logger.getLogger(Subscription.class); 045 046 private final Channel channel; 047 private final String destination; 048 private final String subTopicId; 049 private final String subscriptionId; 050 private String selectorText; 051 private String selectorClassName; 052 private transient Constructor<?> messageSelectorConstructor; 053 private transient MessageSelector selector; 054 private final boolean noLocal; 055 056 057 public Subscription(Channel channel, String destination, String subTopicId, String subscriptionId, boolean noLocal) { 058 super(); 059 this.channel = channel; 060 this.destination = destination; 061 this.subTopicId = subTopicId; 062 this.subscriptionId = subscriptionId; 063 this.noLocal = noLocal; 064 } 065 066 private void readObject(java.io.ObjectInputStream in) throws ClassNotFoundException, IOException { 067 in.defaultReadObject(); 068 if (selectorClassName != null) { 069 try { 070 messageSelectorConstructor = TypeUtil.getConstructor(selectorClassName, new Class<?>[] { String.class }); 071 } 072 catch (NoSuchMethodException e) { 073 throw new IOException("Could not get message selector: " + selectorClassName); 074 } 075 } 076 parseSelector(); 077 } 078 079 public Channel getChannel() { 080 return channel; 081 } 082 083 public String getSubTopicId() { 084 return subTopicId; 085 } 086 087 public String getSubscriptionId() { 088 return subscriptionId; 089 } 090 091 092 public void setSelector(String selector) { 093 this.selectorText = selector; 094 parseSelector(); 095 } 096 097 private void parseSelector() { 098 if (selectorText != null) { 099 try { 100 Constructor<?> messageSelectorConstructor = this.messageSelectorConstructor; 101 if (messageSelectorConstructor == null) { 102 GraniteContext context = GraniteContext.getCurrentInstance(); 103 if (context == null) 104 throw new IllegalStateException("Cannot parse selector outside of GDS context"); 105 messageSelectorConstructor = context.getGraniteConfig().getMessageSelectorConstructor(); 106 } 107 if (messageSelectorConstructor == null) 108 this.selector = new GravityMessageSelector(selectorText); 109 else 110 this.selector = (MessageSelector)messageSelectorConstructor.newInstance(selectorText); 111 } 112 catch (Exception e) { 113 throw new RuntimeException("Could not create message selector", e); 114 } 115 } 116 } 117 118 119 public boolean deliver(Channel fromClient, AsyncMessage message) { 120 if (noLocal && fromClient.getId().equals(channel.getId())) 121 return false; 122 123 if (selector == null || selector.accept(message)) { 124 try { 125 message.setHeader(AsyncMessage.DESTINATION_CLIENT_ID_HEADER, subscriptionId); 126 getChannel().receive(message); 127 return true; 128 } catch (MessageReceivingException e) { 129 log.error(e, "Could not deliver message"); 130 } 131 } 132 133 return false; 134 } 135 136 public Message getUnsubscribeMessage() { 137 CommandMessage unsubscribeMessage = new CommandMessage(); 138 unsubscribeMessage.setOperation(CommandMessage.UNSUBSCRIBE_OPERATION); 139 unsubscribeMessage.setClientId(getChannel().getId()); 140 unsubscribeMessage.setDestination(destination); 141 unsubscribeMessage.setHeader(AsyncMessage.SUBTOPIC_HEADER, getSubTopicId()); 142 unsubscribeMessage.setHeader(AsyncMessage.DESTINATION_CLIENT_ID_HEADER, getSubscriptionId()); 143 return unsubscribeMessage; 144 } 145 146 147 @Override 148 public boolean equals(Object o) { 149 if (!o.getClass().equals(Subscription.class)) 150 return false; 151 152 Subscription s = (Subscription)o; 153 return getChannel().equals(s.getChannel()) && getSubscriptionId().equals(s.getSubscriptionId()); 154 } 155 156 @Override 157 public String toString() { 158 return subscriptionId + ":" + subTopicId; 159 } 160}