1   // ========================================================================
2   // Copyright 2006 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // Licensed under the Apache License, Version 2.0 (the "License");
5   // you may not use this file except in compliance with the License.
6   // You may obtain a copy of the License at 
7   // http://www.apache.org/licenses/LICENSE-2.0
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
13  // ========================================================================
14  
15  package org.mortbay.cometd;
16  
17  import javax.servlet.ServletRequest;
18  import javax.servlet.http.HttpServletRequest;
19  import javax.servlet.http.HttpServletResponse;
20  
21  import org.mortbay.cometd.ClientImpl;
22  import org.mortbay.thread.Timeout;
23  
24  /* ------------------------------------------------------------ */
25  /**
26   * Extension of {@link ClientImpl} that uses {@link Continuation}s to
27   * resume clients waiting for messages. Continuation clients are used for
28   * remote clients and have removed if they are not accessed within
29   * an idle timeout (@link {@link SuspendingBayeux#_clientTimer}).
30   * 
31   * @author gregw
32   *
33   */
34  public class SuspendingClient extends ClientImpl
35  {
36      private long _accessed;
37      public transient Timeout.Task _timeout; 
38      private SuspendingBayeux _bayeux;
39      private transient ServletRequest _pollRequest;
40  
41      /* ------------------------------------------------------------ */
42      protected SuspendingClient(SuspendingBayeux bayeux)
43      {
44          super(bayeux);
45          _bayeux=bayeux;
46  
47          if (!isLocal())
48          {
49              _timeout=new Timeout.Task()
50              {
51                  public void expired()
52                  {
53                      remove(true);
54                  }
55                  public String toString()
56                  {
57                      return "T-"+SuspendingClient.this.toString();
58                  }
59              };
60              _bayeux.startTimeout(_timeout,getTimeout());
61          }
62      }
63  
64  
65      /* ------------------------------------------------------------ */
66      public void setPollRequest(ServletRequest request)
67      {
68          
69          if (request==null)
70          {
71              synchronized (this)
72              {
73                  if (_pollRequest!=null)
74                  {
75                      if(_pollRequest.isSuspended())
76                          _pollRequest.resume(); 
77                  }
78                  _pollRequest=null;
79                  if (_timeout!=null)
80                      _bayeux.startTimeout(_timeout,getTimeout());
81              }
82          }
83          else
84          {
85              synchronized (this)
86              {
87                  if (_pollRequest!=null)
88                  {
89                      if(_pollRequest.isSuspended())
90                          _pollRequest.resume(); 
91                  }
92                  _pollRequest=request;
93                  if (_timeout!=null)
94                      _bayeux.cancelTimeout(_timeout);
95              }
96          }
97      }
98      
99      /* ------------------------------------------------------------ */
100     public ServletRequest getPollRequest()
101     {
102         return _pollRequest;
103     }
104 
105     /* ------------------------------------------------------------ */
106     public void resume()
107     {
108         synchronized (this)
109         {
110             if (_pollRequest!=null)
111             {
112                 ((HttpServletResponse)((HttpServletRequest)_pollRequest).getServletResponse()).addHeader("Debug","Resume");
113                 _pollRequest.resume();
114             }
115             _pollRequest=null;
116         }
117     }
118 
119     /* ------------------------------------------------------------ */
120     public boolean isLocal()
121     {
122         return false;
123     }
124 
125     /* ------------------------------------------------------------ */
126     public void access()
127     {
128         synchronized(this)
129         {
130             // distribute access time in cluster
131             _accessed=_bayeux.getNow();
132             if (_timeout!=null && _timeout.isScheduled())
133             {
134                 _timeout.reschedule();
135             }
136         }
137     }
138 
139 
140     /* ------------------------------------------------------------ */
141     public synchronized long lastAccessed()
142     {
143         return _accessed;
144     }
145     
146     /* ------------------------------------------------------------ */
147     /* (non-Javadoc)
148      * @see org.mortbay.cometd.ClientImpl#remove(boolean)
149      */
150     public void remove(boolean wasTimeout) 
151     {
152         synchronized(this)
153         {
154             if (!wasTimeout && _timeout!=null)
155                 _bayeux.cancelTimeout(_timeout);
156             _timeout=null;
157             super.remove(wasTimeout);
158         }   
159     }
160 
161 }