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    
021    package org.granite.gravity.jetty;
022    
023    import javax.servlet.ServletConfig;
024    
025    import org.granite.gravity.AbstractChannel;
026    import org.granite.gravity.AsyncHttpContext;
027    import org.granite.gravity.GravityConfig;
028    import org.granite.gravity.GravityManager;
029    import org.granite.gravity.MessageReceivingException;
030    import org.granite.logging.Logger;
031    import org.mortbay.util.ajax.Continuation;
032    
033    import flex.messaging.messages.AsyncMessage;
034    
035    /**
036     * @author William DRAI
037     */
038    public class ContinuationChannel extends AbstractChannel {
039    
040        private static final Logger log = Logger.getLogger(ContinuationChannel.class);
041    
042        private Continuation continuation = null;
043    
044        public ContinuationChannel(ServletConfig servletConfig, GravityConfig gravityConfig, String id) {
045            super(servletConfig, gravityConfig, id);
046        }
047    
048        public void setContinuation(Continuation continuation) {
049            log.debug("Setting continuation %s for client: %s", continuation, getId());
050            try {
051                if (this.continuation != null && this.continuation.isPending()) {
052                    log.debug("Resuming previous continuation %s for client: %s", this.continuation, getId());
053                    this.continuation.resume();
054                }
055            }
056            finally {
057                this.continuation = continuation;
058            }
059        }
060        
061        public void reset() {
062            try {
063                if (this.continuation != null)
064                    this.continuation.reset();
065            }
066            finally {
067                this.continuation = null;
068            }
069        }
070        
071    
072        public void resume() {
073            log.debug("Resuming pending continuation %s for client: %s", continuation, getId());
074            try {
075                if (this.continuation != null && this.continuation.isPending())
076                    this.continuation.resume();
077            }
078            finally {
079                this.continuation = null;
080            }
081        }
082        
083        @Override
084            public void receive(AsyncMessage message) throws MessageReceivingException {
085                    if (message == null)
086                            throw new NullPointerException("message cannot be null");
087    
088                    GravityConfig gravityConfig = GravityManager.getGravity(getServletContext()).getGravityConfig();
089                    
090                    receivedQueueLock.lock();
091                    try {
092                            if (receivedQueue.size() + 1 > gravityConfig.getMaxMessagesQueuedPerChannel())
093                                    throw new MessageReceivingException(message, "Could not queue message (channel's queue is full) for channel: " + this);
094                            
095                            receivedQueue.add(message);
096                    }
097                    finally {
098                            receivedQueueLock.unlock();
099                    }
100                    
101                    synchronized (this) {
102                            resume();
103                    }
104            }
105    
106            @Override
107            protected boolean hasAsyncHttpContext() {
108                    return false;
109            }
110    
111            @Override
112            protected void releaseAsyncHttpContext(AsyncHttpContext context) {
113            }
114    
115            @Override
116            protected AsyncHttpContext acquireAsyncHttpContext() {
117            return null;
118        }
119    
120        public boolean isLocal() {
121            return true;
122        }
123    
124            @Override
125            public void destroy() {
126                    try {
127                            super.destroy();
128                    }
129                    finally {
130                            synchronized (this) {
131                                    reset();
132                            }
133                    }
134            }
135    }