View Javadoc

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.continuation;
16  
17  import org.mortbay.cometd.ClientImpl;
18  import org.mortbay.thread.Timeout;
19  import org.mortbay.util.ajax.Continuation;
20  
21  /* ------------------------------------------------------------ */
22  /**
23   * Extension of {@link ClientImpl} that uses {@link Continuation}s to resume
24   * clients waiting for messages. Continuation clients are used for remote
25   * clients and have removed if they are not accessed within an idle timeout (@link
26   * {@link ContinuationBayeux#_clientTimer}).
27   * 
28   * @author gregw
29   * 
30   */
31  public class ContinuationClient extends ClientImpl
32  {
33      private long _accessed;
34      public final Timeout.Task _intervalTimeoutTask;
35      public final Timeout.Task _lazyTimeoutTask;
36      private ContinuationBayeux _bayeux;
37      private volatile Continuation _continuation;
38      private volatile boolean _lazyResuming;
39  
40      /* ------------------------------------------------------------ */
41      protected ContinuationClient(ContinuationBayeux bayeux)
42      {
43          super(bayeux);
44          _bayeux=bayeux;
45  
46          if (isLocal())
47          {
48              _intervalTimeoutTask=null;
49              _lazyTimeoutTask=null;
50          }
51          else
52          {
53              _intervalTimeoutTask=new Timeout.Task()
54              {
55                  @Override
56                  public void expired()
57                  {
58                      remove(true);
59                  }
60  
61                  @Override
62                  public String toString()
63                  {
64                      return "T-" + ContinuationClient.this.toString();
65                  }
66              };
67  
68              _lazyTimeoutTask=new Timeout.Task()
69              {
70                  @Override
71                  public void expired()
72                  {
73                      _lazyResuming=false;
74                      if (hasMessages())
75                          resume();
76                  }
77  
78                  @Override
79                  public String toString()
80                  {
81                      return "L-" + ContinuationClient.this.toString();
82                  }
83              };
84              
85              _bayeux.startIntervalTimeout(_intervalTimeoutTask,getInterval());
86          }
87      }
88  
89      /* ------------------------------------------------------------ */
90      public void setContinuation(Continuation continuation)
91      {
92          if (continuation == null)
93          {
94              synchronized(this)
95              {
96                  if (_continuation != null)
97                  {
98                      if (_continuation.isPending())
99                          _continuation.resume();
100                 }
101                 _continuation=null;
102                 if (_intervalTimeoutTask != null)
103                     _bayeux.startIntervalTimeout(_intervalTimeoutTask,getInterval());
104             }
105         }
106         else
107         {
108             synchronized(this)
109             {
110                 if (_continuation != null)
111                 {
112                     if (_continuation.isPending())
113                         _continuation.resume();
114                 }
115                 _continuation=continuation;
116                 _bayeux.cancelIntervalTimeout(_intervalTimeoutTask);
117                 _accessed=_bayeux.getNow();
118             }
119         }
120     }
121 
122     /* ------------------------------------------------------------ */
123     public Continuation getContinuation()
124     {
125         return _continuation;
126     }
127 
128     /* ------------------------------------------------------------ */
129     @Override
130     public void lazyResume()
131     {
132         int max=_bayeux.getMaxLazyLatency();
133         if (max>0 && _lazyTimeoutTask!=null && !_lazyResuming)
134         {
135             _lazyResuming=true;
136             // use modulo so all lazy clients do not wakeup at once
137             _bayeux.startIntervalTimeout(_lazyTimeoutTask,_accessed%max); 
138         }
139     }
140     
141     /* ------------------------------------------------------------ */
142     @Override
143     public void resume()
144     {
145         synchronized(this)
146         {
147             if (_continuation != null)
148             {
149                 _continuation.resume();
150             }
151             _continuation=null;
152         }
153     }
154 
155     /* ------------------------------------------------------------ */
156     @Override
157     public boolean isLocal()
158     {
159         return false;
160     }
161 
162     /* ------------------------------------------------------------ */
163     public void access()
164     {
165         synchronized(this)
166         {
167             _accessed=_bayeux.getNow();
168             if (_intervalTimeoutTask != null && _intervalTimeoutTask.isScheduled())
169             {
170                 // reschedule the timer even though it may be cancelled next...
171                 // it might not be.
172                 _intervalTimeoutTask.reschedule();
173             }
174         }
175     }
176 
177     /* ------------------------------------------------------------ */
178     public synchronized long lastAccessed()
179     {
180         return _accessed;
181     }
182 
183     /* ------------------------------------------------------------ */
184     /*
185      * (non-Javadoc)
186      * 
187      * @see org.mortbay.cometd.ClientImpl#remove(boolean)
188      */
189     @Override
190     public void remove(boolean wasTimeout)
191     {
192         synchronized(this)
193         {
194             if (!wasTimeout && _intervalTimeoutTask!=null)
195                 _bayeux.cancelIntervalTimeout(_intervalTimeoutTask);
196         }
197         super.remove(wasTimeout);
198     }
199 }