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  
19  import org.mortbay.cometd.ClientImpl;
20  import org.mortbay.thread.Timeout;
21  
22  /* ------------------------------------------------------------ */
23  /**
24   * Extension of {@link ClientImpl} that uses {@link Continuation}s to
25   * resume clients waiting for messages. Continuation clients are used for
26   * remote clients and have removed if they are not accessed within
27   * an idle timeout (@link {@link SuspendingBayeux#_clientTimer}).
28   * 
29   * @author gregw
30   *
31   */
32  public class SuspendingClient extends ClientImpl
33  {
34      private long _accessed;
35      public transient Timeout.Task _timeout; 
36      private SuspendingBayeux _bayeux;
37      private transient ServletRequest _pollRequest;
38  
39      /* ------------------------------------------------------------ */
40      protected SuspendingClient(SuspendingBayeux bayeux)
41      {
42          super(bayeux);
43          _bayeux=bayeux;
44  
45          if (!isLocal())
46          {
47              _timeout=new Timeout.Task()
48              {
49                  public void expired()
50                  {
51                      remove(true);
52                  }
53                  public String toString()
54                  {
55                      return "T-"+SuspendingClient.this.toString();
56                  }
57              };
58              _bayeux.startTimeout(_timeout,getTimeout());
59          }
60      }
61  
62  
63      /* ------------------------------------------------------------ */
64      public void setPollRequest(ServletRequest request)
65      {
66          Timeout.Task task=null;
67          
68          if (request==null)
69          {
70              synchronized (this)
71              {
72                  if (_pollRequest!=null)
73                  {
74                      if(_pollRequest.isSuspended())
75                          _pollRequest.resume(); 
76                  }
77                  _pollRequest=null;
78                  task=_timeout;
79              }
80  
81              if (task!=null)
82                  _bayeux.startTimeout(task,getTimeout());
83          }
84          else
85          {
86              synchronized (this)
87              {
88                  if (_pollRequest!=null)
89                  {
90                      if(_pollRequest.isSuspended())
91                          _pollRequest.resume(); 
92                  }
93                  _pollRequest=request;
94                  task=_timeout;
95              }
96  
97              if (task!=null)
98                  _bayeux.cancelTimeout(task);
99          }
100     }
101     
102     /* ------------------------------------------------------------ */
103     public ServletRequest getPollRequest()
104     {
105         return _pollRequest;
106     }
107 
108     /* ------------------------------------------------------------ */
109     public void resume()
110     {
111         Timeout.Task task=null;
112         synchronized (this)
113         {
114             if (_pollRequest!=null)
115             {
116                 _pollRequest.getServletResponse().disable();
117                 _pollRequest.resume();
118                 task=_timeout;
119             }
120             _pollRequest=null;
121         }
122         
123         if (task!=null)
124             _bayeux.startTimeout(task,getTimeout());
125     }
126 
127     /* ------------------------------------------------------------ */
128     public boolean isLocal()
129     {
130         return false;
131     }
132 
133     /* ------------------------------------------------------------ */
134     public void access()
135     {
136         Timeout.Task task=null;
137         synchronized(this)
138         {
139             // distribute access time in cluster
140             _accessed=_bayeux.getNow();
141             if (_timeout!=null && _timeout.isScheduled())
142                 task=_timeout;
143         }
144         
145         if (task!=null)
146             _bayeux.startTimeout(task,getTimeout());
147     }
148 
149 
150     /* ------------------------------------------------------------ */
151     public synchronized long lastAccessed()
152     {
153         return _accessed;
154     }
155     
156     /* ------------------------------------------------------------ */
157     /* (non-Javadoc)
158      * @see org.mortbay.cometd.ClientImpl#remove(boolean)
159      */
160     public void remove(boolean wasTimeout) 
161     {
162         Timeout.Task task=null;
163         synchronized(this)
164         {
165             if (!wasTimeout)
166                 task=_timeout;
167             _timeout=null;
168             super.remove(wasTimeout);
169         }
170         
171         if (task!=null)
172             _bayeux.cancelTimeout(task);
173         
174     }
175 
176 }