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    }