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