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.gae;
023
024 import org.granite.config.GraniteConfig;
025 import org.granite.config.flex.ServicesConfig;
026 import org.granite.gravity.Channel;
027 import org.granite.gravity.ChannelFactory;
028 import org.granite.gravity.DefaultGravity;
029 import org.granite.gravity.GravityConfig;
030 import org.granite.gravity.Subscription;
031 import org.granite.messaging.jmf.SharedContext;
032 import org.granite.util.UUIDUtil;
033
034 import com.google.appengine.api.memcache.Expiration;
035 import com.google.appengine.api.memcache.MemcacheService;
036 import com.google.appengine.api.memcache.MemcacheServiceFactory;
037
038 import flex.messaging.messages.Message;
039
040 /**
041 * @author William DRAI
042 * @author Franck WOLFF
043 */
044 public class GAEGravity extends DefaultGravity {
045
046 ///////////////////////////////////////////////////////////////////////////
047 // Fields.
048
049 static final String CHANNEL_PREFIX = "org.granite.gravity.gae.channel.";
050
051 private static MemcacheService gaeCache = MemcacheServiceFactory.getMemcacheService();
052
053 ///////////////////////////////////////////////////////////////////////////
054 // Constructor.
055
056 public GAEGravity(GravityConfig gravityConfig, ServicesConfig servicesConfig, GraniteConfig graniteConfig, SharedContext sharedContext) {
057 super(gravityConfig, servicesConfig, graniteConfig, sharedContext);
058 }
059
060
061 ///////////////////////////////////////////////////////////////////////////
062 // Channel's operations.
063
064 @Override
065 protected <C extends Channel> C createChannel(ChannelFactory<C> channelFactory, String channelId) {
066 C channel = null;
067 if (channelId != null) {
068 channel = getChannel(channelFactory, channelId);
069 if (channel != null)
070 return channel;
071 }
072
073 channel = channelFactory.newChannel(UUIDUtil.randomUUID(), null);
074 Expiration expiration = Expiration.byDeltaMillis((int)getGravityConfig().getChannelIdleTimeoutMillis());
075 gaeCache.put(CHANNEL_PREFIX + channel.getId(), channel, expiration);
076 gaeCache.put(GAEChannel.MSG_COUNT_PREFIX + channel.getId(), 0L, expiration);
077 return channel;
078 }
079
080 @SuppressWarnings("unchecked")
081 @Override
082 public <C extends Channel> C getChannel(ChannelFactory<C> channelFactory, String channelId) {
083 if (channelId == null)
084 return null;
085
086 return (C)gaeCache.get(CHANNEL_PREFIX + channelId);
087 }
088
089
090 @Override
091 public Channel removeChannel(String channelId, boolean timeout) {
092 if (channelId == null)
093 return null;
094
095 Channel channel = (Channel)gaeCache.get(CHANNEL_PREFIX + channelId);
096 if (channel != null) {
097 for (Subscription subscription : channel.getSubscriptions()) {
098 Message message = subscription.getUnsubscribeMessage();
099 handleMessage(channel.getFactory(), message, true);
100 }
101
102 channel.destroy(timeout);
103 gaeCache.delete(CHANNEL_PREFIX + channelId);
104 gaeCache.delete(GAEChannel.MSG_COUNT_PREFIX + channelId);
105 }
106
107 return channel;
108 }
109
110 @Override
111 public boolean access(String channelId) {
112 return true;
113 }
114
115
116 @Override
117 public void internalStart() {
118 // Avoid starting thread pool
119 }
120
121
122 @Override
123 protected void postManage(Channel channel) {
124 Expiration expiration = Expiration.byDeltaMillis((int)getGravityConfig().getChannelIdleTimeoutMillis());
125 gaeCache.put(CHANNEL_PREFIX + channel.getId(), channel, expiration);
126 }
127 }